Skip to content

Commit

Permalink
Add NumeralAccordionBoxes and CompareAccordionBoxes to the compare sc…
Browse files Browse the repository at this point in the history
…reen, see #2
  • Loading branch information
chrisklus committed Nov 12, 2019
1 parent ebf7895 commit 8c07bcd
Show file tree
Hide file tree
Showing 7 changed files with 380 additions and 23 deletions.
1 change: 1 addition & 0 deletions js/common/NumberPlayConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ define( require => {
ORANGE_BACKGROUND: 'rgb( 255, 218, 176 )',
PURPLE_BACKGROUND: 'rgb( 254, 202, 255 )',
BLUE_BACKGROUND: 'rgb( 190, 232, 255 )',
WHITE_BACKGROUND: 'rgb( 255, 255, 255 )',
BUCKET_BASE_COLOR: 'rgb( 100, 101, 162 )',

// misc TODO: when base classes exist, move bucket specs there
Expand Down
10 changes: 8 additions & 2 deletions js/compare/CompareScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ define( require => {
const CompareScreenView = require( 'NUMBER_PLAY/compare/view/CompareScreenView' );
const Image = require( 'SCENERY/nodes/Image' );
const numberPlay = require( 'NUMBER_PLAY/numberPlay' );
const NumberPlayConstants = require( 'NUMBER_PLAY/common/NumberPlayConstants' );
const Property = require( 'AXON/Property' );
const Screen = require( 'JOIST/Screen' );
const Vector2 = require( 'DOT/Vector2' );

// strings
const screenCompareString = require( 'string!NUMBER_PLAY/screen.compare' );
Expand All @@ -31,13 +33,17 @@ define( require => {

const options = {
name: screenCompareString,
backgroundColorProperty: new Property( 'white' ),
backgroundColorProperty: new Property( NumberPlayConstants.WHITE_BACKGROUND ),
homeScreenIcon: new Image( compareScreenIconImage ),
tandem: tandem
};

super(
() => new CompareModel( tandem.createTandem( 'model' ) ),
() => new CompareModel(
NumberPlayConstants.TWENTY,
new Vector2( 16, 262 ), // empirically determined
1.3, // empirically determined
tandem.createTandem( 'model' ) ),
model => new CompareScreenView( model, tandem.createTandem( 'view' ) ),
options
);
Expand Down
47 changes: 37 additions & 10 deletions js/compare/model/CompareModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,59 @@ define( require => {
'use strict';

// modules
const BooleanProperty = require( 'AXON/BooleanProperty' );
const numberPlay = require( 'NUMBER_PLAY/numberPlay' );
const ComparePlayArea = require( 'NUMBER_PLAY/compare/model/ComparePlayArea' );
const NumberProperty = require( 'AXON/NumberProperty' );
const Range = require( 'DOT/Range' );

class CompareModel {
class CompareModel {

/**
* @param {number} highestCount - the highest integer number that can be counted to
* @param {Vector2} paperNumberOrigin - see OnesPlayArea for doc
* @param {number} objectMaxScale - see PlayObject for doc
* @param {Tandem} tandem
*/
constructor( tandem ) {
//TODO
constructor( highestCount, paperNumberOrigin, objectMaxScale, tandem ) {

// @public {NumberProperty}
this.leftCurrentNumberProperty = new NumberProperty( 0, {
range: new Range( 0, highestCount )
} );
this.rightCurrentNumberProperty = new NumberProperty( 0, {
range: new Range( 0, highestCount )
} );

// @public {BooleanProperty} - see NumberPlayModel for doc
this.isResettingProperty = new BooleanProperty( false );

// @public
this.leftPlayArea = new ComparePlayArea( this.leftCurrentNumberProperty, objectMaxScale, paperNumberOrigin, this.isResettingProperty );
this.rightPlayArea = new ComparePlayArea( this.rightCurrentNumberProperty, objectMaxScale, paperNumberOrigin, this.isResettingProperty );
}

/**
* Resets the model.
* Steps the model.
* @param {number} dt - time step, in seconds
* @public
*/
reset() {
//TODO
step( dt ) {
this.leftPlayArea.step( dt );
this.rightPlayArea.step( dt );
}

/**
* Steps the model.
* @param {number} dt - time step, in seconds
* Resets the model.
* @public
*/
step( dt ) {
//TODO
reset() {
this.isResettingProperty.value = true;
this.leftPlayArea.reset();
this.rightPlayArea.reset();
this.leftCurrentNumberProperty.reset();
this.rightCurrentNumberProperty.reset();
this.isResettingProperty.reset();
}
}

Expand Down
72 changes: 72 additions & 0 deletions js/compare/model/ComparePlayArea.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2019, University of Colorado Boulder

/**
* Model class for a ComparePlayArea, which combines a OnesPlayArea and an ObjectPlayArea.
*
* @author Chris Klusendorf (PhET Interactive Simulations)
*/
define( require => {
'use strict';

// modules
const EnumerationProperty = require( 'AXON/EnumerationProperty' );
const numberPlay = require( 'NUMBER_PLAY/numberPlay' );
const ObjectsPlayArea = require( 'NUMBER_PLAY/common/model/ObjectsPlayArea' );
const OnesPlayArea = require( 'NUMBER_PLAY/common/model/OnesPlayArea' );
const ComparePlayObjectType = require( 'NUMBER_PLAY/compare/model/ComparePlayObjectType' );

class ComparePlayArea {

/**
* @param {NumberProperty} currentNumberProperty
* @param {number} objectMaxScale - see PlayObject for doc
* @param {Vector2} paperNumberOrigin - see OnesPlayArea for doc
* @param {BooleanProperty} isResetting
*/
constructor( currentNumberProperty, objectMaxScale, paperNumberOrigin, isResettingProperty ) {

// @public {EnumerationProperty.<ComparePlayObjectType>} - the current type of playObject being displayed
this.playObjectTypeProperty = new EnumerationProperty( ComparePlayObjectType, ComparePlayObjectType.DOG );

// since one value of ComparePlayObjectType is not valid in ObjectsPlayArea, this is a separate Property
// to prevent that value from passing through to ObjectsPlayArea. see the link below for usage.
const playObjectTypeProperty = new EnumerationProperty( ComparePlayObjectType, ComparePlayObjectType.DOG );

// @public (read-only) - the model for managing paper ones in the playArea
this.onesPlayArea = new OnesPlayArea( currentNumberProperty, paperNumberOrigin, isResettingProperty );

// @public (read-only) - the model for managing objects in the playArea
this.objectsPlayArea = new ObjectsPlayArea( currentNumberProperty, objectMaxScale, isResettingProperty, {
playObjectTypeProperty: playObjectTypeProperty
} );

// if the value of the current play object type is a paper one, don't send update the Property that was passed to
// ObjectsPlayArea, as it does not handle paper ones. instead, see how this same link is used in
// CompareAccordionBox to hide ObjectsPlayArea and show the OnesPlayArea for this case.
this.playObjectTypeProperty.link( type => {
if ( type !== ComparePlayObjectType.PAPER_ONE ) {
playObjectTypeProperty.value = type;
}
} );
}

/**
* @param {number} dt - time step, in seconds
* @public
*/
step( dt ) {
this.onesPlayArea.step( dt );
}

/**
* @public
*/
reset() {
this.onesPlayArea.reset();
this.objectsPlayArea.reset();
this.playObjectTypeProperty.reset();
}
}

return numberPlay.register( 'ComparePlayArea', ComparePlayArea );
} );
20 changes: 20 additions & 0 deletions js/compare/model/ComparePlayObjectType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2019, University of Colorado Boulder

/**
* Play object types specific to the `Compare` screen.
*
* @author Chris Klusendorf
*/
define( require => {
'use strict';

// modules
const Enumeration = require( 'PHET_CORE/Enumeration' );
const numberPlay = require( 'NUMBER_PLAY/numberPlay' );
const PlayObjectType = require( 'NUMBER_PLAY/common/model/PlayObjectType' );

// @public
const ComparePlayObjectType = new Enumeration( [ PlayObjectType.DOG.name, PlayObjectType.APPLE.name, 'PAPER_ONE' ] );

return numberPlay.register( 'ComparePlayObjectType', ComparePlayObjectType );
} );
162 changes: 162 additions & 0 deletions js/compare/view/CompareAccordionBox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
// Copyright 2019, University of Colorado Boulder

/**
* Class for the `Objects` accordion box on the 'Compare' screen, which mixes the functionality of ObjectsAccordionBox
* and OnesAccordionBox
*
* TODO: Generalize the ObjectsAccordionBox and OnesAccordionBox so that they share code, which will remove the need
* to use both ObjectsPlayAreaNode and OnesPlayAreaNode.
*
* @author Chris Klusendorf (PhET Interactive Simulations)
*/
define( require => {
'use strict';

// modules
const AccordionBox = require( 'SUN/AccordionBox' );
const BaseNumber = require( 'MAKE_A_TEN/make-a-ten/common/model/BaseNumber' );
const BaseNumberNode = require( 'MAKE_A_TEN/make-a-ten/common/view/BaseNumberNode' );
const Bounds2 = require( 'DOT/Bounds2' );
const ComparePlayObjectType = require( 'NUMBER_PLAY/compare/model/ComparePlayObjectType' );
const Color = require( 'SCENERY/util/Color' );
const Dimension2 = require( 'DOT/Dimension2' );
const EnumerationProperty = require( 'AXON/EnumerationProperty' );
const merge = require( 'PHET_CORE/merge' );
const ModelViewTransform2 = require( 'PHETCOMMON/view/ModelViewTransform2' );
const numberPlay = require( 'NUMBER_PLAY/numberPlay' );
const NumberPlayConstants = require( 'NUMBER_PLAY/common/NumberPlayConstants' );
const ObjectsPlayAreaNode = require( 'NUMBER_PLAY/common/view/ObjectsPlayAreaNode' );
const OnesPlayAreaNode = require( 'NUMBER_PLAY/common/view/OnesPlayAreaNode' );
const PlayObject = require( 'NUMBER_PLAY/common/model/PlayObject' );
const PlayObjectNode = require( 'NUMBER_PLAY/common/view/PlayObjectNode' );
const RadioButtonGroup = require( 'SUN/buttons/RadioButtonGroup' );
const Rectangle = require( 'SCENERY/nodes/Rectangle' );
const Text = require( 'SCENERY/nodes/Text' );
const Vector2 = require( 'DOT/Vector2' );

// constants
const WIDTH = 394; // the width of this AccordionBox, in screen coordinates. from the screen's design asset.

// strings
const objectsString = require( 'string!NUMBER_PLAY/objects' );

class CompareAccordionBox extends AccordionBox {

/**
* @param {ComparePlayArea} playArea
* @param {number} height - the height of this accordion box
* @param {Object} [options]
*/
constructor( playArea, height, options ) {

options = merge( {
titleNode: new Text( objectsString, { font: NumberPlayConstants.ACCORDION_BOX_TITLE_FONT } ),
fill: NumberPlayConstants.BLUE_BACKGROUND,
minWidth: WIDTH,
maxWidth: WIDTH,

contentWidth: 350, // {number}
radioButtonSize: new Dimension2( 28, 28 ), // {Dimension2}
radioButtonSpacing: 10 // {number}
}, NumberPlayConstants.ACCORDION_BOX_OPTIONS, options );

const contentNode = new Rectangle( {
rectHeight: height,
rectWidth: options.contentWidth
} );

// create view bounds for the ObjectsPlayAreaNode
const playAreaMarginY = 15;
const objectsPlayAreaViewBounds = new Bounds2(
contentNode.left,
contentNode.top + playAreaMarginY,
contentNode.right,
contentNode.bottom - playAreaMarginY
);
const translateMVT = ModelViewTransform2.createSinglePointScaleInvertedYMapping(
Vector2.ZERO,
new Vector2( objectsPlayAreaViewBounds.left + NumberPlayConstants.BUCKET_SIZE.width / 2, objectsPlayAreaViewBounds.bottom ),
1
);
const playAreaModelBounds = translateMVT.viewToModelBounds( objectsPlayAreaViewBounds ).dilatedX( -20 ).dilatedY( -19 );

// create and add the ObjectsPlayAreaNode
const objectsPlayAreaNode = new ObjectsPlayAreaNode(
playArea.objectsPlayArea,
playAreaModelBounds,
translateMVT
);
contentNode.addChild( objectsPlayAreaNode );

// create view bounds for the OnesPlayAreaNode
const onesPlayAreaViewBounds = new Bounds2(
contentNode.left,
contentNode.top,
contentNode.right,
contentNode.bottom - playAreaMarginY
);

// create and add the OnesPlayAreaNode
const onesPlayAreaNode = new OnesPlayAreaNode(
playArea.onesPlayArea,
onesPlayAreaViewBounds,
translateMVT
);
contentNode.addChild( onesPlayAreaNode );

// create the icons for the RadioButtonGroup
const buttons = [];
ComparePlayObjectType.VALUES.forEach( playObjectType => {
let iconNode = null;
if ( playObjectType === ComparePlayObjectType.PAPER_ONE ) {
iconNode = new BaseNumberNode( new BaseNumber( 1, 0 ), 1 );
iconNode.setScaleMagnitude( options.radioButtonSize.height / iconNode.height / 4 );
}
else {
iconNode = new PlayObjectNode(
new PlayObject(
new EnumerationProperty( ComparePlayObjectType, playObjectType ),
new Vector2( 0, 0 ),
options.radioButtonSize,
1
),
playAreaModelBounds,
translateMVT
);
}

buttons.push( {
value: playObjectType,
node: iconNode
} );
} );

// create and add the RadioButtonGroup, which is a control for changing the ComparePlayObjectType of this play area
const radioButtonGroup = new RadioButtonGroup( playArea.playObjectTypeProperty, buttons, {
baseColor: Color.WHITE,
orientation: 'horizontal',
spacing: options.radioButtonSpacing
} );
radioButtonGroup.right = objectsPlayAreaViewBounds.right - 2; // empirically determined tweak
radioButtonGroup.bottom = objectsPlayAreaViewBounds.bottom;
contentNode.addChild( radioButtonGroup );

// since (for now) there are two underlying play areas in place of one, hide and show whichever is appropriate
// based on the value of playObjectTypeProperty
playArea.playObjectTypeProperty.link( type => {
if ( type === ComparePlayObjectType.PAPER_ONE ) {
objectsPlayAreaNode.visible = false;
onesPlayAreaNode.visible = true;
}
else {
onesPlayAreaNode.visible = false;
objectsPlayAreaNode.visible = true;
}
} );

super( contentNode, options );
}
}

return numberPlay.register( 'CompareAccordionBox', CompareAccordionBox );
} );
Loading

0 comments on commit 8c07bcd

Please sign in to comment.