Skip to content

Commit

Permalink
https://github.com/phetsims/graphing-quadratics/issues/178
Browse files Browse the repository at this point in the history
  • Loading branch information
pixelzoom committed Jun 7, 2023
1 parent 01b22d8 commit 7b8913a
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 122 deletions.
6 changes: 4 additions & 2 deletions js/common/view/GQScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,10 @@ export default class GQScreenView extends ScreenView {
this.addChild( pointToolsParent );

// Horizontally center controls in the space to the right of the graph.
controlsParent.centerX = graphNode.right + X_SPACING + ( controlPanelMaxWidth / 2 );
controlsParent.top = GQConstants.SCREEN_VIEW_Y_MARGIN;
controlsParent.boundsProperty.link( () => {
controlsParent.centerX = graphNode.right + X_SPACING + ( controlPanelMaxWidth / 2 );
controlsParent.top = GQConstants.SCREEN_VIEW_Y_MARGIN;
} );

// Reset All Button
const resetAllButton = new ResetAllButton( {
Expand Down
165 changes: 58 additions & 107 deletions js/explore/view/ExploreInteractiveEquationNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,19 @@
*/

import NumberProperty from '../../../../axon/js/NumberProperty.js';
import Bounds2 from '../../../../dot/js/Bounds2.js';
import optionize, { combineOptions, EmptySelfOptions } from '../../../../phet-core/js/optionize.js';
import PickRequired from '../../../../phet-core/js/types/PickRequired.js';
import StringUtils from '../../../../phetcommon/js/util/StringUtils.js';
import MathSymbols from '../../../../scenery-phet/js/MathSymbols.js';
import NumberDisplay, { NumberDisplayOptions } from '../../../../scenery-phet/js/NumberDisplay.js';
import { Node, NodeOptions, RichText, RichTextOptions } from '../../../../scenery/js/imports.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import GQColors from '../../common/GQColors.js';
import GQConstants from '../../common/GQConstants.js';
import GQSymbols from '../../common/GQSymbols.js';
import LinearSlider from '../../common/view/LinearSlider.js';
import QuadraticSlider from '../../common/view/QuadraticSlider.js';
import graphingQuadratics from '../../graphingQuadratics.js';
import Multilink from '../../../../axon/js/Multilink.js';

type SelfOptions = EmptySelfOptions;

Expand All @@ -45,9 +44,6 @@ export default class ExploreInteractiveEquationNode extends Node {
}
}, providedOptions );

// equation
const equationNode = new EquationNode( aProperty, bProperty, cProperty, options.tandem.createTandem( 'equationNode' ) );

// coefficient controls (labeled sliders)
const aSlider = new QuadraticSlider( GQSymbols.aMarkupStringProperty, aProperty, {
interval: GQConstants.EXPLORE_INTERVAL_A,
Expand All @@ -69,130 +65,85 @@ export default class ExploreInteractiveEquationNode extends Node {
phetioDocumentation: StringUtils.fillIn( GQConstants.SLIDER_DOC, { symbol: 'c' } )
} );

options.children = [ equationNode, aSlider, bSlider, cSlider ];

super( options );

// horizontally align sliders under their associated values in the equation
const ySpacing = 3;
aSlider.x = this.globalToLocalBounds( equationNode.aGlobalBounds ).centerX;
aSlider.top = equationNode.bottom + ySpacing;
bSlider.x = this.globalToLocalBounds( equationNode.bGlobalBounds ).centerX;
bSlider.top = equationNode.bottom + ySpacing;
cSlider.x = this.globalToLocalBounds( equationNode.cGlobalBounds ).centerX;
cSlider.top = equationNode.bottom + ySpacing;
}
}

