Skip to content

Commit

Permalink
progress toward using fluent patterns for the accessibility strings, …
Browse files Browse the repository at this point in the history
  • Loading branch information
jessegreenberg committed Nov 15, 2024
1 parent f39a6bb commit a88070c
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 205 deletions.
37 changes: 1 addition & 36 deletions js/ohms-law/OhmsLawConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,39 +36,6 @@ const BATTERIES_OFFSET = 30;
const AA_VOLTAGE = 1.5; // in volts
const MAX_NUMBER_OF_BATTERIES = Math.ceil( VOLTAGE_RANGE.max / AA_VOLTAGE );

// map for relative size of variables to their accessible description - ranges values are the ratio of sizes
// for instance, a value 0.25 means that the letter is 1/4 the size of the other
const COMPARATIVE_DESCRIPTION_RANGES = {
MUCH_MUCH_SMALLER: {
range: new Range( 0, 0.25 ),
description: muchMuchSmallerThanString
},
MUCH_SMALLER: {
range: new Range( 0.25, 0.50 ),
description: muchSmallerThanString
},
SLIGHTLY_SMALLER: {
range: new Range( 0.50, 0.9 ),
description: slightlySmallerThanString
},
COMPARABLE: {
range: new Range( 0.9, 1.10 ),
description: comparableToString
},
SLIGHTLY_LARGER: {
range: new Range( 1.10, 2.0 ),
description: slightlyLargerThanString
},
MUCH_LARGER: {
range: new Range( 2.0, 4.0 ),
description: muchLargerThanString
},
MUCH_MUCH_LARGER: {
range: new Range( 4.0, Number.MAX_VALUE ),
description: muchMuchLargerThanString
}
};

const OhmsLawConstants = {

// colors
Expand Down Expand Up @@ -117,9 +84,7 @@ const OhmsLawConstants = {
largeString, veryLargeString, hugeString ],

COMPARISON_SIZE_STRINGS: [ muchMuchSmallerThanString, muchSmallerThanString, slightlySmallerThanString,
comparableToString, slightlyLargerThanString, muchLargerThanString, muchMuchLargerThanString ],

COMPARATIVE_DESCRIPTION_RANGES: COMPARATIVE_DESCRIPTION_RANGES
comparableToString, slightlyLargerThanString, muchLargerThanString, muchMuchLargerThanString ]
};

ohmsLaw.register( 'OhmsLawConstants', OhmsLawConstants );
Expand Down
18 changes: 10 additions & 8 deletions js/ohms-law/view/BatteriesView.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@

import Utils from '../../../../dot/js/Utils.js';
import merge from '../../../../phet-core/js/merge.js';
import StringUtils from '../../../../phetcommon/js/util/StringUtils.js';
import { Node } from '../../../../scenery/js/imports.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import ohmsLaw from '../../ohmsLaw.js';
import OhmsLawA11yStrings from '../OhmsLawA11yStrings.js';
import OhmsLawFluentMessages, { PatternMessageProperty } from '../../OhmsLawFluentMessages.js';
import DerivedProperty from '../../../../axon/js/DerivedProperty.js';
import OhmsLawConstants from '../OhmsLawConstants.js';
import BatteryView from './BatteryView.js';

const batteriesSupplyPatternString = OhmsLawA11yStrings.batteriesSupplyPattern.value;

