diff --git a/js/resistance-in-a-wire/ResistanceInAWireA11yStrings.js b/js/resistance-in-a-wire/ResistanceInAWireA11yStrings.js
index fcc60f6..a73634d 100644
--- a/js/resistance-in-a-wire/ResistanceInAWireA11yStrings.js
+++ b/js/resistance-in-a-wire/ResistanceInAWireA11yStrings.js
@@ -35,6 +35,42 @@ define( function( require ) {
summaryAreaPatternString: {
value: 'area, A is {{value}} centimeters squared',
},
+ resistanceEquationString: {
+ value: 'Resistance Equation'
+ },
+ resistanceEquationDescriptionString: {
+ value: 'Resistance, R, is equal to resistivity, rho, times length, L, over area, A.'
+ },
+ rhoLAndAComparablePatternString: {
+ value: 'Size of letter R is {{rToAll}} the size of the letter rho, letter L, and letter A.'
+ },
+ lAndAComparablePatternString: {
+ value: 'Size of letter R is {{rToRho}} the size of letter rho, and {{rToLAndA}} than letter L and letter A.'
+ },
+ noneComparablePatternString: {
+ value: 'Size of letter R is {{rToRho}} the size of letter rho, {{rToL}} letter L, and {{rToA}} letter A.'
+ },
+ muchMuchSmallerThanString: {
+ value: 'much much smaller than',
+ },
+ muchSmallerThanString: {
+ value: 'much smaller than',
+ },
+ slightlySmallerThanString: {
+ value: 'slightly smaller than',
+ },
+ comparableToString: {
+ value: 'comparable to',
+ },
+ slightlyLargerThanString: {
+ value: 'slightly larger than',
+ },
+ muchLargerThanString: {
+ value: 'much larger than',
+ },
+ muchMuchLargerThanString: {
+ value: 'much much larger than',
+ },
resistivityUnitsPatternString: {
value: '{{value}} ohm centimeters',
},
diff --git a/js/resistance-in-a-wire/ResistanceInAWireConstants.js b/js/resistance-in-a-wire/ResistanceInAWireConstants.js
index e3a559b..dad45b0 100644
--- a/js/resistance-in-a-wire/ResistanceInAWireConstants.js
+++ b/js/resistance-in-a-wire/ResistanceInAWireConstants.js
@@ -11,8 +11,19 @@ define( function( require ) {
// modules
var PhetFont = require( 'SCENERY_PHET/PhetFont' );
var RangeWithValue = require( 'DOT/RangeWithValue' );
+ 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' );
+ // a11y strings
+ var muchMuchSmallerThanString = ResistanceInAWireA11yStrings.muchMuchSmallerThanString.value;
+ var muchSmallerThanString = ResistanceInAWireA11yStrings.muchSmallerThanString.value;
+ var slightlySmallerThanString = ResistanceInAWireA11yStrings.slightlySmallerThanString.value;
+ var comparableToString = ResistanceInAWireA11yStrings.comparableToString.value;
+ var slightlyLargerThanString = ResistanceInAWireA11yStrings.slightlyLargerThanString.value;
+ var muchLargerThanString = ResistanceInAWireA11yStrings.muchLargerThanString.value;
+ var muchMuchLargerThanString = ResistanceInAWireA11yStrings.muchMuchLargerThanString.value;
+
var ResistanceInAWireConstants = {
// colors
@@ -54,6 +65,39 @@ define( function( require ) {
resistance < 0.001 ? 4 : // when less than 0.001, show 4 decimals, see #125
resistance < 1 ? 3 : // when less than 1, show 3 decimal places, see #125
2; // Numbers less than 10 show 2 decimal points, like 8.35
+ },
+
+
+ // a11y - used to map relative scale magnitudes of the letters to relative size description
+ RELATIVE_SIZE_MAP: {
+ muchMuchSmaller: {
+ description: muchMuchSmallerThanString,
+ range: new Range( 0, 0.1)
+ },
+ muchSmaller: {
+ description: muchSmallerThanString,
+ range: new Range( 0.1, 0.4 )
+ },
+ slightlySmaller: {
+ description: slightlySmallerThanString,
+ range: new Range( 0.4, 0.7 )
+ },
+ comparable: {
+ description: comparableToString,
+ range: new Range( 0.7, 1.3 )
+ },
+ slightlyLarger: {
+ description: slightlyLargerThanString,
+ range: new Range( 1.3, 2 )
+ },
+ muchLarger: {
+ description: muchLargerThanString,
+ range: new Range( 2, 20 )
+ },
+ muchMuchLarger: {
+ description: muchMuchLargerThanString,
+ range: new Range( 20, Number.MAX_VALUE )
+ }
}
};
diff --git a/js/resistance-in-a-wire/view/AccessibleSummaryNode.js b/js/resistance-in-a-wire/view/AccessibleSummaryNode.js
index 9f22de6..b9fb506 100644
--- a/js/resistance-in-a-wire/view/AccessibleSummaryNode.js
+++ b/js/resistance-in-a-wire/view/AccessibleSummaryNode.js
@@ -96,7 +96,6 @@ define( function( require ) {
// the precision might change during interaction, get precision if property is a function
var precision = typeof item.precision === 'number' ? item.precision : item.precision( value );
- console.log( item.patternString );
item.node.accessibleLabelAsHTML = StringUtils.fillIn( item.patternString, {
value: Util.toFixed( value, precision )
} );
diff --git a/js/resistance-in-a-wire/view/FormulaNode.js b/js/resistance-in-a-wire/view/FormulaNode.js
index 345488c..1fc808f 100644
--- a/js/resistance-in-a-wire/view/FormulaNode.js
+++ b/js/resistance-in-a-wire/view/FormulaNode.js
@@ -22,7 +22,9 @@ define( function( require ) {
var resistanceInAWire = require( 'RESISTANCE_IN_A_WIRE/resistanceInAWire' );
var ResistanceInAWireConstants = require( 'RESISTANCE_IN_A_WIRE/resistance-in-a-wire/ResistanceInAWireConstants' );
var Shape = require( 'KITE/Shape' );
+ var ResistanceInAWireA11yStrings = require( 'RESISTANCE_IN_A_WIRE/resistance-in-a-wire/ResistanceInAWireA11yStrings' );
var Text = require( 'SCENERY/nodes/Text' );
+ var StringUtils = require( 'PHETCOMMON/util/StringUtils' );
var Vector2 = require( 'DOT/Vector2' );
// strings
@@ -31,6 +33,20 @@ define( function( require ) {
var resistanceSymbolString = require( 'string!RESISTANCE_IN_A_WIRE/resistanceSymbol' );
var resistivitySymbolString = require( 'string!RESISTANCE_IN_A_WIRE/resistivitySymbol' );
+ // a11y strings
+ var resistanceEquationString = ResistanceInAWireA11yStrings.resistanceEquationString.value;
+ var resistanceEquationDescriptionString = ResistanceInAWireA11yStrings.resistanceEquationDescriptionString.value;
+ var rhoLAndAComparablePatternString = ResistanceInAWireA11yStrings.rhoLAndAComparablePatternString.value;
+ var lAndAComparablePatternString = ResistanceInAWireA11yStrings.lAndAComparablePatternString.value;
+ var noneComparablePatternString = ResistanceInAWireA11yStrings.noneComparablePatternString.value;
+
+ // constants - rather than keep a reference to each letter node, a map from key to scale magnitude is used
+ // to track letter scales
+ var RESISTANCE_KEY = 'resistance';
+ var RESISTIVITY_KEY = 'resistivity';
+ var AREA_KEY = 'area';
+ var LENGTH_KEY = 'length';
+
/**
* @param {ResistanceInAWireModel} model
* @param {Tandem} tandem
@@ -39,7 +55,16 @@ define( function( require ) {
*/
function FormulaNode( model, tandem, options ) {
- Node.call( this, { tandem: tandem } );
+ Node.call( this, {
+ tandem: tandem,
+
+ // a11y
+ tagName: 'div',
+ labelTagName: 'h3',
+ accessibleLabel: resistanceEquationString,
+ prependLabels: true,
+ accessibleDescriptionAsHTML: resistanceEquationDescriptionString
+ } );
// equals sign, hard coded
var equalsSignText = new Text( '=', { // we never internationalize the '=' sign
@@ -49,6 +74,13 @@ define( function( require ) {
tandem: tandem.createTandem( 'equalsSign' )
} );
+ // maps identifier to scale magnitude
+ this.a11yScaleMap = {};
+ this.a11yScaleMap[ RESISTANCE_KEY ] = 0;
+ this.a11yScaleMap[ RESISTIVITY_KEY ] = 0;
+ this.a11yScaleMap[ AREA_KEY ] = 0;
+ this.a11yScaleMap[ LENGTH_KEY ] = 0;
+
// An array of attributes related to text
var symbolTexts = [ {
label: resistanceSymbolString,
@@ -56,28 +88,34 @@ define( function( require ) {
property: model.resistanceProperty,
color: ResistanceInAWireConstants.RED_COLOR,
cappedSize: true, // To make sure that the 'R' doesn't get too big, see https://github.com/phetsims/resistance-in-a-wire/issues/28
- tandem: tandem.createTandem( 'resistanceSymbol' )
+ tandem: tandem.createTandem( 'resistanceSymbol' ),
+ scaleKey: RESISTANCE_KEY
}, {
label: resistivitySymbolString,
center: new Vector2( equalsSignText.centerX + 120, -90 ),
property: model.resistivityProperty,
color: ResistanceInAWireConstants.BLUE_COLOR,
- tandem: tandem.createTandem( 'resistivitySymbol' )
+ tandem: tandem.createTandem( 'resistivitySymbol' ),
+ scaleKey: RESISTIVITY_KEY
}, {
label: lengthSymbolString,
center: new Vector2( equalsSignText.centerX + 220, -90 ),
property: model.lengthProperty,
color: ResistanceInAWireConstants.BLUE_COLOR,
- tandem: tandem.createTandem( 'lengthSymbol' )
+ tandem: tandem.createTandem( 'lengthSymbol' ),
+ scaleKey: LENGTH_KEY
}, {
label: areaSymbolString,
center: new Vector2( equalsSignText.centerX + 170, 90 ),
property: model.areaProperty,
color: ResistanceInAWireConstants.BLUE_COLOR,
- tandem: tandem.createTandem( 'areaSymbol' )
+ tandem: tandem.createTandem( 'areaSymbol' ),
+ scaleKey: AREA_KEY
} ];
- var lettersNode = new Node();
+ // parent for all letters in the equation - given a 'p' tag for a11y because this node will hold the relative
+ // size description, see getRelativeSizeDescription()
+ var lettersNode = new Node( { tagName: 'p' } );
// if we are on a safari platform render with canvas to prevent these issues, but only on safari because
// canvas doesn't perform as well on other browsers
@@ -86,6 +124,7 @@ define( function( require ) {
if ( platform.safari ) { lettersNode.renderer = 'canvas'; }
// dynamically sized text
+ var self = this;
symbolTexts.forEach( function( entry ) {
var text = new Text( entry.label, {
@@ -106,11 +145,20 @@ define( function( require ) {
// Set the scale based on the default value of the property; normalize the scale for all letters.
var scale = 7 / entry.property.value; // empirically determined '7'
- // The size of the formula letter will scale with the value the letter represents. This does not need an unlink
- // because it exists for the life of the sim.
+ // The size of the formula letter will scale with the value the letter represents. The accessible description for
+ // the equation will also update. This does not need an unlink because it exists for the life of the sim.
entry.property.link( function( value ) {
- letterNode.setScaleMagnitude( scale * value + 1 );
+ var scaleMagnitude = scale * value + 1;
+ letterNode.setScaleMagnitude( scaleMagnitude );
letterNode.center = entry.center;
+
+ // for lookup when describing relative letter sizes
+ self.a11yScaleMap[ entry.scaleKey ] = scaleMagnitude;
+ } );
+
+ // linked lazily so that relative scales are defined
+ entry.property.lazyLink( function() {
+ lettersNode.setAccessibleDescription( self.getRelativeSizeDescription() );
} );
} );
@@ -127,9 +175,96 @@ define( function( require ) {
} ) );
this.mutate( options );
+
+ // a11y - set the initial description
+ lettersNode.setAccessibleDescription( self.getRelativeSizeDescription() );
}
resistanceInAWire.register( 'FormulaNode', FormulaNode );
- return inherit( Node, FormulaNode );
+ inherit( Node, FormulaNode, {
+
+ /**
+ * Get a description of the relative size of various letters. Size of each letter is described relative to
+ * resistance R. When all or L and A letters are the same size, a simplified sentence is used to reduce verbosity,
+ * so this function might return something like:
+ *
+ * "Size of letter R is comparable to the size of letter rho, letter L, and letter A" or
+ * "Size of letter R is much larger than the size of letter rho, and slightly larger than letter L and letter A." or
+ * "Size of letter R is much smaller than letter rho, comparable to letter L, and much much larger than letter A."
+ *
+ * @return {string}
+ * @a11y
+ */
+ getRelativeSizeDescription: function() {
+ var resistanceScale = this.a11yScaleMap[ RESISTANCE_KEY ];
+ var resistivityScale = this.a11yScaleMap[ RESISTIVITY_KEY ];
+ var areaScale = this.a11yScaleMap[ AREA_KEY ];
+ var lengthScale = this.a11yScaleMap[ LENGTH_KEY ];
+
+ var rToRho = resistanceScale / resistivityScale;
+ var rToA = resistanceScale / areaScale;
+ var rToL = resistanceScale / lengthScale;
+ var lToA = lengthScale / areaScale;
+ var lToRho = lengthScale / resistivityScale;
+
+ var rToRhoDescription = getRelativeSizeDescription( rToRho );
+ var roTLDescription = getRelativeSizeDescription( rToL );
+ var rToADescription = getRelativeSizeDescription( rToA );
+
+ var description;
+ var comparableRange = ResistanceInAWireConstants.RELATIVE_SIZE_MAP.comparable.range;
+ if ( comparableRange.contains( lToA ) && comparableRange.contains( lToRho ) ) {
+
+ // all right hand side letters are comparable in size
+ description = StringUtils.fillIn( rhoLAndAComparablePatternString, {
+ rToAll: rToRhoDescription // any size description will work
+ } );
+ }
+ else if ( comparableRange.contains( lToA ) ) {
+
+ // L and A are comparable, so they are the same size relative to R
+ description = StringUtils.fillIn( lAndAComparablePatternString, {
+ rToRho: rToRhoDescription,
+ rToLAndA: roTLDescription // either length or area relative descriptions will work
+ } );
+ }
+ else {
+
+ // all relative sizes could be unique
+ description = StringUtils.fillIn( noneComparablePatternString, {
+ rToRho: rToRhoDescription,
+ rToL: roTLDescription,
+ rToA: rToADescription
+ } );
+ }
+
+ return description;
+ }
+ } );
+
+ /**
+ * Get a relative size description from a relative scale, used to describe letters relative to each other. Will return
+ * something like
+ *
+ * "comparable to" or
+ * "much much larger than"
+ *
+ * @param {number} relativeScale
+ * @return {string}
+ */
+ var getRelativeSizeDescription = function( relativeScale ) {
+
+ // get described ranges of each relative scale
+ var keys = Object.keys( ResistanceInAWireConstants.RELATIVE_SIZE_MAP );
+ for ( var i = 0; i < keys.length; i++ ) {
+ var relativeEntry = ResistanceInAWireConstants.RELATIVE_SIZE_MAP[ keys[ i ] ];
+
+ if ( relativeEntry.range.contains( relativeScale ) ) {
+ return relativeEntry.description;
+ }
+ }
+ };
+
+ return FormulaNode;
} );
\ No newline at end of file
diff --git a/js/resistance-in-a-wire/view/ResistanceInAWireScreenView.js b/js/resistance-in-a-wire/view/ResistanceInAWireScreenView.js
index 9923f23..9281d5b 100644
--- a/js/resistance-in-a-wire/view/ResistanceInAWireScreenView.js
+++ b/js/resistance-in-a-wire/view/ResistanceInAWireScreenView.js
@@ -11,6 +11,7 @@ define( function( require ) {
// modules
var AccessibleSummaryNode = require( 'RESISTANCE_IN_A_WIRE/resistance-in-a-wire/view/AccessibleSummaryNode' );
+ var AccessibleSectionNode = require( 'SCENERY_PHET/accessibility/AccessibleSectionNode' );
var ArrowNode = require( 'SCENERY_PHET/ArrowNode' );
var ControlPanel = require( 'RESISTANCE_IN_A_WIRE/resistance-in-a-wire/view/ControlPanel' );
var FocusHighlightPath = require( 'SCENERY/accessibility/FocusHighlightPath' );
@@ -22,6 +23,11 @@ define( function( require ) {
var ScreenView = require( 'JOIST/ScreenView' );
var Shape = require( 'KITE/Shape' );
var WireNode = require( 'RESISTANCE_IN_A_WIRE/resistance-in-a-wire/view/WireNode' );
+ var JoistA11yStrings = require( 'JOIST/JoistA11yStrings' );
+
+ // a11y strings
+ var playAreaString = JoistA11yStrings.playAreaString;
+ var controlPanelString = JoistA11yStrings.controlPanelString;
/**
* @param {ResistanceInAWireModel} model
@@ -35,8 +41,16 @@ define( function( require ) {
} );
// a11y - Create and add the summary for this simulation, the first thing screen reader users encounter
- var summaryNode = new AccessibleSummaryNode( model );
- this.addChild( summaryNode );
+ var a11ySummaryNode = new AccessibleSummaryNode( model );
+ this.addChild( a11ySummaryNode );
+
+ // a11y - the play area for this sim, containing elements that are significant to the pedagogy of the sim
+ var a11yPlayAreaNode = new AccessibleSectionNode( playAreaString );
+ this.addChild( a11yPlayAreaNode );
+
+ // a11y - the control panel for this sim, containing supplemental controls
+ var a11yControlPanelNode = new AccessibleSectionNode( controlPanelString );
+ this.addChild( a11yControlPanelNode );
// Create the control panel with sliders that change the values of the equation's variables. Hard coded
var controlPanel = new ControlPanel( model, tandem.createTandem( 'controlPanel' ), {
@@ -49,14 +63,14 @@ define( function( require ) {
centerX: controlPanel.left / 2,
centerY: 190
} );
- this.addChild( formulaNode );
+ a11yPlayAreaNode.addChild( formulaNode );
// Create the wire display to represent the formula
var wireNode = new WireNode( model, tandem.createTandem( 'wireNode' ), {
centerX: formulaNode.centerX,
centerY: formulaNode.centerY + 270
} );
- this.addChild( wireNode );
+ a11yPlayAreaNode.addChild( wireNode );
var tailX = wireNode.centerX - ResistanceInAWireConstants.TAIL_LENGTH / 2;
var tipX = wireNode.centerX + ResistanceInAWireConstants.TAIL_LENGTH / 2;
@@ -72,7 +86,7 @@ define( function( require ) {
lineWidth: 1,
tandem: tandem.createTandem( 'arrowNode' )
} );
- this.addChild( arrowNode );
+ a11yPlayAreaNode.addChild( arrowNode );
var resetAllButton = new ResetAllButton( {
listener: function() { model.reset(); },
@@ -81,7 +95,7 @@ define( function( require ) {
bottom: this.layoutBounds.bottom - 20,
tandem: tandem.createTandem( 'resetAllButton' )
} );
- this.addChild( resetAllButton );
+ a11yControlPanelNode.addChild( resetAllButton );
// the outer stroke of the ResetAllButton focus highlight is black so that it is visible when the equation
// resistance letter grows too large
@@ -90,10 +104,10 @@ define( function( require ) {
resetAllButton.focusHighlight = new FocusHighlightPath( highlightShape , { outerStroke: 'black' } );
// add the control panel last so it is always on top.
- this.addChild( controlPanel );
+ a11yPlayAreaNode.addChild( controlPanel );
// a11y - the reset all button should come last, control panel first
- this.accessibleOrder = [ summaryNode, controlPanel ];
+ this.accessibleOrder = [ a11ySummaryNode, a11yPlayAreaNode ];
}
resistanceInAWire.register( 'ResistanceInAWireScreenView', ResistanceInAWireScreenView );