Skip to content

Commit

Permalink
more working on converting the view, #404
Browse files Browse the repository at this point in the history
  • Loading branch information
zepumph committed Oct 21, 2021
1 parent 210a56a commit 04ad335
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 41 deletions.
56 changes: 45 additions & 11 deletions js/common/view/BothHandsInteractionListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,42 @@ import ratioAndProportion from '../../ratioAndProportion.js';
import RAPRatioTuple from '../model/RAPRatioTuple.js';
import RatioTerm from '../model/RatioTerm.js';
import rapConstants from '../rapConstants.js';
import getKeyboardInputSnappingMapper from './getKeyboardInputSnappingMapper.js';
import getKeyboardInputSnappingMapper, { KeyboardInputMapper } from './getKeyboardInputSnappingMapper.js';
import Node from '../../../../scenery/js/nodes/Node.js';
import Property from '../../../../axon/js/Property.js';
import Range from '../../../../dot/js/Range.js';
import BoundarySoundClip from './sound/BoundarySoundClip.js';
import TickMarkBumpSoundClip from './sound/TickMarkBumpSoundClip.js';
import SceneryEvent from '../../../../scenery/js/input/SceneryEvent.js';

const TOTAL_RANGE = rapConstants.TOTAL_RATIO_TERM_VALUE_RANGE;