class BatteriesView extends Node {
/**
* @param {Property.<number>} voltageProperty
Expand Down Expand Up @@ -66,10 +64,14 @@ class BatteriesView extends Node {
}
} );

// pdom - update the description for the number of batteries
this.innerContent = StringUtils.fillIn( batteriesSupplyPatternString, {
voltage: Utils.toFixed( voltage, OhmsLawConstants.VOLTAGE_SIG_FIGS )
} );
this.innerContent = new PatternMessageProperty(
OhmsLawFluentMessages.batteriesSupplyPatternMessageProperty,
{
voltage: new DerivedProperty( [ voltageProperty ], voltage => {
return Utils.toFixed( voltage, OhmsLawConstants.VOLTAGE_SIG_FIGS );
} )
}
);
} );
this.mutate( options );
}
Expand Down
36 changes: 22 additions & 14 deletions js/ohms-law/view/ControlPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

import DerivedProperty from '../../../../axon/js/DerivedProperty.js';
import merge from '../../../../phet-core/js/merge.js';
import StringUtils from '../../../../phetcommon/js/util/StringUtils.js';
import SceneryPhetStrings from '../../../../scenery-phet/js/SceneryPhetStrings.js';
import { HBox } from '../../../../scenery/js/imports.js';
import Panel from '../../../../sun/js/Panel.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import ValueChangeUtterance from '../../../../utterance-queue/js/ValueChangeUtterance.js';
import ohmsLaw from '../../ohmsLaw.js';
import OhmsLawFluentMessages, { PatternMessageProperty } from '../../OhmsLawFluentMessages.js';
import OhmsLawStrings from '../../OhmsLawStrings.js';
import OhmsLawModel from '../model/OhmsLawModel.js';
import OhmsLawA11yStrings from '../OhmsLawA11yStrings.js';
Expand All @@ -28,20 +28,14 @@ const voltageSymbolString = OhmsLawStrings.voltageSymbol;
const voltageUnitsString = OhmsLawStrings.voltageUnits;

// can provide translators with context
const resistanceUnitsPatternString = OhmsLawA11yStrings.resistanceUnitsPattern.value;
const voltageUnitsPatternString = OhmsLawA11yStrings.voltageUnitsPattern.value;
const resistanceSliderLabelString = OhmsLawA11yStrings.resistanceSliderLabel.value;
const voltageSliderLabelString = OhmsLawA11yStrings.voltageSliderLabel.value;
const sliderControlsString = OhmsLawA11yStrings.sliderControls.value;
const slidersDescriptionString = OhmsLawA11yStrings.slidersDescription.value;
const letterRString = OhmsLawA11yStrings.letterR.value;
const letterVString = OhmsLawA11yStrings.letterV.value;
const shrinksString = OhmsLawA11yStrings.shrinks.value;
const growsString = OhmsLawA11yStrings.grows.value;
const aLotString = OhmsLawA11yStrings.aLot.value;

// constants
const NUMBER_OF_LETTER_SIZES = OhmsLawA11yStrings.numberOfSizes.value; // pdom - the number of sizes that letters can be described as.
const NUMBER_OF_LETTER_SIZES = 6; // pdom - the number of sizes that letters can be described as.

class ControlPanel extends Panel {

Expand Down Expand Up @@ -69,6 +63,13 @@ class ControlPanel extends Panel {
const resistanceUtterance = new ValueChangeUtterance();
const voltageUtterance = new ValueChangeUtterance();

const voltageUnitsMessageProperty = new PatternMessageProperty(
OhmsLawFluentMessages.voltageUnitsPatternMessageProperty,
{
value: voltageProperty
}
);

// Create the voltage slider with readout and labels
let oldVoltage; // stored on startDrag;
let newVoltage; // stored on endDrag;
Expand All @@ -78,13 +79,13 @@ class ControlPanel extends Panel {
voltageSymbolString,
voltageString,
voltageUnitsString,
voltageSliderLabelString,
OhmsLawFluentMessages.voltageSliderLabelMessageProperty,
{
sliderOptions: {

// pdom
keyboardStep: 0.5, // volts
pdomCreateAriaValueText: value => StringUtils.fillIn( voltageUnitsPatternString, { value: value } ),
pdomCreateAriaValueText: value => voltageUnitsMessageProperty.value,
startDrag: () => {
oldVoltage = voltageProperty.get();
},
Expand Down Expand Up @@ -133,20 +134,27 @@ class ControlPanel extends Panel {
};

// Create the resistance slider with readout and labels
const resistanceUnitsMessageProperty = new PatternMessageProperty(
OhmsLawFluentMessages.resistanceUnitsPatternMessageProperty,
{
value: resistanceProperty
}
);

const resistanceSlider = new SliderUnit(
resistanceProperty,
OhmsLawConstants.RESISTANCE_RANGE,
resistanceSymbolString,
resistanceString,
SceneryPhetStrings.symbol.ohmsStringProperty,
resistanceSliderLabelString,
OhmsLawFluentMessages.resistanceSliderLabelMessageProperty,
{
sliderOptions: {

// pdom
keyboardStep: 20, // ohms
shiftKeyboardStep: 1, // ohms
pdomCreateAriaValueText: value => StringUtils.fillIn( resistanceUnitsPatternString, { value: value } ),
pdomCreateAriaValueText: value => resistanceUnitsMessageProperty.value,
startDrag: () => {
oldResistance = resistanceProperty.get();
oldCurrent = currentProperty.get();
Expand All @@ -165,8 +173,8 @@ class ControlPanel extends Panel {
// pdom - contain the sliders in a list
labelTagName: 'h3',
tagName: 'div',
labelContent: sliderControlsString,
descriptionContent: slidersDescriptionString
labelContent: OhmsLawFluentMessages.sliderControlsMessageProperty,
descriptionContent: OhmsLawFluentMessages.slidersDescriptionMessageProperty
} );

super( content, options );
Expand Down
81 changes: 81 additions & 0 deletions js/ohms-law/view/FormulaDescriber.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2024, University of Colorado Boulder

/**
* Describes the relationships between the letters in the Ohm's Law formula.
*
* @author Jesse Greenberg (PhET Interactive Simulations)
*/

import DerivedProperty from '../../../../axon/js/DerivedProperty.js';
import Range from '../../../../dot/js/Range.js';
import Enumeration from '../../../../phet-core/js/Enumeration.js';
import EnumerationValue from '../../../../phet-core/js/EnumerationValue.js';
import ohmsLaw from '../../ohmsLaw.js';

// enum for describing the relative sizes of letters
class SizeComparison extends EnumerationValue {
static MUCH_MUCH_SMALLER = new SizeComparison();
static MUCH_SMALLER = new SizeComparison();
static SLIGHTLY_SMALLER = new SizeComparison();
static COMPARABLE = new SizeComparison();
static SLIGHTLY_LARGER = new SizeComparison();
static MUCH_LARGER = new SizeComparison();
static MUCH_MUCH_LARGER = new SizeComparison();
static enumeration = new Enumeration( SizeComparison );
}

// Map for relative size of variables to their accessible description - ranges values are the
// ratio of sizes for instance, a value 0.25 means that the letter is 1/4 the size of the other.
const COMPARATIVE_DESCRIPTION_RANGES = new Map( [
[ new Range( 0, 0.25 ), SizeComparison.MUCH_MUCH_SMALLER ],
[ new Range( 0.25, 0.50 ), SizeComparison.MUCH_SMALLER ],
[ new Range( 0.50, 0.9 ), SizeComparison.SLIGHTLY_SMALLER ],
[ new Range( 0.9, 1.10 ), SizeComparison.COMPARABLE ],
[ new Range( 1.10, 2.0 ), SizeComparison.SLIGHTLY_LARGER ],
[ new Range( 2.0, 4.0 ), SizeComparison.MUCH_LARGER ],
[ new Range( 4.0, Number.MAX_VALUE ), SizeComparison.MUCH_MUCH_LARGER ]
] );

const COMPARATIVE_RANGES = Array.from( COMPARATIVE_DESCRIPTION_RANGES.keys() );

export default class FormulaDescriber {
constructor( model, resistanceLetterNode, currentLetterNode, voltageLetterNode ) {
this.resistanceLetterNode = resistanceLetterNode;
this.currentLetterNode = currentLetterNode;
this.voltageLetterNode = voltageLetterNode;

// The SizeComparison between the ltter V and I
this.vToIComparisonProperty = new DerivedProperty( [ model.voltageProperty, model.currentProperty ], ( voltage, current ) => {
return this.compareNodeHeight( this.voltageLetterNode, this.currentLetterNode );
} );

// The SizeComparison between the ltter V and R
this.vToRComparisonProperty = new DerivedProperty( [ model.voltageProperty, model.resistanceProperty ], ( voltage, resistance ) => {
return this.compareNodeHeight( this.voltageLetterNode, this.resistanceLetterNode );
} );
}

/**
* Returns a SizeComparison between the height of two Nodes. The returned value compares "nodeA" to "nodeB", such that
* a value of MUCH_SMALLER means that "nodeA" is much smaller than "nodeB".
* @private
*/
compareNodeHeight( nodeA, nodeB ) {
const aHeight = nodeA.height;
const bHeight = nodeB.height;

const aToB = aHeight / bHeight;

for ( let i = 0; i < COMPARATIVE_RANGES.length; i++ ) {
const range = COMPARATIVE_RANGES[ i ];
if ( range.contains( aToB ) ) {
return COMPARATIVE_DESCRIPTION_RANGES.get( range );
}
}

// Arbitrary default for consistent return.
return SizeComparison.MUCH_MUCH_SMALLER;
}
}

ohmsLaw.register( 'FormulaDescriber', FormulaDescriber );
77 changes: 12 additions & 65 deletions js/ohms-law/view/FormulaNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,22 @@
* @author Anton Ulyanov (Mlearner)
*/

import Multilink from '../../../../axon/js/Multilink.js';
import merge from '../../../../phet-core/js/merge.js';
import StringUtils from '../../../../phetcommon/js/util/StringUtils.js';
import MathSymbols from '../../../../scenery-phet/js/MathSymbols.js';
import PhetColorScheme from '../../../../scenery-phet/js/PhetColorScheme.js';
import PhetFont from '../../../../scenery-phet/js/PhetFont.js';
import { Node, Rectangle, Text } from '../../../../scenery/js/imports.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import ohmsLaw from '../../ohmsLaw.js';
import OhmsLawFluentMessages, { PatternMessageProperty } from '../../OhmsLawFluentMessages.js';
import OhmsLawStrings from '../../OhmsLawStrings.js';
import OhmsLawA11yStrings from '../OhmsLawA11yStrings.js';
import OhmsLawConstants from '../OhmsLawConstants.js';
import FormulaDescriber from './FormulaDescriber.js';

const currentSymbolString = OhmsLawStrings.currentSymbol;
const resistanceSymbolString = OhmsLawStrings.resistanceSymbol;
const voltageSymbolString = OhmsLawStrings.voltageSymbol;

const relativeSizePatternString = OhmsLawA11yStrings.relativeSizePattern.value;
const ohmsLawEquationString = OhmsLawA11yStrings.ohmsLawEquation.value;
const ohmsLawDefinitionString = OhmsLawA11yStrings.ohmsLawDefinition.value;

// constants
const TEXT_FONT = new PhetFont( { family: OhmsLawConstants.FONT_FAMILY, size: 20, weight: 'bold' } );
const CURRENT_SCALE_M = 150; // empirically determined
Expand All @@ -46,8 +41,8 @@ class FormulaNode extends Node {
tandem: Tandem.REQUIRED,

// pdom
labelContent: ohmsLawEquationString,
descriptionContent: ohmsLawDefinitionString,
labelContent: OhmsLawFluentMessages.ohmsLawEquationMessageProperty,
descriptionContent: OhmsLawFluentMessages.ohmsLawDefinitionMessageProperty,
tagName: 'div',
labelTagName: 'h3' // labels should come before other child content
}, options );
Expand Down Expand Up @@ -132,65 +127,17 @@ class FormulaNode extends Node {
const descriptionNode = new Node( { tagName: 'p' } );
this.addChild( descriptionNode );

// when any of the model Properties change, update the accessible description
Multilink.multilink( [ model.currentProperty, model.resistanceProperty, model.voltageProperty ], ( current, resistance, voltage ) => {
descriptionNode.innerContent = this.getComparativeSizeDescription();
} );

this.mutate( options );
}

