diff --git a/js/gravity-force-lab/GravityForceLabA11yStrings.js b/js/gravity-force-lab/GravityForceLabA11yStrings.js index 20603fc8..d2aba5cc 100644 --- a/js/gravity-force-lab/GravityForceLabA11yStrings.js +++ b/js/gravity-force-lab/GravityForceLabA11yStrings.js @@ -16,7 +16,7 @@ define( require => { // Screen Summary Strings screenSummaryMainDescription: { - value: 'The Play Area has a blue sphere labelled m1 and a red sphere labelled m2. A force vector arrow starts at the center of each sphere and points directly at the opposite sphere. Spheres can be moved closer or further from one another The mass of each sphere can be increased or decreased. Each sphere is held in place by a robot.' + value: 'The Play Area has a blue sphere labelled m1 and a red sphere labelled m2. A force vector arrow starts at the center of each sphere and points directly at the opposite sphere. Spheres can be moved closer or further from one another. The mass of each sphere can be increased or decreased. Each sphere is held in place by a robot.' }, screenSummarySecondaryDescription: { value: 'In the Control Area, checkboxes change what things are shown and how they behave, and a button resets the sim. There is a moveable ruler to take measurements, if needed.' @@ -73,6 +73,12 @@ define( require => { muchMuchLargerThan: { value: 'much much larger than' }, + getsSmaller: { + value: 'gets smaller' + }, + getsBigger: { + value: 'gets bigger' + }, // mass sphere density notAtAllDense: { diff --git a/js/gravity-force-lab/view/GravityForceLabAlertManager.js b/js/gravity-force-lab/view/GravityForceLabAlertManager.js index d05841d2..79146062 100644 --- a/js/gravity-force-lab/view/GravityForceLabAlertManager.js +++ b/js/gravity-force-lab/view/GravityForceLabAlertManager.js @@ -6,14 +6,14 @@ define( require => { // modules const gravityForceLab = require( 'GRAVITY_FORCE_LAB/gravityForceLab' ); const GravityForceLabA11yStrings = require( 'GRAVITY_FORCE_LAB/gravity-force-lab/GravityForceLabA11yStrings' ); - // const ISLCObjectEnum = require( 'INVERSE_SQUARE_LAW_COMMON/view/ISLCObjectEnum' ); + const ISLCObjectEnum = require( 'INVERSE_SQUARE_LAW_COMMON/view/ISLCObjectEnum' ); const ISLCA11yStrings = require( 'INVERSE_SQUARE_LAW_COMMON/ISLCA11yStrings' ); const ISLCAlertManager = require( 'INVERSE_SQUARE_LAW_COMMON/view/ISLCAlertManager' ); const Utterance = require( 'SCENERY_PHET/accessibility/Utterance' ); const utteranceQueue = require( 'SCENERY_PHET/accessibility/utteranceQueue' ); // constants - // const { OBJECT_ONE } = ISLCObjectEnum; + const { OBJECT_ONE, OBJECT_TWO } = ISLCObjectEnum; // strings const forcesInScientificNotationString = ISLCA11yStrings.forcesInScientificNotation.value; @@ -47,12 +47,12 @@ define( require => { model.object1.valueProperty.lazyLink( ( value, oldValue ) => { utteranceQueue.clear(); - this.alertMassValueChanged( value, oldValue ); + this.alertMassValueChanged( OBJECT_ONE, value, oldValue ); } ); model.object2.valueProperty.lazyLink( ( value, oldValue ) => { utteranceQueue.clear(); - this.alertMassValueChanged( value, oldValue ); + this.alertMassValueChanged( OBJECT_TWO, value, oldValue ); } ); } @@ -73,8 +73,8 @@ define( require => { utteranceQueue.addToBack( alert ); } - alertMassValueChanged( value, oldValue ) { - const alert = this.stringManager.getMassValueChangedAlertText( value, oldValue ); + alertMassValueChanged( objectEnum, value, oldValue ) { + const alert = this.stringManager.getMassValueChangedAlertText( objectEnum, value, oldValue ); const utterance = new Utterance( { alert, uniqueGroupId: 'massChanged' } ); utteranceQueue.addToBack( utterance ); } diff --git a/js/gravity-force-lab/view/GravityForceLabStringManager.js b/js/gravity-force-lab/view/GravityForceLabStringManager.js index c3cb1cd1..ef93b2b9 100644 --- a/js/gravity-force-lab/view/GravityForceLabStringManager.js +++ b/js/gravity-force-lab/view/GravityForceLabStringManager.js @@ -31,6 +31,8 @@ define( require => { const valueUnitsPatternString = GravityForceLabA11yStrings.valueUnitstPattern.value; const positionMeterPatternString = GravityForceLabA11yStrings.positionMeterPattern.value; + const getsBiggerString = GravityForceLabA11yStrings.getsBigger.value; + const getsSmallerString = GravityForceLabA11yStrings.getsSmaller.value; const muchMuchSmallerThanString = GravityForceLabA11yStrings.muchMuchSmallerThan.value; const muchSmallerThanString = GravityForceLabA11yStrings.muchSmallerThan.value; const slightlySmallerThanString = GravityForceLabA11yStrings.slightlySmallerThan.value; @@ -44,9 +46,7 @@ define( require => { // constants const MICRO_CONVERSION_FACTOR = 1e6; - const { OBJECT_ONE } = ISLCObjectEnum; - // const exponentToIndex = new LinearFunction( -1, 1, 0, 6 ); - // const massDifferenceToIndex = new LinearFunction( -500, 500, 0, 6, true ); + const { OBJECT_ONE, OBJECT_TWO } = ISLCObjectEnum; const radiusDifferenceToIndex = new LinearFunction( -0.6, 0.6, 0, 6, true ); const { min, max } = GravityForceLabConstants.PULL_FORCE_RANGE; const forceToPullIndex = new LinearFunction( min, max, 6, 0, true ); @@ -54,6 +54,14 @@ define( require => { class GravityForceLabStringManager extends ISLCStringManager { constructor( model, object1Label, object2Label, options ) { + // TODO: + // - forceValueToString function should be for additional language (e.g. 300 'billion') + // - default: forceValue => StringUtils.fillIn( '{{forceValue}}', { forceValue } ); + // - convertForce is used if there is a unit change for any reason + // - default: force => force + // - formatPosition: likely the same as convertForce + // - valueUnits and distanceUnits will be protected and mutable by subtypes + const forceValueToString = forceValue => { let units; let value; @@ -88,6 +96,7 @@ define( require => { this._radiusDifference = 0; this._object1MassGrowing = false; this._object2MassGrowing = false; + this._pushedMassEnum = null; this.formatMassValue = options.formatMassValue; this.centerOffset = options.centerOffset; this.formatPositionUnitMark = options.formatPositionUnitMark; @@ -99,20 +108,13 @@ define( require => { } ); - Property.multilink( - [ model.object1.valueProperty, model.object2.valueProperty ], - ( m1, m2 ) => { - /* - * TS noted in the design doc about using 'steps' instead of ratios - * this implies that I should take the actual difference between the two - * values - */ - // this._object1ToObject2Ratio = r1 / r2; - // this._object2ToObject1Ratio = 1 / this._object1ToObject2Ratio; - // if r2 is larger than r1 then the value will be negative - this._objectMassDifference = m1 - m2; - } - ); + model.object1.radiusProperty.link( radius => { + this._pushedMassEnum = this.getPushedObjectEnum( OBJECT_ONE ); + } ); + + model.object2.radiusProperty.link( radius => { + this._pushedMassEnum = this.getPushedObjectEnum( OBJECT_TWO ); + } ); model.object1.valueProperty.link( ( newMass, oldMass ) => { this._object1MassGrowing = ( newMass - oldMass ) > 0; @@ -175,29 +177,49 @@ define( require => { return StringUtils.fillIn( pattern, { massValue, size, relativeSize, otherObject } ); } - // getSpherePositionAriaValueText( newPosition, objectNode ) { - // newPosition = this.convertDistanceMetric( newPosition + this.centerOffset ); - // return super.getSpherePositionAriaValueText( newPosition, objectNode ); - // } - getSpherePositionAndRegionText( position, objectEnum ) { position = this.convertDistanceMetric( position + this.centerOffset ); return super.getSpherePositionAndRegionText( position, objectEnum ); } - getMassValueChangedAlertText( newMass, oldMass ) { - let pattern = 'As mass {{massChange}}, vectors {{vectorChange}}.'; - const objectIsGrowing = ( newMass - oldMass ) > 0; - const massChange = objectIsGrowing ? 'gets bigger' : 'gets smaller'; - const vectorChange = objectIsGrowing ? 'get bigger' : 'get smaller'; + getMassValueChangedAlertText( objectEnum, newMass, oldMass ) { + let massClausePattern = 'As mass {{massChange}}'; + const massChange = newMass > oldMass ? getsBiggerString : getsSmallerString; + const vectorChange = ISLCStringManager.getVectorChangeDirection( newMass > oldMass ); + const massFillObject = { massChange }; + + const vectorClausePattern = 'vectors {{vectorChange}}'; + + const forcesClausePattern = 'forces now {{forceValue}}'; + + let alertPattern = '{{massClause}}, {{vectorClause}}.'; + + if ( this._pushedMassEnum !== null ) { + // something was pushed + massFillObject.direction = this._pushedMassEnum === OBJECT_ONE ? 'left' : 'right'; - const fillObject = { massChange, vectorChange }; + if ( this._pushedMassEnum === objectEnum ) { + // this mass moved + massClausePattern = 'As mass {{massChange}} and moves {{direction}}'; + } + else { + // other mass moved + massClausePattern = 'As mass {{massChange}} and moves {{otherObjectLabel}} {{direction}}'; + massFillObject.otherObjectLabel = this.getOtherObjectLabel( objectEnum ); + } + } + + const massClause = StringUtils.fillIn( massClausePattern, massFillObject ); + const vectorClause = StringUtils.fillIn( vectorClausePattern, { vectorChange } ); + const alertFillObject = { massClause, vectorClause }; if ( this.model.forceValuesProperty.get() ) { - pattern = 'As mass {{massChange}}, vectors {{vectorChange}}, forces now {{forceValue}}'; - fillObject.forceValue = this.getForceValueText(); + alertPattern = '{{massClause}}, {{vectorClause}}, {{forceClause}}.'; + const forceValue = this.getForceValueText(); + alertFillObject.forceClause = StringUtils.fillIn( forcesClausePattern, { forceValue } ); } - return StringUtils.fillIn( pattern, fillObject ); + + return StringUtils.fillIn( alertPattern, alertFillObject ); } getSizeOfMass( massValue ) { @@ -222,6 +244,32 @@ define( require => { return Util.roundSymmetric( radiusDifferenceToIndex( difference ) ); } + getPushedObjectEnum( changingObjectEnum ) { + const { otherObject } = this.getObjectsFromEnum( changingObjectEnum ); + const otherBoundary = changingObjectEnum === OBJECT_ONE ? this.model.rightObjectBoundary : this.model.leftObjectBoundary; + const otherAtEdge = otherObject.positionProperty.get() === otherBoundary; + const pushed = this.model.getSumRadiusWithSeparation() > this._distanceBetween; + if ( pushed && otherAtEdge ) { + return changingObjectEnum; + } + else if ( pushed && !otherAtEdge ) { + return changingObjectEnum === OBJECT_ONE ? OBJECT_TWO : OBJECT_ONE; + } + else { + // no pushing + return null; + } + } + + // massWasPushed( objectEnum ) { + // const pushedMassEnum = this.getPushedObjectEnum( ) + // // const { thisObject } = this.getObjectsFromEnum( objectEnum ); + // // const boundary = objectEnum === OBJECT_ONE ? this.model.leftObjectBoundary : this.model.rightObjectBoundary; + // // const atEdge = thisObject.positionProperty.get() === boundary; + // // const pushed = this.model.getSumRadiusWithSeparation() > this._distanceBetween; + // // return ( !atEdge ) && pushed; + // } + getMassSizeIndex( mass ) { assert && assert( ( typeof mass ) === 'number' ); if ( mass < 26 ) {