diff --git a/js/ohms-law/OhmsLawConstants.js b/js/ohms-law/OhmsLawConstants.js index b8ed082..d91339c 100644 --- a/js/ohms-law/OhmsLawConstants.js +++ b/js/ohms-law/OhmsLawConstants.js @@ -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 @@ -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 ); diff --git a/js/ohms-law/view/BatteriesView.js b/js/ohms-law/view/BatteriesView.js index fc88e2e..177a6cb 100644 --- a/js/ohms-law/view/BatteriesView.js +++ b/js/ohms-law/view/BatteriesView.js @@ -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.} voltageProperty @@ -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 ); } diff --git a/js/ohms-law/view/ControlPanel.js b/js/ohms-law/view/ControlPanel.js index afe89ec..63931f0 100644 --- a/js/ohms-law/view/ControlPanel.js +++ b/js/ohms-law/view/ControlPanel.js @@ -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'; @@ -28,12 +28,6 @@ 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; @@ -41,7 +35,7 @@ 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 { @@ -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; @@ -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(); }, @@ -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(); @@ -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 ); diff --git a/js/ohms-law/view/FormulaDescriber.js b/js/ohms-law/view/FormulaDescriber.js new file mode 100644 index 0000000..8049464 --- /dev/null +++ b/js/ohms-law/view/FormulaDescriber.js @@ -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 ); \ No newline at end of file diff --git a/js/ohms-law/view/FormulaNode.js b/js/ohms-law/view/FormulaNode.js index 6403446..dc9ebbb 100644 --- a/js/ohms-law/view/FormulaNode.js +++ b/js/ohms-law/view/FormulaNode.js @@ -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 @@ -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 ); @@ -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 ); } } diff --git a/js/ohms-law/view/OhmsLawDescriber.js b/js/ohms-law/view/OhmsLawDescriber.js index 895a34b..cbd1a6f 100644 --- a/js/ohms-law/view/OhmsLawDescriber.js +++ b/js/ohms-law/view/OhmsLawDescriber.js @@ -21,7 +21,7 @@ const currentAmpsString = OhmsLawA11yStrings.currentAmps.value; const sliderChangeAlertPatternString = OhmsLawA11yStrings.sliderChangeAlertPattern.value; // enum for describing resistance impurities -export class ResistorImpurities extends EnumerationValue { +class ResistorImpurities extends EnumerationValue { static TINY = new ResistorImpurities(); static VERY_SMALL = new ResistorImpurities(); static SMALL = new ResistorImpurities(); @@ -51,6 +51,10 @@ class OhmsLawDescriber { const index = Utils.roundSymmetric( Utils.linear( range.min, range.max, 0, values.length - 1, resistance ) ); return values[ index ]; } ); + + this.formattedCurrentProperty = new DerivedProperty( [ model.currentUnitsProperty ], current => { + return model.getFixedCurrent(); + } ); } /** diff --git a/js/ohms-law/view/WireBox.js b/js/ohms-law/view/WireBox.js index a6a6d55..4b33e86 100644 --- a/js/ohms-law/view/WireBox.js +++ b/js/ohms-law/view/WireBox.js @@ -6,23 +6,17 @@ * @author Anton Ulyanov (Mlearner) */ -import Multilink from '../../../../axon/js/Multilink.js'; -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, Rectangle } 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 OhmsLawConstants from '../OhmsLawConstants.js'; import BatteriesView from './BatteriesView.js'; import ReadoutPanel from './ReadoutPanel.js'; import ResistorNode from './ResistorNode.js'; import RightAngleArrow from './RightAngleArrow.js'; - -const circuitLabelString = OhmsLawA11yStrings.circuitLabel.value; -const circuitDescriptionString = OhmsLawA11yStrings.circuitDescription.value; -const currentDescriptionPatternString = OhmsLawA11yStrings.currentDescriptionPattern.value; +import WireBoxDescriber from './WireBoxDescriber.js'; // constants const WIDTH = OhmsLawConstants.WIRE_WIDTH; @@ -46,8 +40,8 @@ class WireBox extends Node { // pdom tagName: 'ul', labelTagName: 'h3', - labelContent: circuitLabelString, - descriptionContent: circuitDescriptionString + labelContent: OhmsLawFluentMessages.circuitLabelMessageProperty, + descriptionContent: OhmsLawFluentMessages.circuitDescriptionMessageProperty }, options ); super( options ); @@ -103,61 +97,20 @@ class WireBox extends Node { } ); this.addChild( currentReadoutPanel ); - model.voltageProperty.set( OhmsLawConstants.VOLTAGE_RANGE.min ); - model.resistanceProperty.set( OhmsLawConstants.RESISTANCE_RANGE.max ); - - // @private - this is the min height of the arrows for this sim - this.minArrowHeight = this.bottomLeftArrow.height; + const wireBoxDescriber = new WireBoxDescriber( model, this.bottomLeftArrow ); - // reset the model after using to get height of arrows - model.reset(); - - // pdom - when the current changes, update the accessible description - Multilink.multilink( [ model.currentProperty, model.currentUnitsProperty ], () => { - accessibleCurrentNode.innerContent = StringUtils.fillIn( currentDescriptionPatternString, { - arrowSize: this.getArrowSizeDescription(), - value: model.getFixedCurrent(), - unit: ohmsLawDescriber.getUnitForCurrent() - } ); - } ); + accessibleCurrentNode.innerContent = new PatternMessageProperty( + OhmsLawFluentMessages.currentDescriptionPatternMessageProperty, + { + arrowSize: wireBoxDescriber.arrowSizeDescriptionProperty, + value: ohmsLawDescriber.formattedCurrentProperty, + unit: model.currentUnitsProperty + } + ); // pdom - the order of descriptions should be batteries, resistance, then current this.pdomOrder = [ batteriesView, resistorNode, accessibleCurrentNode ]; } - - - /** - * Get a description of the arrow size. Returns omething like "small" or "huge" or "medium size". - * @public - * - * @returns {string} - */ - getArrowSizeDescription() { - - const height = this.bottomLeftArrow.height; - - // Empirically determined, the idea is for the largest relative size string to map to when the 'I' in the formula - // goes off the screen (or at least close to that), see https://github.com/phetsims/ohms-law/issues/97. - const maxArrowHeightThresholdCoefficient = 2; - - // The max in the linear function, instead of the max height of the arrow, everything bigger will just be the - // largest relative size. - const maxArrowHeightThreshold = HEIGHT * maxArrowHeightThresholdCoefficient; - - // map the normalized height to one of the size descriptions - let index = Utils.roundSymmetric( Utils.linear( - this.minArrowHeight, maxArrowHeightThreshold, // a1 b1 - 0, OhmsLawConstants.RELATIVE_SIZE_STRINGS.length - 1, // a2 b2 - height ) ); // a3 - - // if beyond the threshold, clamp it back to the highest index - if ( height > maxArrowHeightThreshold ) { - index = OhmsLawConstants.RELATIVE_SIZE_STRINGS.length - 1; - } - assert && assert( index >= 0 && index < OhmsLawConstants.RELATIVE_SIZE_STRINGS.length, - 'mapping to relative size string incorrect' ); - return OhmsLawConstants.RELATIVE_SIZE_STRINGS[ index ].toLowerCase(); - } } ohmsLaw.register( 'WireBox', WireBox ); diff --git a/js/ohms-law/view/WireBoxDescriber.js b/js/ohms-law/view/WireBoxDescriber.js new file mode 100644 index 0000000..ce0aec6 --- /dev/null +++ b/js/ohms-law/view/WireBoxDescriber.js @@ -0,0 +1,88 @@ +// Copyright 2024, University of Colorado Boulder + +/** + * Describes the state of the circuit components in the wire box. + * + * @author Jesse Greenberg (PhET Interactive Simulations) + */ + +import DerivedProperty from '../../../../axon/js/DerivedProperty.js'; +import Utils from '../../../../dot/js/Utils.js'; +import Enumeration from '../../../../phet-core/js/Enumeration.js'; +import EnumerationValue from '../../../../phet-core/js/EnumerationValue.js'; +import ohmsLaw from '../../ohmsLaw.js'; +import OhmsLawConstants from '../OhmsLawConstants.js'; + +// enum for describing the relative sizes of letters +class SizeDescription extends EnumerationValue { + static TINY = new SizeDescription(); + static VERY_SMALL = new SizeDescription(); + static SMALL = new SizeDescription(); + static MEDIUM_SIZE = new SizeDescription(); + static LARGE = new SizeDescription(); + static VERY_LARGE = new SizeDescription(); + static HUGE = new SizeDescription(); + static enumeration = new Enumeration( SizeDescription ); +} + +export default class WireBoxDescriber { + constructor( model, arrowNode ) { + this.arrowNode = arrowNode; + + // Set the model to a state where the arrows will be tiny, so that we can + // keep that as a minimum height for future calculations. + model.voltageProperty.set( OhmsLawConstants.VOLTAGE_RANGE.min ); + model.resistanceProperty.set( OhmsLawConstants.RESISTANCE_RANGE.max ); + + // @private - this is the min height of the arrows for this sim + this.minArrowHeight = arrowNode.height; + + // reset the model after using to get height of arrows + model.reset(); + + this.arrowSizeDescriptionProperty = new DerivedProperty( [ model.voltageProperty, model.resistanceProperty ], + ( voltage, resistance ) => this.getArrowSizeDescription() + ); + } + + + /** + * Get a SizeDescription for the arrow. + * @public + * + * @returns {string} + */ + getArrowSizeDescription() { + + const height = this.arrowNode.height; + + // Empirically determined, the idea is for the largest relative size string to map to when the 'I' in the formula + // goes off the screen (or at least close to that), see https://github.com/phetsims/ohms-law/issues/97. + const maxArrowHeightThresholdCoefficient = 2; + + // The max in the linear function, instead of the max height of the arrow, everything bigger will just be the + // largest relative size. + const maxArrowHeightThreshold = OhmsLawConstants.WIRE_HEIGHT * maxArrowHeightThresholdCoefficient; + + const values = SizeDescription.enumeration.values; + + // map the normalized height to one of the size descriptions + let index = Utils.roundSymmetric( Utils.linear( + this.minArrowHeight, maxArrowHeightThreshold, // a1 b1 + 0, values.length - 1, // a2 b2 + height ) ); // a3 + + // if beyond the threshold, clamp it back to the highest index + if ( height > maxArrowHeightThreshold ) { + index = values.length - 1; + } + assert && assert( + index >= 0 && index < values.length, + 'mapping to relative size string incorrect' + ); + + return values[ index ]; + } +} + +ohmsLaw.register( 'WireBoxDescriber', WireBoxDescriber ); \ No newline at end of file diff --git a/ohms-law-strings_en.ftl b/ohms-law-strings_en.ftl index 60d9fda..d86c0a2 100644 --- a/ohms-law-strings_en.ftl +++ b/ohms-law-strings_en.ftl @@ -2,27 +2,29 @@ resistance-units-pattern = { $value } Ohms voltage-units-pattern = { $value } Volts resistance-slider-label = R, Resistance voltage-slider-label = V, Voltage -current-amps = amps -current-milliamps = milliamps choose-unit-for-current = Choose unit for current. +-amps = amps +-milliamps = milliamps + # Relative size strings -number-of-sizes = 6 -tiny = Tiny -very-small = Very small -small = Small -medium-size = Medium size -large = Large -very-large = Very large -huge = Huge -much-much-smaller-than = much much smaller than -much-smaller-than = much smaller than -slightly-smaller-than = slightly smaller than -comparable-to = comparable to -slightly-larger-than = slightly larger than -much-larger-than = much larger than -much-much-larger-than = much much larger than -relative-size-pattern = In equation, letter V is { $iComparison } letter I and { $rComparison } letter R. +relative-size-pattern = In equation, letter V is { $iComparison -> + [ MUCH_MUCH_SMALLER ] much much smaller than + [ MUCH_SMALLER ] much smaller than + [ SLIGHTLY_SMALLER ] slightly smaller than + [ COMPARABLE ] comparable to + [ SLIGHTLY_LARGER ] slightly larger than + [ MUCH_LARGER ] much larger than + *[ MUCH_MUCH_LARGER ] much much larger than +} letter I and { $rComparison -> + [ MUCH_MUCH_SMALLER ] much much smaller than + [ MUCH_SMALLER ] much smaller than + [ SLIGHTLY_SMALLER ] slightly smaller than + [ COMPARABLE ] comparable to + [ SLIGHTLY_LARGER ] slightly larger than + [ MUCH_LARGER ] much larger than + *[ MUCH_MUCH_LARGER ] much much larger than +} letter R. # Equation strings ohms-law-equation = Ohm's Law Equation @@ -36,7 +38,18 @@ circuit-description = A pair of wires connect a resistor to a series of batterie batteries-supply-pattern = batteries supply { $voltage } volts # Current strings -current-description-pattern = { $arrowSize } arrows indicate a current flowing clockwise at { $value } { $unit } +current-description-pattern = { $arrowSize -> + [TINY] Tiny + [VERY_SMALL] Very small + [SMALL] Small + [MEDIUM] Medium size + [LARGE] Large + [VERY_LARGE] Very large + *[HUGE] Huge +} arrows indicate a current flowing clockwise at { $value } { $unit -> + [AMPS] { -amps } + *[MILLIAMPS] { -milliamps } +} # Resistance strings resistance-dots-pattern = resistor shows a { $impurities -> @@ -59,8 +72,8 @@ right-now = Right now, voltage-summary-pattern = voltage, V, is { $value } volts resistance-summary-pattern = resistance, R, is { $value } ohms current-summary-pattern = current, I, is { $value } { $unit -> - [AMPS] amps - *[MILLIAMPS] milliamps + [AMPS] { -amps } + *[MILLIAMPS] { -milliamps } } # Slider strings