const formulaDescriber = new FormulaDescriber( model, this.resistanceLetterNode, this.currentLetterNode, this.voltageLetterNode );

/**
* Get the comparative size description for the letters, something like
* "Letter V is much larger than letter I and comparable to letter R."
* Used for a11y.
*
* @public
* @returns {string}
*/
getComparativeSizeDescription() {

const rHeight = this.resistanceLetterNode.height;
const iHeight = this.currentLetterNode.height;
const vHeight = this.voltageLetterNode.height;

const vToI = vHeight / iHeight;
const vToR = vHeight / rHeight;

// for iteration
let i;
let describedRange;

// map the relations to the comparative descriptions
// loop through array of keys to avoid closures every time this is called
const ranges = OhmsLawConstants.COMPARATIVE_DESCRIPTION_RANGES;
const keys = Object.keys( ranges );

// get the relative size description comparing V to I
let vToIDescription;
for ( i = 0; i < keys.length; i++ ) {
describedRange = ranges[ keys[ i ] ];
if ( describedRange.range.contains( vToI ) ) {
vToIDescription = describedRange.description;
break;
}
}

// get the relative size description comparing V to R
let vToRDescription;
for ( i = 0; i < keys.length; i++ ) {
describedRange = ranges[ keys[ i ] ];
if ( describedRange.range.contains( vToR ) ) {
vToRDescription = describedRange.description;
break;
descriptionNode.innerContent = new PatternMessageProperty(
OhmsLawFluentMessages.relativeSizePatternMessageProperty,
{
iComparison: formulaDescriber.vToIComparisonProperty,
rComparison: formulaDescriber.vToRComparisonProperty
}
}
);

return StringUtils.fillIn( relativeSizePatternString, {
iComparison: vToIDescription,
rComparison: vToRDescription
} );
this.mutate( options );
}
}

Expand Down
Loading

0 comments on commit a88070c

Please sign in to comment.