diff --git a/js/common/view/BottomRepresentationCheckboxGroup.ts b/js/common/view/BottomRepresentationCheckboxGroup.ts index 7ea2549b..b565d738 100644 --- a/js/common/view/BottomRepresentationCheckboxGroup.ts +++ b/js/common/view/BottomRepresentationCheckboxGroup.ts @@ -7,35 +7,21 @@ * @author Sam Reid (PhET Interactive Simulations) */ -import optionize from '../../../../phet-core/js/optionize.js'; import Property from '../../../../axon/js/Property.js'; import Tandem from '../../../../tandem/js/Tandem.js'; import ArrowNode from '../../../../scenery-phet/js/ArrowNode.js'; import centerAndVariability from '../../centerAndVariability.js'; -import VerticalCheckboxGroup, { VerticalCheckboxGroupItem, VerticalCheckboxGroupOptions } from '../../../../sun/js/VerticalCheckboxGroup.js'; +import VerticalCheckboxGroup, { VerticalCheckboxGroupItem } from '../../../../sun/js/VerticalCheckboxGroup.js'; import { AlignGroup, GridBox, Node, TColor, Text } from '../../../../scenery/js/imports.js'; import CAVModel from '../model/CAVModel.js'; import CAVConstants from '../CAVConstants.js'; import CenterAndVariabilityStrings from '../../CenterAndVariabilityStrings.js'; import CAVColors from '../CAVColors.js'; import NumberLineNode from './NumberLineNode.js'; -import PickRequired from '../../../../phet-core/js/types/PickRequired.js'; import PredictionThumbNode from './PredictionThumbNode.js'; import LinkableProperty from '../../../../axon/js/LinkableProperty.js'; import VariabilityModel from '../../variability/model/VariabilityModel.js'; -type SelfOptions = { - - // TODO: Let each class create exactly what they want without these options - includeMedian: boolean; - includeMean: boolean; - includePredictMean: boolean; - includePredictMedian: boolean; - includeVariability: boolean; -}; -export type BottomRepresentationCheckboxGroupOptions = SelfOptions & VerticalCheckboxGroupOptions & - PickRequired; - // constants const TEXT_OPTIONS = { font: CAVConstants.BUTTON_FONT, @@ -44,73 +30,96 @@ const TEXT_OPTIONS = { export default class BottomRepresentationCheckboxGroup extends VerticalCheckboxGroup { - public constructor( model: CAVModel, providedOptions?: BottomRepresentationCheckboxGroupOptions ) { - - const options = optionize()( { - }, providedOptions ); - - const items: VerticalCheckboxGroupItem[] = []; - const iconGroup = new AlignGroup(); - - const newGridBox = ( text: Node, icon: Node ) => { - return new GridBox( { - stretch: true, - spacing: 5, - grow: 1, - rows: [ [ - - // TODO: this will be odd to a11y because both buttons have the same text. Do we have alt text for the icons? Or maybe we need alt text for the entire checkbox? - new Node( { children: [ text ], layoutOptions: { xAlign: 'left' } } ), - iconGroup.createBox( icon, { layoutOptions: { xAlign: 'right' }, xAlign: 'center' } ) - ] ] - } ); - }; - - const createPredictionItem = ( property: Property, stringProperty: LinkableProperty, color: TColor, spacing: number, - tandemName: string ) => { - return { - createNode: ( tandem: Tandem ) => newGridBox( new Text( stringProperty, TEXT_OPTIONS ), new PredictionThumbNode( { color: color, maxHeight: 20, pickable: false } ) ), - property: property, - tandemName: tandemName - }; - }; - - options.includePredictMedian && items.push( createPredictionItem( model.isShowingMedianPredictionProperty, - CenterAndVariabilityStrings.predictMedianStringProperty, CAVColors.medianColorProperty, 8, 'predictMedianCheckbox' - ) ); - options.includePredictMean && items.push( createPredictionItem( model.isShowingMeanPredictionProperty, - CenterAndVariabilityStrings.predictMeanStringProperty, CAVColors.meanColorProperty, 20.3, 'predictMeanCheckbox' - ) ); + private static newGridBox( text: Node, icon: Node, iconGroup: AlignGroup ): GridBox { + return new GridBox( { + stretch: true, + spacing: 5, + grow: 1, + rows: [ [ + + // TODO: this will be odd to a11y because both buttons have the same text. Do we have alt text for the icons? Or maybe we need alt text for the entire checkbox? + new Node( { children: [ text ], layoutOptions: { xAlign: 'left' } } ), + iconGroup.createBox( icon, { layoutOptions: { xAlign: 'right' }, xAlign: 'center' } ) + ] ] + } ); + } - options.includeVariability && items.push( { - createNode: ( tandem: Tandem ) => newGridBox( new Text( CenterAndVariabilityStrings.variabilityStringProperty, TEXT_OPTIONS ), - NumberLineNode.createMeanIndicatorNode( true, true ) ), - property: ( model as VariabilityModel ).isShowingPlayAreaVariabilityProperty, + public static getVariabilityCheckbox( alignGroup: AlignGroup, model: VariabilityModel ): VerticalCheckboxGroupItem { + return { + createNode: ( tandem: Tandem ) => { + return BottomRepresentationCheckboxGroup.newGridBox( + new Text( CenterAndVariabilityStrings.variabilityStringProperty, TEXT_OPTIONS ), + NumberLineNode.createMeanIndicatorNode( true, true ), + alignGroup + ); + }, + property: model.isShowingPlayAreaVariabilityProperty, tandemName: 'variabilityCheckbox' - } ); + }; + } - options.includeMedian && items.push( { - createNode: ( tandem: Tandem ) => newGridBox( new Text( CenterAndVariabilityStrings.medianStringProperty, TEXT_OPTIONS ), - new ArrowNode( 0, 0, 0, 27, { - fill: CAVColors.medianColorProperty, - stroke: CAVColors.arrowStrokeProperty, - lineWidth: CAVConstants.ARROW_LINE_WIDTH, - headHeight: 12, - headWidth: 18, - maxHeight: 20 - } ) ), + public static getMedianCheckbox( alignGroup: AlignGroup, model: CAVModel ): VerticalCheckboxGroupItem { + return { + createNode: ( tandem: Tandem ) => { + return BottomRepresentationCheckboxGroup.newGridBox( + new Text( CenterAndVariabilityStrings.medianStringProperty, TEXT_OPTIONS ), + new ArrowNode( 0, 0, 0, 27, { + fill: CAVColors.medianColorProperty, + stroke: CAVColors.arrowStrokeProperty, + lineWidth: CAVConstants.ARROW_LINE_WIDTH, + headHeight: 12, + headWidth: 18, + maxHeight: 20 + } ), alignGroup ); + }, property: model.isShowingPlayAreaMedianProperty, tandemName: 'medianCheckbox' - } ); + }; + } - options.includeMean && items.push( { - createNode: ( tandem: Tandem ) => newGridBox( new Text( CenterAndVariabilityStrings.meanStringProperty, TEXT_OPTIONS ), - NumberLineNode.createMeanIndicatorNode( true, true ) ), + public static getMeanCheckbox( alignGroup: AlignGroup, model: CAVModel ): VerticalCheckboxGroupItem { + return { + createNode: ( tandem: Tandem ) => BottomRepresentationCheckboxGroup.newGridBox( new Text( CenterAndVariabilityStrings.meanStringProperty, TEXT_OPTIONS ), + NumberLineNode.createMeanIndicatorNode( true, true ), alignGroup ), property: model.isShowingPlayAreaMeanProperty, tandemName: 'meanCheckbox' - } ); + }; + } + + private static createPredictionItem( property: Property, stringProperty: LinkableProperty, color: TColor, spacing: number, + tandemName: string, alignGroup: AlignGroup ): VerticalCheckboxGroupItem { + return { + createNode: ( tandem: Tandem ) => { + return BottomRepresentationCheckboxGroup.newGridBox( + new Text( stringProperty, TEXT_OPTIONS ), + new PredictionThumbNode( { color: color, maxHeight: 20, pickable: false } ), + alignGroup ); + }, + property: property, + tandemName: tandemName + }; + } + + public static getPredictMedianCheckbox( alignGroup: AlignGroup, model: CAVModel ): VerticalCheckboxGroupItem { + return BottomRepresentationCheckboxGroup.createPredictionItem( + model.isShowingMedianPredictionProperty, + CenterAndVariabilityStrings.predictMedianStringProperty, + CAVColors.medianColorProperty, + 8, + 'predictMedianCheckbox', + alignGroup + ); + } - super( items, options ); + public static getPredictMeanCheckbox( alignGroup: AlignGroup, model: CAVModel ): VerticalCheckboxGroupItem { + return BottomRepresentationCheckboxGroup.createPredictionItem( + model.isShowingMeanPredictionProperty, + CenterAndVariabilityStrings.predictMeanStringProperty, + CAVColors.meanColorProperty, + 20.3, + 'predictMeanCheckbox', + alignGroup + ); } } diff --git a/js/mean-and-median/view/MeanAndMedianScreenView.ts b/js/mean-and-median/view/MeanAndMedianScreenView.ts index 09f91024..149e0879 100644 --- a/js/mean-and-median/view/MeanAndMedianScreenView.ts +++ b/js/mean-and-median/view/MeanAndMedianScreenView.ts @@ -12,13 +12,14 @@ import centerAndVariability from '../../centerAndVariability.js'; import MeanAndMedianModel from '../model/MeanAndMedianModel.js'; import CAVColors from '../../common/CAVColors.js'; import CenterAndVariabilityStrings from '../../CenterAndVariabilityStrings.js'; -import { AlignBox, ManualConstraint, Node } from '../../../../scenery/js/imports.js'; +import { AlignBox, AlignGroup, ManualConstraint, Node } from '../../../../scenery/js/imports.js'; import StrictOmit from '../../../../phet-core/js/types/StrictOmit.js'; import CAVScreenView, { CAVScreenViewOptions } from '../../common/view/CAVScreenView.js'; import Bounds2 from '../../../../dot/js/Bounds2.js'; import Tandem from '../../../../tandem/js/Tandem.js'; import MeanAndMedianAccordionBox from './MeanAndMedianAccordionBox.js'; import BottomRepresentationCheckboxGroup from '../../common/view/BottomRepresentationCheckboxGroup.js'; +import VerticalCheckboxGroup from '../../../../sun/js/VerticalCheckboxGroup.js'; type MeanAndMedianScreenViewOptions = StrictOmit; @@ -46,12 +47,13 @@ export default class MeanAndMedianScreenView extends CAVScreenView { contentsWrapper.x = playAreaNumberLineNodeWrapper.x; } ); - const bottomCheckboxGroup = new BottomRepresentationCheckboxGroup( model, { - includeMean: true, - includePredictMean: true, - includePredictMedian: true, - includeMedian: true, - includeVariability: false, + const iconGroup = new AlignGroup(); + const bottomCheckboxGroup = new VerticalCheckboxGroup( [ + BottomRepresentationCheckboxGroup.getPredictMedianCheckbox( iconGroup, model ), + BottomRepresentationCheckboxGroup.getPredictMeanCheckbox( iconGroup, model ), + BottomRepresentationCheckboxGroup.getMedianCheckbox( iconGroup, model ), + BottomRepresentationCheckboxGroup.getMeanCheckbox( iconGroup, model ) + ], { tandem: options.tandem.createTandem( 'bottomCheckboxGroup' ) } ); @@ -60,8 +62,13 @@ export default class MeanAndMedianScreenView extends CAVScreenView { const BOTTOM_CHECKBOX_PANEL_MARGIN = 12.5; const BOTTOM_CHECKBOX_PANEL_Y_MARGIN = this.layoutBounds.maxY - this.modelViewTransform.modelToViewY( 0 ) + BOTTOM_CHECKBOX_PANEL_MARGIN; - const checkboxAlignBox = new AlignBox( bottomCheckboxGroup, { alignBounds: this.layoutBounds, xAlign: 'right', yAlign: 'bottom', xMargin: BOTTOM_CHECKBOX_PANEL_MARGIN, yMargin: BOTTOM_CHECKBOX_PANEL_Y_MARGIN } ); - this.addChild( checkboxAlignBox ); + this.addChild( new AlignBox( bottomCheckboxGroup, { + alignBounds: this.layoutBounds, + xAlign: 'right', + yAlign: 'bottom', + xMargin: BOTTOM_CHECKBOX_PANEL_MARGIN, + yMargin: BOTTOM_CHECKBOX_PANEL_Y_MARGIN + } ) ); } } diff --git a/js/median/view/MedianScreenView.ts b/js/median/view/MedianScreenView.ts index d80b6219..b1a742cd 100644 --- a/js/median/view/MedianScreenView.ts +++ b/js/median/view/MedianScreenView.ts @@ -18,7 +18,8 @@ import Bounds2 from '../../../../dot/js/Bounds2.js'; import Tandem from '../../../../tandem/js/Tandem.js'; import MedianAccordionBox from './MedianAccordionBox.js'; import BottomRepresentationCheckboxGroup from '../../common/view/BottomRepresentationCheckboxGroup.js'; -import { AlignBox } from '../../../../scenery/js/imports.js'; +import { AlignBox, AlignGroup } from '../../../../scenery/js/imports.js'; +import VerticalCheckboxGroup from '../../../../sun/js/VerticalCheckboxGroup.js'; type SelfOptions = EmptySelfOptions; type MedianScreenViewOptions = @@ -43,12 +44,11 @@ export default class MedianScreenView extends CAVScreenView { ( tandem: Tandem, top: number, layoutBounds: Bounds2 ) => new MedianAccordionBox( model, layoutBounds, tandem, top ), options ); - const bottomCheckboxGroup = new BottomRepresentationCheckboxGroup( model, { - includeMean: false, - includePredictMean: false, - includePredictMedian: true, - includeMedian: true, - includeVariability: false, + const iconGroup = new AlignGroup(); + const bottomCheckboxGroup = new VerticalCheckboxGroup( [ + BottomRepresentationCheckboxGroup.getPredictMedianCheckbox( iconGroup, model ), + BottomRepresentationCheckboxGroup.getMedianCheckbox( iconGroup, model ) + ], { tandem: options.tandem.createTandem( 'bottomCheckboxGroup' ) } ); @@ -56,8 +56,13 @@ export default class MedianScreenView extends CAVScreenView { const BOTTOM_CHECKBOX_PANEL_MARGIN = 12.5; const BOTTOM_CHECKBOX_PANEL_Y_MARGIN = this.layoutBounds.maxY - this.modelViewTransform.modelToViewY( 0 ) + BOTTOM_CHECKBOX_PANEL_MARGIN; - const checkboxAlignBox = new AlignBox( bottomCheckboxGroup, { alignBounds: this.layoutBounds, xAlign: 'right', yAlign: 'bottom', xMargin: BOTTOM_CHECKBOX_PANEL_MARGIN, yMargin: BOTTOM_CHECKBOX_PANEL_Y_MARGIN } ); - this.addChild( checkboxAlignBox ); + this.addChild( new AlignBox( bottomCheckboxGroup, { + alignBounds: this.layoutBounds, + xAlign: 'right', + yAlign: 'bottom', + xMargin: BOTTOM_CHECKBOX_PANEL_MARGIN, + yMargin: BOTTOM_CHECKBOX_PANEL_Y_MARGIN + } ) ); } } diff --git a/js/variability/view/VariabilityScreenView.ts b/js/variability/view/VariabilityScreenView.ts index 5efb8830..374213e5 100644 --- a/js/variability/view/VariabilityScreenView.ts +++ b/js/variability/view/VariabilityScreenView.ts @@ -14,7 +14,7 @@ import centerAndVariability from '../../centerAndVariability.js'; import VariabilityModel from '../model/VariabilityModel.js'; import CAVColors from '../../common/CAVColors.js'; import CenterAndVariabilityStrings from '../../CenterAndVariabilityStrings.js'; -import { AlignBox, ManualConstraint, Node } from '../../../../scenery/js/imports.js'; +import { AlignBox, AlignGroup, ManualConstraint, Node } from '../../../../scenery/js/imports.js'; import DistributionRadioButtonGroup from './DistributionRadioButtonGroup.js'; import VariabilityMeasureRadioButtonGroup from './VariabilityMeasureRadioButtonGroup.js'; import InfoDialog from './InfoDialog.js'; @@ -23,6 +23,7 @@ import Bounds2 from '../../../../dot/js/Bounds2.js'; import Tandem from '../../../../tandem/js/Tandem.js'; import VariabilityAccordionBox from './VariabilityAccordionBox.js'; import BottomRepresentationCheckboxGroup from '../../common/view/BottomRepresentationCheckboxGroup.js'; +import VerticalCheckboxGroup from '../../../../sun/js/VerticalCheckboxGroup.js'; type SelfOptions = EmptySelfOptions; type VariabilityScreenViewOptions = SelfOptions & StrictOmit; @@ -90,12 +91,12 @@ export default class VariabilityScreenView extends CAVScreenView { } } ); - const bottomCheckboxGroup = new BottomRepresentationCheckboxGroup( model, { - includeVariability: true, - includePredictMean: false, - includePredictMedian: false, - includeMean: true, - includeMedian: true, + const iconGroup = new AlignGroup(); + const bottomCheckboxGroup = new VerticalCheckboxGroup( [ + BottomRepresentationCheckboxGroup.getVariabilityCheckbox( iconGroup, model ), + BottomRepresentationCheckboxGroup.getMedianCheckbox( iconGroup, model ), + BottomRepresentationCheckboxGroup.getMeanCheckbox( iconGroup, model ) + ], { tandem: options.tandem.createTandem( 'bottomCheckboxGroup' ) } ); @@ -104,8 +105,12 @@ export default class VariabilityScreenView extends CAVScreenView { const BOTTOM_CHECKBOX_PANEL_MARGIN = 12.5; const BOTTOM_CHECKBOX_PANEL_Y_MARGIN = this.layoutBounds.maxY - this.modelViewTransform.modelToViewY( 0 ) + BOTTOM_CHECKBOX_PANEL_MARGIN; - const checkboxAlignBox = new AlignBox( bottomCheckboxGroup, { alignBounds: this.layoutBounds, xAlign: 'right', yAlign: 'bottom', xMargin: BOTTOM_CHECKBOX_PANEL_MARGIN, yMargin: BOTTOM_CHECKBOX_PANEL_Y_MARGIN } ); - this.addChild( checkboxAlignBox ); + this.addChild( new AlignBox( bottomCheckboxGroup, { + alignBounds: this.layoutBounds, + xAlign: 'right', yAlign: 'bottom', + xMargin: BOTTOM_CHECKBOX_PANEL_MARGIN, + yMargin: BOTTOM_CHECKBOX_PANEL_Y_MARGIN + } ) ); } }