/**
* The equation that appears above the sliders.
*/
class EquationNode extends Node {

private readonly aNode: Node;
private readonly bNode: Node;
private readonly cNode: Node;

public constructor( aProperty: NumberProperty, bProperty: NumberProperty, cProperty: NumberProperty, tandem: Tandem ) {

const options: NodeOptions = {
tandem: tandem,
phetioDocumentation: 'the equation that changes as the sliders are adjusted',
visiblePropertyOptions: {
phetioFeatured: true
}
};

// options for parts of the equation
const equationOptions: RichTextOptions = {
font: GQConstants.INTERACTIVE_EQUATION_FONT
};
const xyOptions = combineOptions<RichTextOptions>( {}, equationOptions, {
maxWidth: 20 // determined empirically
} );

// y
const yNode = new RichText( GQSymbols.yMarkupStringProperty, xyOptions );

// =
const equalsNode = new RichText( MathSymbols.EQUAL_TO, equationOptions );

// a value
const aNode = new NumberDisplay( aProperty, aProperty.range,
// NumberDisplays for a, b, c
const aNumberDisplay = new NumberDisplay( aProperty, aProperty.range,
combineOptions<NumberDisplayOptions>( {}, GQConstants.NUMBER_DISPLAY_OPTIONS, {
textOptions: {
fill: GQColors.EXPLORE_A
},
decimalPlaces: GQConstants.EXPLORE_DECIMALS_A
} ) );

// x^2
const xSquaredNode = new RichText( GQSymbols.xSquaredMarkupStringProperty, xyOptions );

// +
const plusNode = new RichText( MathSymbols.PLUS, equationOptions );

// b value
const bNode = new NumberDisplay( bProperty, bProperty.range,
const bNumberDisplay = new NumberDisplay( bProperty, bProperty.range,
combineOptions<NumberDisplayOptions>( {}, GQConstants.NUMBER_DISPLAY_OPTIONS, {
textOptions: {
fill: GQColors.EXPLORE_B
},
decimalPlaces: GQConstants.EXPLORE_DECIMALS_B
} ) );

// x
const xNode = new RichText( GQSymbols.xMarkupStringProperty, xyOptions );

// +
const anotherPlusNode = new RichText( MathSymbols.PLUS, equationOptions );

// c value
const cNode = new NumberDisplay( cProperty, bProperty.range,
const cNumberDisplay = new NumberDisplay( cProperty, bProperty.range,
combineOptions<NumberDisplayOptions>( {}, GQConstants.NUMBER_DISPLAY_OPTIONS, {
textOptions: {
fill: GQColors.EXPLORE_C
},
decimalPlaces: GQConstants.EXPLORE_DECIMALS_C
} ) );

// y = ax^2 + bx + c
options.children = [
yNode, equalsNode, aNode, xSquaredNode, plusNode,
xNode, bNode, anotherPlusNode, cNode
];

// layout
equalsNode.left = yNode.right + GQConstants.EQUATION_OPERATOR_SPACING;
aNode.left = equalsNode.right + GQConstants.EQUATION_OPERATOR_SPACING;
xSquaredNode.left = aNode.right + GQConstants.EQUATION_TERM_SPACING;
plusNode.left = xSquaredNode.right + GQConstants.EQUATION_OPERATOR_SPACING;
bNode.left = plusNode.right + GQConstants.EQUATION_OPERATOR_SPACING;
xNode.left = bNode.right + GQConstants.EQUATION_TERM_SPACING;
anotherPlusNode.left = xNode.right + GQConstants.EQUATION_OPERATOR_SPACING;
cNode.left = anotherPlusNode.right + GQConstants.EQUATION_OPERATOR_SPACING;
aNode.bottom = equalsNode.bottom;
bNode.bottom = equalsNode.bottom;
cNode.bottom = equalsNode.bottom;

super( options );

this.aNode = aNode;
this.bNode = bNode;
this.cNode = cNode;
}
// static parts of the equation
const equationOptions: RichTextOptions = {
font: GQConstants.INTERACTIVE_EQUATION_FONT
};
const xyOptions = combineOptions<RichTextOptions>( {}, equationOptions, {
maxWidth: 20 // determined empirically
} );
const yText = new RichText( GQSymbols.yMarkupStringProperty, xyOptions );
const equalToText = new RichText( MathSymbols.EQUAL_TO, equationOptions );
const xSquaredText = new RichText( GQSymbols.xSquaredMarkupStringProperty, xyOptions );
const plusText = new RichText( MathSymbols.PLUS, equationOptions );
const xText = new RichText( GQSymbols.xMarkupStringProperty, xyOptions );
const plusText2 = new RichText( MathSymbols.PLUS, equationOptions );

const equationNode = new Node( {
children: [ yText, equalToText, aNumberDisplay, xSquaredText, plusText, xText, bNumberDisplay, plusText2, cNumberDisplay ],
tandem: options.tandem.createTandem( 'equationNode' ),
phetioDocumentation: 'the equation that changes as the sliders are adjusted',
visiblePropertyOptions: {
phetioFeatured: true
}
} );

// Gets the global bounds of a, b, c, used for layout
public get aGlobalBounds(): Bounds2 {
return this.aNode.getGlobalBounds();
}
options.children = [ equationNode, aSlider, bSlider, cSlider ];

public get bGlobalBounds(): Bounds2 {
return this.bNode.getGlobalBounds();
}
super( options );

public get cGlobalBounds(): Bounds2 {
return this.cNode.getGlobalBounds();
// If any of the components that include dynamic text change their size, redo the layout.
Multilink.multilink( [
yText.boundsProperty, xSquaredText.boundsProperty, xText.boundsProperty,
aSlider.boundsProperty, bSlider.boundsProperty, cSlider.boundsProperty
],
() => {

// equation layout: y = ax^2 + bx + c
equalToText.left = yText.right + GQConstants.EQUATION_OPERATOR_SPACING;
aNumberDisplay.left = equalToText.right + GQConstants.EQUATION_OPERATOR_SPACING;
xSquaredText.left = aNumberDisplay.right + GQConstants.EQUATION_TERM_SPACING;
plusText.left = xSquaredText.right + GQConstants.EQUATION_OPERATOR_SPACING;
bNumberDisplay.left = plusText.right + GQConstants.EQUATION_OPERATOR_SPACING;
xText.left = bNumberDisplay.right + GQConstants.EQUATION_TERM_SPACING;
plusText2.left = xText.right + GQConstants.EQUATION_OPERATOR_SPACING;
cNumberDisplay.left = plusText2.right + GQConstants.EQUATION_OPERATOR_SPACING;
aNumberDisplay.bottom = equalToText.bottom;
bNumberDisplay.bottom = equalToText.bottom;
cNumberDisplay.bottom = equalToText.bottom;

// horizontally align sliders under their associated values in the equation
const ySpacing = 3;
aSlider.x = aNumberDisplay.centerX;
aSlider.top = equationNode.bottom + ySpacing;
bSlider.x = bNumberDisplay.centerX;
bSlider.top = equationNode.bottom + ySpacing;
cSlider.x = cNumberDisplay.centerX;
cSlider.top = equationNode.bottom + ySpacing;
} );
}
}

Expand Down
34 changes: 21 additions & 13 deletions js/standardform/view/StandardFormInteractiveEquationNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import GQConstants from '../../common/GQConstants.js';
import GQSymbols from '../../common/GQSymbols.js';
import graphingQuadratics from '../../graphingQuadratics.js';
import { combineOptions } from '../../../../phet-core/js/optionize.js';
import Multilink from '../../../../axon/js/Multilink.js';

export default class StandardFormInteractiveEquationNode extends Node {

Expand Down Expand Up @@ -71,20 +72,27 @@ export default class StandardFormInteractiveEquationNode extends Node {

super( options );

// layout
equalToText.left = yText.right + GQConstants.EQUATION_OPERATOR_SPACING;
aPicker.left = equalToText.right + GQConstants.EQUATION_OPERATOR_SPACING;
xSquaredText.left = aPicker.right + GQConstants.EQUATION_TERM_SPACING;
plusText.left = xSquaredText.right + GQConstants.EQUATION_OPERATOR_SPACING;
bPicker.left = plusText.right + GQConstants.EQUATION_OPERATOR_SPACING;
xText.left = bPicker.right + GQConstants.EQUATION_TERM_SPACING;
secondPlusText.left = xText.right + GQConstants.EQUATION_OPERATOR_SPACING;
cPicker.left = secondPlusText.right + GQConstants.EQUATION_OPERATOR_SPACING;
// If any of the components that include dynamic text change their size, redo the layout.
Multilink.multilink( [
yText.boundsProperty, xSquaredText.boundsProperty, xText.boundsProperty,
aPicker.boundsProperty, bPicker.boundsProperty, cPicker.boundsProperty
], () => {

// vertically center pickers on equals
aPicker.centerY = equalToText.centerY;
bPicker.centerY = equalToText.centerY;
cPicker.centerY = equalToText.centerY;
// layout
equalToText.left = yText.right + GQConstants.EQUATION_OPERATOR_SPACING;
aPicker.left = equalToText.right + GQConstants.EQUATION_OPERATOR_SPACING;
xSquaredText.left = aPicker.right + GQConstants.EQUATION_TERM_SPACING;
plusText.left = xSquaredText.right + GQConstants.EQUATION_OPERATOR_SPACING;
bPicker.left = plusText.right + GQConstants.EQUATION_OPERATOR_SPACING;
xText.left = bPicker.right + GQConstants.EQUATION_TERM_SPACING;
secondPlusText.left = xText.right + GQConstants.EQUATION_OPERATOR_SPACING;
cPicker.left = secondPlusText.right + GQConstants.EQUATION_OPERATOR_SPACING;

// vertically center pickers on equals
aPicker.centerY = equalToText.centerY;
bPicker.centerY = equalToText.centerY;
cPicker.centerY = equalToText.centerY;
} );
}
}

Expand Down

0 comments on commit 7b8913a

Please sign in to comment.