class BothHandsInteractionListener {

private targetNode: Node;
private antecedentInteractedWithProperty: BooleanProperty;
private consequentInteractedWithProperty: BooleanProperty;
private enabledRatioTermsRangeProperty: Property<Range>;
private tickMarkRangeProperty: Property<number>;
private ratioTupleProperty: Property<RAPRatioTuple>;
private keyboardStep: number;
private shiftKeyboardStep: number;
private boundarySoundClip: BoundarySoundClip;
private tickMarkBumpSoundClip: TickMarkBumpSoundClip;
private ratioLockedProperty: Property<boolean>;
private targetRatioProperty: Property<number>;
private inProportionProperty: Property<boolean>;
private onInput: ( knockOutOfLock?: boolean ) => void;
private antecedentMapKeyboardInput: KeyboardInputMapper;
private consequentMapKeyboardInput: KeyboardInputMapper;
private isBeingInteractedWithProperty: Property<boolean>;
private jumpToZeroWhileLockedEmitter: Emitter<[]>;
private playBoundarySoundOnKeyup: boolean;

/**
* @param {Object} config
*/
constructor( config ) {
constructor( config: any ) {

config = merge( {

Expand Down Expand Up @@ -126,16 +152,16 @@ class BothHandsInteractionListener {
* @param {boolean} increment - if the value is being incremented, as opposed to decremented.
* @private
*/
onValueIncrementDecrement( tupleField, inputMapper, increment ) {
onValueIncrementDecrement( tupleField: 'antecedent' | 'consequent', inputMapper: KeyboardInputMapper, increment: boolean ) {
this.isBeingInteractedWithProperty.value = true;
const currentTuple = this.ratioTupleProperty.value[ tupleField ];
const currentValueFromTuple = this.ratioTupleProperty.value[ tupleField ];

const changeAmount = globalKeyStateTracker.shiftKeyDown ? this.shiftKeyboardStep : this.keyboardStep;
const valueDelta = changeAmount * ( increment ? 1 : -1 );

// Because this interaction uses the keyboard, snap to the keyboard step to handle the case where the hands were
// previously moved via mouse/touch. See https://github.com/phetsims/ratio-and-proportion/issues/156
const newValue = inputMapper( currentTuple + valueDelta, currentTuple, globalKeyStateTracker.shiftKeyDown ? this.shiftKeyboardStep : this.keyboardStep, this.inProportionProperty.value );
const newValue = inputMapper( currentValueFromTuple + valueDelta, currentValueFromTuple, globalKeyStateTracker.shiftKeyDown, this.inProportionProperty.value );
const newRatioTuple = tupleField === 'antecedent' ? this.ratioTupleProperty.value.withAntecedent( newValue ) : this.ratioTupleProperty.value.withConsequent( newValue );

this.ratioTupleProperty.value = newRatioTuple.constrainFields( this.enabledRatioTermsRangeProperty.value );
Expand All @@ -156,15 +182,16 @@ class BothHandsInteractionListener {
* @public
* @param {SceneryEvent} sceneryEvent
*/
keydown( sceneryEvent ) {
keydown( sceneryEvent: SceneryEvent ) {

if ( sceneryEvent.target === this.targetNode ) {

// signify that this listener is reserved for keyboard movement so that other listeners can change
// their behavior during scenery event dispatch
sceneryEvent.pointer.reserveForKeyboardDrag();

const domEvent = sceneryEvent.domEvent;
assert && assert( sceneryEvent.domEvent, 'dom event expected' );
const domEvent = sceneryEvent.domEvent as Event;
const key = KeyboardUtils.getEventCode( domEvent );

if ( key === KeyboardUtils.KEY_DOWN_ARROW ) {
Expand All @@ -188,8 +215,14 @@ class BothHandsInteractionListener {
// for number keys 0-9, jump both values to that tick mark number. This value changes based on the tickMarkRangeProperty
for ( let i = 0; i <= 9; i++ ) {
if ( KeyboardUtils.getNumberFromCode( domEvent ) === i &&

// @ts-ignore
!domEvent.getModifierState( 'Control' ) &&

// @ts-ignore
!domEvent.getModifierState( 'Shift' ) &&

// @ts-ignore
!domEvent.getModifierState( 'Alt' ) ) {

this.isBeingInteractedWithProperty.value = true;
Expand Down Expand Up @@ -246,11 +279,12 @@ class BothHandsInteractionListener {
* @public
* @param {SceneryEvent} sceneryEvent
*/
keyup( sceneryEvent ) {
keyup( sceneryEvent: SceneryEvent ) {

if ( sceneryEvent.target === this.targetNode ) {

const domEvent = sceneryEvent.domEvent;
assert && assert( sceneryEvent.domEvent, 'domEvent expected' );
const domEvent = sceneryEvent.domEvent as Event;

if ( KeyboardUtils.isAnyKeyEvent( domEvent, [ KeyboardUtils.KEY_DOWN_ARROW, KeyboardUtils.KEY_UP_ARROW ] ) ) {
this.handleBoundarySoundOnInput( this.ratioTupleProperty.value.consequent );
Expand All @@ -270,8 +304,8 @@ class BothHandsInteractionListener {
* Handle boundary sound output based on an input for this interaction
* @param {number} newValue
*/
handleBoundarySoundOnInput( newValue ) {
this.boundarySoundClip.onStartInteraction( newValue );
handleBoundarySoundOnInput( newValue: number ) {
this.boundarySoundClip.onStartInteraction();
this.boundarySoundClip.onInteract( newValue );
this.boundarySoundClip.onEndInteraction( newValue );
}
Expand Down
2 changes: 1 addition & 1 deletion js/common/view/RAPScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class RAPScreenView extends ScreenView {
* @param {Tandem} tandem
* @param {Object} [options]
*/
constructor( model: RAPModel, tandem: Tandem, options: any ) {
constructor( model: RAPModel, tandem: Tandem, options?: any ) {

options = merge( {
tandem: tandem,
Expand Down
16 changes: 11 additions & 5 deletions js/common/view/getKeyboardInputSnappingMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,24 @@ import Utils from '../../../../dot/js/Utils.js';
import ratioAndProportion from '../../ratioAndProportion.js';
import rapConstants from '../rapConstants.js';

type KeyboardInputMapper = {
( newValue: number, oldVaue: number, useShiftKeyStep: boolean, alreadyInProportion: boolean ): number,
reset: () => void
}


/**
* @param {function():number} getIdealValue - get the ideal target value
* @param {number} keyboardStep
* @param {number} shiftKeyboardStep
* @returns {function(newValue: number, oldValue:number, useShiftKeyStep:boolean, alreadyInProportion:boolean):number} - returns a function that returns the snap/conserved value
* @returns {KeyboardInputMapper} - returns a function that returns the snap/conserved value
*/
function getKeyboardInputSnappingMapper( getIdealValue, keyboardStep, shiftKeyboardStep ) {
function getKeyboardInputSnappingMapper( getIdealValue: () => number, keyboardStep: number, shiftKeyboardStep: number ) {

// keep track of the remainder for next input post-process
let remainder = 0;

const snappingFunction = ( newValue, oldValue, useShiftKeyStep, alreadyInProportion ) => {
const snappingFunction: KeyboardInputMapper = ( newValue, oldValue, useShiftKeyStep, alreadyInProportion ) => {
// Don't conserve the snap for page up/down or home/end keys, just basic movement changes.
const applyConservationSnap = rapConstants.toFixed( Math.abs( newValue - oldValue ) ) <= shiftKeyboardStep && // eslint-disable-line bad-sim-text
newValue > rapConstants.NO_SUCCESS_VALUE_THRESHOLD &&
Expand All @@ -36,8 +42,7 @@ function getKeyboardInputSnappingMapper( getIdealValue, keyboardStep, shiftKeybo
if ( remainder === 0 ) {
const snapToKeyboardStep = useShiftKeyStep ? shiftKeyboardStep : keyboardStep;
newValue = rapConstants.toFixed( // eslint-disable-line bad-sim-text
Utils.roundSymmetric( newValue / snapToKeyboardStep ) * snapToKeyboardStep,
Utils.numberOfDecimalPlaces( snapToKeyboardStep ) );
Utils.roundSymmetric( newValue / snapToKeyboardStep ) * snapToKeyboardStep );
}

// If we are in the case where we want to potentially snap to the value that would yield the in-proportion state.
Expand Down Expand Up @@ -71,4 +76,5 @@ function getKeyboardInputSnappingMapper( getIdealValue, keyboardStep, shiftKeybo
}

ratioAndProportion.register( 'getKeyboardInputSnappingMapper', getKeyboardInputSnappingMapper );
export { KeyboardInputMapper };
export default getKeyboardInputSnappingMapper;
6 changes: 3 additions & 3 deletions js/common/view/sound/BoundarySoundClip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class BoundarySoundClip extends SoundClip {
* @param {Range} verticalRange - the total range that the vertical position can take
* @param {Object} [options]
*/
constructor( verticalRange: Range, options: any ) {
constructor( verticalRange: Range, options?: any ) {
super( boundarySound, options );

// @private
Expand All @@ -47,15 +47,15 @@ class BoundarySoundClip extends SoundClip {
* @param {number} [horizontalPosition]
* @param {Range} [horizontalRange] - the horizontal range can change based on view scaling
*/
onInteract( verticalPosition: number, horizontalPosition: number, horizontalRange: Range ) {
onInteract( verticalPosition: number, horizontalPosition?: number, horizontalRange?: Range ) {

if ( this.lastYPosition !== verticalPosition &&
( verticalPosition === this.verticalRange.min || verticalPosition === this.verticalRange.max ) ) {
this.play();
}
this.lastYPosition = verticalPosition;

if ( horizontalPosition ) {
if ( horizontalPosition && horizontalRange ) {

if ( this.lastXPosition !== horizontalPosition &&
( horizontalPosition === horizontalRange.min || horizontalPosition === horizontalRange.max ) ) {
Expand Down
2 changes: 1 addition & 1 deletion js/common/view/sound/InProportionSoundGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class InProportionSoundGenerator extends SoundClip {
* an on/off Property for the SoundGenerator, see below.
* @param {Object} [options]
*/
constructor( model: RAPModel, enabledControlProperty: Property<boolean>, options: any ) {
constructor( model: RAPModel, enabledControlProperty: Property<boolean>, options?: any ) {

options = merge( {
initialOutputLevel: 0.5
Expand Down
2 changes: 1 addition & 1 deletion js/common/view/sound/MovingInProportionSoundGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class MovingInProportionSoundGenerator extends SoundGenerator {
* @param {RAPModel} model
* @param {Object} [options]
*/
constructor( model: RAPModel, options: any ) {
constructor( model: RAPModel, options?: any ) {
options = merge( {
initialOutputLevel: 0.13
}, options );
Expand Down
9 changes: 7 additions & 2 deletions js/common/view/sound/StaccatoFrequencySoundGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import dotRandom from '../../../../../dot/js/dotRandom.js';
import Range from '../../../../../dot/js/Range.js';
import LinearFunction from '../../../../../dot/js/LinearFunction.js';
import merge from '../../../../../phet-core/js/merge.js';
import SoundClip from '../../../../../tambo/js/sound-generators/SoundClip.js';
Expand Down Expand Up @@ -51,12 +52,16 @@ const staccatoSounds = [
[ gSound, g001Sound, g002Sound ]
];

type LinearFunctionStub = ( x: number ) => number;

class StaccatoFrequencySoundGenerator extends SoundGenerator {


private inProportionProperty: Property<boolean>;
private fitnessProperty: Property<number>;
private staccatoSoundClips: SoundClip[][];
private timeLinearFunction: LinearFunctionStub;
private timeSinceLastPlay: number;

/**
* @param {Property.<number>} fitnessProperty
Expand Down Expand Up @@ -97,7 +102,7 @@ class StaccatoFrequencySoundGenerator extends SoundGenerator {
fitnessRange.max,
500,
120,
true );
true ) as LinearFunctionStub;

// @private - in ms, keep track of the amount of time that has passed since the last staccato sound played
this.timeSinceLastPlay = 0;
Expand All @@ -108,7 +113,7 @@ class StaccatoFrequencySoundGenerator extends SoundGenerator {
* @param {number} dt
* @public
*/
step( dt ) {
step( dt: number ) {
const newFitness = this.fitnessProperty.value;

// If fitness is less than zero, make sure enough time has past that it will play a sound immediately.
Expand Down
38 changes: 24 additions & 14 deletions js/common/view/sound/TickMarkBumpSoundClip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,26 @@
import SoundClip from '../../../../../tambo/js/sound-generators/SoundClip.js';
import tickMarkCrossBumpSound from '../../../../../tambo/sounds/general-soft-click_mp3.js';
import ratioAndProportion from '../../../ratioAndProportion.js';
import NumberProperty from '../../../../../axon/js/NumberProperty.js';
import Range from '../../../../../dot/js/Range.js';

// This value was copied from similar sound work done in Waves Intro
const MIN_INTER_CLICK_TIME = 33.3; // min time between clicking sounds, in milliseconds, empirically determined

class TickMarkBumpSoundClip extends SoundClip {

private tickMarkRangeProperty: NumberProperty;
private positionRange: Range;
private timeOfLastClick: number;
private lastValue: null | number;

/**
* @param {NumberProperty} tickMarkRangeProperty - serves as the divisor of the position range to yield position
* where bump sounds should occur.
* @param {Range} positionRange - the total range in position
* @param {Object} [options]
*/
constructor( tickMarkRangeProperty, positionRange, options ) {
constructor( tickMarkRangeProperty: NumberProperty, positionRange: Range, options?: any ) {
super( tickMarkCrossBumpSound, options );

// @private
Expand All @@ -38,24 +45,27 @@ class TickMarkBumpSoundClip extends SoundClip {
* Call this when an interaction occurs that could potentially cause a tick mark sound to play.
*
* @public
* @param currentValue
* @param {number} currentValue
*/
onInteract( currentValue ) {
onInteract( currentValue: number ) {

if ( this.lastValue !== null ) {

// handle the sound as desired for mouse/touch style input (for vertical changes)
for ( let i = 0; i < this.tickMarkRangeProperty.value; i++ ) {
const tickValue = ( i / this.positionRange.getLength() ) / this.tickMarkRangeProperty.value;
// handle the sound as desired for mouse/touch style input (for vertical changes)
for ( let i = 0; i < this.tickMarkRangeProperty.value; i++ ) {
const tickValue = ( i / this.positionRange.getLength() ) / this.tickMarkRangeProperty.value;

// Not at max or min, crossed a tick mark value
if ( currentValue !== this.positionRange.min && currentValue !== this.positionRange.max &&
this.lastValue < tickValue && currentValue >= tickValue || this.lastValue > tickValue && currentValue <= tickValue ) {
// Not at max or min, crossed a tick mark value
if ( currentValue !== this.positionRange.min && currentValue !== this.positionRange.max &&
this.lastValue < tickValue && currentValue >= tickValue || this.lastValue > tickValue && currentValue <= tickValue ) {

// if enough time has passed since the last change
if ( phet.joist.elapsedTime - this.timeOfLastClick >= MIN_INTER_CLICK_TIME ) {
this.play();
this.timeOfLastClick = phet.joist.elapsedTime;
// if enough time has passed since the last change
if ( phet.joist.elapsedTime - this.timeOfLastClick >= MIN_INTER_CLICK_TIME ) {
this.play();
this.timeOfLastClick = phet.joist.elapsedTime;
}
break;
}
break;
}
}

Expand Down
6 changes: 3 additions & 3 deletions js/common/view/sound/ViewSounds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class ViewSounds {

readonly grabSoundClip: SoundClip;
readonly releaseSoundClip: SoundClip;
readonly boundarySoundClip: SoundClip;
readonly tickMarkBumpSoundClip: SoundClip;
readonly boundarySoundClip: BoundarySoundClip;
readonly tickMarkBumpSoundClip: TickMarkBumpSoundClip;

/**
* @param {NumberProperty} tickMarkRangeProperty
Expand All @@ -39,7 +39,7 @@ class ViewSounds {
* @param {Object} [options]
*/
constructor( tickMarkRangeProperty: NumberProperty, tickMarkViewProperty: Property<TickMarkViewType>,
playTickMarkBumpSoundProperty: BooleanProperty, options: any ) {
playTickMarkBumpSoundProperty: BooleanProperty, options?: any ) {

options = merge( {
addSoundOptions: {
Expand Down

0 comments on commit 04ad335

Please sign in to comment.