diff --git a/js/resistance-in-a-wire/ResistanceInAWireA11yStrings.js b/js/resistance-in-a-wire/ResistanceInAWireA11yStrings.js
index 603bf8a..891185d 100644
--- a/js/resistance-in-a-wire/ResistanceInAWireA11yStrings.js
+++ b/js/resistance-in-a-wire/ResistanceInAWireA11yStrings.js
@@ -27,13 +27,13 @@ define( function( require ) {
value: 'resistance, R, is {{value}} ohms',
},
summaryResistivityPatternString: {
- value: 'resistivity, rho is {{value}} ohm centimeters',
+ value: 'resistivity, rho, is {{value}} ohm centimeters',
},
summaryLengthPatternString: {
- value: 'length, L is {{value}} centimeters',
+ value: 'length, L, is {{value}} centimeters',
},
summaryAreaPatternString: {
- value: 'area, A is {{value}} centimeters squared',
+ value: 'area, A, is {{value}} centimeters squared',
},
resistanceEquationString: {
value: 'Resistance Equation'
@@ -163,6 +163,30 @@ define( function( require ) {
},
slidersDescriptionString: {
value: 'Resistivity, Length, and Area sliders allow changes to equation and wire.'
+ },
+ sizeChangeAlertPatternString: {
+ value: 'As letter {{letter}} {{letterChange}}, letter R {{rChange}}. Resistance now {{resistance}} ohms.'
+ },
+ letterRhoString: {
+ value: 'rho'
+ },
+ letterLString: {
+ value: 'L'
+ },
+ letterAString: {
+ value: 'A'
+ },
+ growsString: {
+ value: 'grows'
+ },
+ shrinksString: {
+ value: 'shrinks'
+ },
+ growsALotString: {
+ value: 'grows a lot'
+ },
+ shrinksALotString: {
+ value: 'shrinks a lot'
}
};
diff --git a/js/resistance-in-a-wire/ResistanceInAWireConstants.js b/js/resistance-in-a-wire/ResistanceInAWireConstants.js
index b0b73cb..2960ba1 100644
--- a/js/resistance-in-a-wire/ResistanceInAWireConstants.js
+++ b/js/resistance-in-a-wire/ResistanceInAWireConstants.js
@@ -14,6 +14,7 @@ define( function( require ) {
var Range = require( 'DOT/Range' );
var ResistanceInAWireA11yStrings = require( 'RESISTANCE_IN_A_WIRE/resistance-in-a-wire/ResistanceInAWireA11yStrings' );
var resistanceInAWire = require( 'RESISTANCE_IN_A_WIRE/resistanceInAWire' );
+ var Util = require( 'DOT/Util' );
// a11y strings
var muchMuchSmallerThanString = ResistanceInAWireA11yStrings.muchMuchSmallerThanString.value;
@@ -45,6 +46,7 @@ define( function( require ) {
var aVeryLargeAmountOfImpuritiesString = ResistanceInAWireA11yStrings.aVeryLargeAmountOfImpuritiesString.value;
var aHugeAmountOfImpuritiesString = ResistanceInAWireA11yStrings.aHugeAmountOfImpuritiesString.value;
+
// constants
var RESISTIVITY_RANGE = new RangeWithValue( 0.01, 1.00, 0.5 ); // in Ohm * cm
var LENGTH_RANGE = new RangeWithValue( 0.1, 20, 10 ); // in cm
@@ -54,6 +56,8 @@ define( function( require ) {
var AREA_DESCRIPTIONS = [ extremelyThinString, veryThinString, thinString, ofMediumThicknessString, thickString, veryThickString, extremelyThickString ];
var RESISTIVITY_DESCRIPTIONS = [ aTinyAmountOfImpuritiesString, aVerySmallAmountOfImpuritiesString, aSmallAmountOfImpuritiesString, aMediumAmountOfImpuritiesString, aLargeAmountOfImpuritiesString, aVeryLargeAmountOfImpuritiesString, aHugeAmountOfImpuritiesString ];
+ var RELATIVE_SIZE_STRINGS = [ muchMuchSmallerThanString, muchSmallerThanString, slightlySmallerThanString, comparableToString, slightlyLargerThanString, muchLargerThanString, muchMuchLargerThanString ];
+
/**
* Generate a map from physical value to accessible descripton. Each described range has a length of
* valueRange / descriptionArray.length
@@ -138,6 +142,8 @@ define( function( require ) {
AREA_TO_DESCRIPTION_MAP: AREA_TO_DESCRIPTION_MAP,
RESISTIVITY_TO_DESCRIPTION_MAP: RESISTIVITY_TO_DESCRIPTION_MAP,
+ RELATIVE_SIZE_STRINGS: RELATIVE_SIZE_STRINGS,
+
// a11y - used to map relative scale magnitudes of the letters to relative size description
RELATIVE_SIZE_MAP: {
@@ -197,8 +203,18 @@ define( function( require ) {
return entry.description;
}
}
- }
+ },
+ /**
+ * Get a formatted value for resistance - depending on size of resistance, number of decimals will change. Used
+ * for visual readout as well as for readable values in a11y.
+ *
+ * @param {number} value
+ * @return {string}
+ */
+ getFormattedResistanceValue: function( value ) {
+ return Util.toFixed( value, this.getResistanceDecimals( value ) );
+ }
};
resistanceInAWire.register( 'ResistanceInAWireConstants', ResistanceInAWireConstants );
diff --git a/js/resistance-in-a-wire/model/ResistanceInAWireModel.js b/js/resistance-in-a-wire/model/ResistanceInAWireModel.js
index 814d4fc..5879bb6 100644
--- a/js/resistance-in-a-wire/model/ResistanceInAWireModel.js
+++ b/js/resistance-in-a-wire/model/ResistanceInAWireModel.js
@@ -14,6 +14,7 @@ define( function( require ) {
var DerivedPropertyIO = require( 'AXON/DerivedPropertyIO' );
var inherit = require( 'PHET_CORE/inherit' );
var NumberProperty = require( 'AXON/NumberProperty' );
+ var Range = require( 'DOT/Range' );
var resistanceInAWire = require( 'RESISTANCE_IN_A_WIRE/resistanceInAWire' );
var ResistanceInAWireConstants = require( 'RESISTANCE_IN_A_WIRE/resistance-in-a-wire/ResistanceInAWireConstants' );
@@ -73,5 +74,17 @@ define( function( require ) {
this.lengthProperty.reset();
this.areaProperty.reset();
}
+ }, {
+
+ /**
+ * Get the total range of the derived resistance from the independent Properties of this model.
+ *
+ * @return {Range}
+ */
+ getResistanceRange: function() {
+ var minResistance = ResistanceInAWireConstants.RESISTIVITY_RANGE.min * ResistanceInAWireConstants.LENGTH_RANGE.min / ResistanceInAWireConstants.AREA_RANGE.min;
+ var maxResistance = ResistanceInAWireConstants.RESISTIVITY_RANGE.max * ResistanceInAWireConstants.LENGTH_RANGE.max / ResistanceInAWireConstants.AREA_RANGE.max;
+ return new Range( minResistance, maxResistance );
+ }
} );
} );
\ No newline at end of file
diff --git a/js/resistance-in-a-wire/view/ControlPanel.js b/js/resistance-in-a-wire/view/ControlPanel.js
index 2144ed6..b48f39a 100644
--- a/js/resistance-in-a-wire/view/ControlPanel.js
+++ b/js/resistance-in-a-wire/view/ControlPanel.js
@@ -16,10 +16,13 @@ define( function( require ) {
var resistanceInAWire = require( 'RESISTANCE_IN_A_WIRE/resistanceInAWire' );
var ResistanceInAWireA11yStrings = require( 'RESISTANCE_IN_A_WIRE/resistance-in-a-wire/ResistanceInAWireA11yStrings' );
var ResistanceInAWireConstants = require( 'RESISTANCE_IN_A_WIRE/resistance-in-a-wire/ResistanceInAWireConstants' );
+ var ResistanceInAWireModel = require( 'RESISTANCE_IN_A_WIRE/resistance-in-a-wire/model/ResistanceInAWireModel' );
var SliderUnit = require( 'RESISTANCE_IN_A_WIRE/resistance-in-a-wire/view/SliderUnit' );
var StringUtils = require( 'PHETCOMMON/util/StringUtils' );
var Text = require( 'SCENERY/nodes/Text' );
var Util = require( 'DOT/Util' );
+ var Utterance = require( 'SCENERY_PHET/accessibility/Utterance' );
+ var utteranceQueue = require( 'SCENERY_PHET/accessibility/utteranceQueue' );
// strings
var areaString = require( 'string!RESISTANCE_IN_A_WIRE/area' );
@@ -44,10 +47,22 @@ define( function( require ) {
var areaSliderLabelString = ResistanceInAWireA11yStrings.areaSliderLabelString.value;
var sliderControlsString = ResistanceInAWireA11yStrings.sliderControlsString.value;
var slidersDescriptionString = ResistanceInAWireA11yStrings.slidersDescriptionString.value;
+ var sizeChangeAlertPatternString = ResistanceInAWireA11yStrings.sizeChangeAlertPatternString.value;
+ var letterRhoString = ResistanceInAWireA11yStrings.letterRhoString.value;
+ var letterLString = ResistanceInAWireA11yStrings.letterLString.value;
+ var letterAString = ResistanceInAWireA11yStrings.letterAString.value;
+ var growsString = ResistanceInAWireA11yStrings.growsString.value;
+ var shrinksString = ResistanceInAWireA11yStrings.shrinksString.value;
+ var growsALotString = ResistanceInAWireA11yStrings.growsALotString.value;
+ var shrinksALotString = ResistanceInAWireA11yStrings.shrinksALotString.value;
// constants
var SLIDER_SPACING = 50;
+ // a11y - if resistance changes 2 * the range of the resistance / the number of relative size descriptions, larger change
+ // is signified in description
+ var LARGE_RESISTANCE_DELTA = ( ( ResistanceInAWireModel.getResistanceRange().max - ResistanceInAWireModel.getResistanceRange().min ) / ResistanceInAWireConstants.RELATIVE_SIZE_STRINGS.length ) * 2;
+
/**
* @param {ResistanceInAWireModel} model
* @param {Tandem} tandem
@@ -98,7 +113,12 @@ define( function( require ) {
resistanceReadout.centerX = 0;
} );
+ // a11y - when using a slider, we store the initial value on start drag so that we can describe size change after
+ // interaction
+ var resistanceOnStart = model.resistanceProperty.get();
+
// Create and add the resistivity slider with readout and labels.
+ var rhoOnStart = model.resistivityProperty.get();
var resistivitySlider = new SliderUnit(
model.resistivityProperty,
ResistanceInAWireConstants.RESISTIVITY_RANGE,
@@ -109,11 +129,29 @@ define( function( require ) {
tandem.createTandem( 'resistivitySlider' ), {
keyboardStep: 0.05, // ohm-cm
shiftKeyStep: 0.01, // ohms-cm
- accessibleValuePattern: resistivityUnitsPatternString
+ accessibleValuePattern: resistivityUnitsPatternString,
+ startDrag: function() {
+ rhoOnStart = model.resistivityProperty.get();
+ resistanceOnStart = model.resistanceProperty.get();
+ },
+ endDrag: function() {
+ var resistance = model.resistanceProperty.get();
+ var deltaRho = model.resistivityProperty.get() - rhoOnStart;
+ var deltaResistance = resistance - resistanceOnStart;
+
+ // announce to assistive technology if there is a change - no need to queue many alerts when pressing keys
+ // rapidly
+ if ( deltaRho ) {
+ utteranceQueue.addToBack( new Utterance( getSizeChangeAlert( resistance, deltaResistance, deltaRho, letterRhoString ), {
+ typeId: 'rhoChangeAlert'
+ } ) );
+ }
+ }
}
);
// Create and add the length slider with readout and labels.
+ var lengthOnStart = model.lengthProperty.get();
var lengthSlider = new SliderUnit(
model.lengthProperty,
ResistanceInAWireConstants.LENGTH_RANGE,
@@ -124,12 +162,30 @@ define( function( require ) {
tandem.createTandem( 'lengthSlider' ), {
keyboardStep: 1.0, // cm
shiftKeyboardStep: 0.01, // cm
- accessibleValuePattern: lengthUnitsPatternString
+ accessibleValuePattern: lengthUnitsPatternString,
+ startDrag: function() {
+ lengthOnStart = model.lengthProperty.get();
+ resistanceOnStart = model.resistanceProperty.get();
+ },
+ endDrag: function() {
+ var resistance = model.resistanceProperty.get();
+ var deltaLength = model.lengthProperty.get() - lengthOnStart;
+ var deltaResistance = resistance - resistanceOnStart;
+
+ // announce to assistive technology if there is a change - no need to queue many alerts when pressing keys
+ // rapidly
+ if ( deltaLength ) {
+ utteranceQueue.addToBack( new Utterance( getSizeChangeAlert( resistance, deltaResistance, deltaLength, letterLString ), {
+ typeId: 'rhoChangeAlert'
+ } ) );
+ }
+ }
}
);
// Create and add the area slider with readout and labels. For keyboard dragging, the range ranges doesn't split into even steps,
// so we calculate a keyboard step by breaking the range into 100.
+ var areaOnStart = model.areaProperty.get();
var areaSlider = new SliderUnit(
model.areaProperty,
ResistanceInAWireConstants.AREA_RANGE,
@@ -140,7 +196,24 @@ define( function( require ) {
tandem.createTandem( 'areaSlider' ), {
keyboardStep: 1.0, // cm^2
shiftKeyboardStep: 0.01, // cm^2
- accessibleValuePattern: areaUnitsPatternString
+ accessibleValuePattern: areaUnitsPatternString,
+ startDrag: function() {
+ areaOnStart = model.areaProperty.get();
+ resistanceOnStart = model.resistanceProperty.get();
+ },
+ endDrag: function() {
+ var resistance = model.resistanceProperty.get();
+ var deltaArea = model.areaProperty.get() - areaOnStart;
+ var deltaResistance = resistance - resistanceOnStart;
+
+ // announce to assistive technology if there is a change - no need to queue many alerts when pressing keys
+ // rapidly
+ if ( deltaArea ) {
+ utteranceQueue.addToBack( new Utterance( getSizeChangeAlert( resistance, deltaResistance, deltaArea, letterAString ), {
+ typeId: 'rhoChangeAlert'
+ } ) );
+ }
+ }
}
);
@@ -166,5 +239,58 @@ define( function( require ) {
resistanceInAWire.register( 'ControlPanel', ControlPanel );
+ /**
+ * Get a description for whether a letter grows or shrinks. Optionally, if the size changes enough, an additional
+ * fragment is included that signifies this. Will return something like
+ *
+ * 'grows'
+ * 'shrinks'
+ * 'grows a lot'
+ * 'shrinks a lot'
+ *
+ * @param {number} delta
+ * @param {boolean} describeLargeChanges
+ * @return {string}
+ */
+ var getSizeChangeFromDelta = function( delta, describeLargeChanges ) {
+ assert && assert ( delta !== 0, 'trying to describe no change in size' );
+ var description;
+
+ var useALot = ( describeLargeChanges && Math.abs( delta ) > LARGE_RESISTANCE_DELTA );
+
+ if ( delta > 0 ) {
+ description = useALot ? growsALotString : growsString;
+ }
+ else if ( delta < 0 ){
+ description = useALot ? shrinksALotString : shrinksString;
+ }
+
+ return description;
+ };
+
+ /**
+ * Get a full alert for size letter size and how R changes as well. Will return something like
+ *
+ * "As letter rho grows, letter R grows. Resistance no 0.667 ohms." or
+ * "As letter A grows, letter R shrinks a lot. Resistance now 1.20 ohms"
+ *
+ * @param {number} resistance - current value of resistance
+ * @param {number} deltaResistance - change in
+ * @param {number} otherDelta - change in other variable, resistivity, length, or area
+ * @param {string} letterString - the letter with size changes to describe
+ * @return {string}
+ */
+ var getSizeChangeAlert = function( resistance, deltaResistance, otherDelta, letterString ) {
+ var resistanceChangeString = getSizeChangeFromDelta( deltaResistance, true /*include 'a lot' */ );
+ var letterChangeString = getSizeChangeFromDelta( otherDelta, false /*dont include 'a lot */ );
+
+ return StringUtils.fillIn( sizeChangeAlertPatternString, {
+ letter: letterString,
+ letterChange: letterChangeString,
+ rChange: resistanceChangeString,
+ resistance: ResistanceInAWireConstants.getFormattedResistanceValue( resistance )
+ } );
+ };
+
return inherit( Panel, ControlPanel );
} );
\ No newline at end of file
diff --git a/js/resistance-in-a-wire/view/SliderUnit.js b/js/resistance-in-a-wire/view/SliderUnit.js
index c09a24f..e7bd9bd 100644
--- a/js/resistance-in-a-wire/view/SliderUnit.js
+++ b/js/resistance-in-a-wire/view/SliderUnit.js
@@ -37,7 +37,9 @@ define( function( require ) {
accessibleDecimalPlaces: 2,
keyboardStep: 1,
shiftKeyboardStep: 0.01,
- accessibleValuePattern: '{{value}}' // string pattern used for formatting the value read by the screen reader
+ accessibleValuePattern: '{{value}}', // string pattern used for formatting the value read by the screen reader
+ endDrag: function() {}, // called at end of drag by HSlider
+ startDrag: function() {}
}, options );
// text for the symbol, text bounds must be accurate for correct layou
@@ -69,6 +71,8 @@ define( function( require ) {
shiftKeyboardStep: options.shiftKeyboardStep, // delta when holding shift
accessibleValuePattern: options.accessibleValuePattern,
accessibleDecimalPlaces: options.accessibleDecimalPlaces, // demimal places for readout
+ startDrag: options.startDrag,
+ endDrag: options.endDrag,
parentContainerTagName: 'li',
labelTagName: 'label',