From a894dcfa4d9875fb4f45f2e7543ffd4608e15a9b Mon Sep 17 00:00:00 2001 From: AgustinVallejo Date: Tue, 14 May 2024 17:02:41 -0500 Subject: [PATCH] Adding mystery questionmark and fitting density readout panel, see https://github.com/phetsims/buoyancy-basics/issues/6 --- .../view/BuoyancyBasicsExploreScreenView.ts | 18 ++++--- js/density/view/DensityIntroScreenView.ts | 37 ++++++++++---- js/density/view/DensityNumberLineNode.ts | 51 +++++++++++-------- 3 files changed, 70 insertions(+), 36 deletions(-) diff --git a/js/buoyancy-basics/view/BuoyancyBasicsExploreScreenView.ts b/js/buoyancy-basics/view/BuoyancyBasicsExploreScreenView.ts index 3ba61506..1988fcfc 100644 --- a/js/buoyancy-basics/view/BuoyancyBasicsExploreScreenView.ts +++ b/js/buoyancy-basics/view/BuoyancyBasicsExploreScreenView.ts @@ -35,6 +35,7 @@ import DensityBuoyancyCommonColors from '../../common/view/DensityBuoyancyCommon import CuboidView from '../../common/view/CuboidView.js'; import ScaleView from '../../common/view/ScaleView.js'; import MassView from '../../common/view/MassView.js'; +import BooleanProperty from '../../../../axon/js/BooleanProperty.js'; // constants const MARGIN = DensityBuoyancyCommonConstants.MARGIN; @@ -151,19 +152,24 @@ export default class BuoyancyBasicsExploreScreenView extends DensityBuoyancyScre // DerivedProperty doesn't need disposal, since everything here lives for the lifetime of the simulation { densityProperty: new DerivedProperty( [ model.liquidDensityProperty ], density => density ), - color: DensityBuoyancyCommonColors.liquidLabelProperty, - nameProperty: DensityBuoyancyCommonStrings.fluidStringProperty + nameProperty: DensityBuoyancyCommonStrings.fluidStringProperty, + visibleProperty: new BooleanProperty( true ), + isHiddenProperty: new BooleanProperty( false ), + color: DensityBuoyancyCommonColors.liquidLabelProperty }, { densityProperty: new DerivedProperty( [ model.primaryMass.materialProperty ], material => material.density ), - color: DensityBuoyancyCommonColors.labelPrimaryProperty, - nameProperty: model.primaryMass.tag.nameProperty + nameProperty: model.primaryMass.tag.nameProperty, + visibleProperty: new BooleanProperty( true ), + isHiddenProperty: new DerivedProperty( [ model.primaryMass.materialProperty ], material => material.hidden ), + color: DensityBuoyancyCommonColors.labelPrimaryProperty }, { densityProperty: new DerivedProperty( [ model.secondaryMass.materialProperty ], material => material.density ), - color: DensityBuoyancyCommonColors.labelSecondaryProperty, + nameProperty: model.secondaryMass.tag.nameProperty, visibleProperty: model.secondaryMass.visibleProperty, - nameProperty: model.secondaryMass.tag.nameProperty + isHiddenProperty: new DerivedProperty( [ model.secondaryMass.materialProperty ], material => material.hidden ), + color: DensityBuoyancyCommonColors.labelSecondaryProperty } ]; diff --git a/js/density/view/DensityIntroScreenView.ts b/js/density/view/DensityIntroScreenView.ts index 775ba1df..8119ba29 100644 --- a/js/density/view/DensityIntroScreenView.ts +++ b/js/density/view/DensityIntroScreenView.ts @@ -25,6 +25,8 @@ import Vector3 from '../../../../dot/js/Vector3.js'; import DensityBuoyancyCommonColors from '../../common/view/DensityBuoyancyCommonColors.js'; import BlocksRadioButtonGroup from '../../common/view/BlocksRadioButtonGroup.js'; import MassView from '../../common/view/MassView.js'; +import BooleanProperty from '../../../../axon/js/BooleanProperty.js'; +import Multilink from '../../../../axon/js/Multilink.js'; // constants const MARGIN = DensityBuoyancyCommonConstants.MARGIN; @@ -55,14 +57,17 @@ export default class DensityIntroScreenView extends DensityBuoyancyScreenView material.density ), - color: DensityBuoyancyCommonColors.labelPrimaryProperty, - nameProperty: model.primaryMass.tag.nameProperty + nameProperty: model.primaryMass.tag.nameProperty, + visibleProperty: new BooleanProperty( true ), + isHiddenProperty: new BooleanProperty( false ), + color: DensityBuoyancyCommonColors.labelPrimaryProperty }, { densityProperty: new DerivedProperty( [ model.secondaryMass.materialProperty ], material => material.density ), - color: DensityBuoyancyCommonColors.labelSecondaryProperty, + nameProperty: model.secondaryMass.tag.nameProperty, visibleProperty: model.secondaryMass.visibleProperty, - nameProperty: model.secondaryMass.tag.nameProperty + isHiddenProperty: new BooleanProperty( false ), + color: DensityBuoyancyCommonColors.labelSecondaryProperty } ], tandem: accordionTandem.createTandem( 'densityReadout' ), @@ -90,12 +95,24 @@ export default class DensityIntroScreenView extends DensityBuoyancyScreenView { + const rightBoxLeftEdge = rightBoxBounds.left; + const visibleBoundsLeftEdge = visibleBounds.left; + + const availableWidth = rightBoxLeftEdge - visibleBoundsLeftEdge - 2 * MARGIN; + + if ( availableWidth > 0 ) { + densityAccordionBox.maxWidth = availableWidth; + densityAccordionBox.centerX = visibleBoundsLeftEdge + availableWidth / 2 + MARGIN; + densityAccordionBox.top = visibleBounds.top + MARGIN; + } + } ); this.addChild( new AlignBox( this.rightBox, { alignBoundsProperty: this.visibleBoundsProperty, diff --git a/js/density/view/DensityNumberLineNode.ts b/js/density/view/DensityNumberLineNode.ts index e48516f5..f6d148c1 100644 --- a/js/density/view/DensityNumberLineNode.ts +++ b/js/density/view/DensityNumberLineNode.ts @@ -18,13 +18,16 @@ import densityBuoyancyCommon from '../../densityBuoyancyCommon.js'; import PatternStringProperty from '../../../../axon/js/PatternStringProperty.js'; import Tandem from '../../../../tandem/js/Tandem.js'; import DensityBuoyancyCommonStrings from '../../DensityBuoyancyCommonStrings.js'; +import DerivedProperty from '../../../../axon/js/DerivedProperty.js'; +import Multilink from '../../../../axon/js/Multilink.js'; // Type declarations: DisplayDensity is the object which will construct the marker and the legend export type DisplayDensity = { densityProperty: TReadOnlyProperty; nameProperty: TReadOnlyProperty; + visibleProperty: TReadOnlyProperty; + isHiddenProperty: TReadOnlyProperty; color: TPaint; - visibleProperty?: TReadOnlyProperty; }; type SelfOptions = { @@ -40,12 +43,15 @@ type SelfOptions = { }; // Constants and Functions -const WIDTH = 550; +const WIDTH = 540; const HEIGHT = 22; const MAX_DENSITY = 10000; // To display name: xxx kg/L dynamically -const createDensityStringProperty = ( densityNumberProperty: TReadOnlyProperty, nameStringProperty: TReadOnlyProperty ) => { +const createDensityStringProperty = ( + densityNumberProperty: TReadOnlyProperty, + nameStringProperty: TReadOnlyProperty, + isHiddenProperty: TReadOnlyProperty ) => { // This is densityProperty kg/L (units depending on preferences) const valueUnitsStringProperty = new PatternStringProperty( DensityBuoyancyCommonConstants.KILOGRAMS_PER_VOLUME_PATTERN_STRING_PROPERTY, { value: densityNumberProperty @@ -60,7 +66,11 @@ const createDensityStringProperty = ( densityNumberProperty: TReadOnlyProperty { + return isHidden ? questionMark : valueUnitsString; + } ) } ); return nameColonValueStringProperty; @@ -175,14 +185,15 @@ export default class DensityNumberLineNode extends Node { options.displayDensities.forEach( ( { densityProperty, + nameProperty, visibleProperty, - color, - nameProperty + isHiddenProperty, + color }, index ) => { const arrow = createArrow( index, color ); - const densityStringProperty = options.showNumericValue ? createDensityStringProperty( densityProperty, nameProperty ) : nameProperty; + const densityStringProperty = options.showNumericValue ? createDensityStringProperty( densityProperty, nameProperty, isHiddenProperty ) : nameProperty; const label = new RichText( densityStringProperty, combineOptions( { fill: color @@ -200,12 +211,6 @@ export default class DensityNumberLineNode extends Node { } ); markerNodes.push( marker ); - // Density links - // This instance lives for the lifetime of the simulation, so we don't need to remove this listener - densityProperty.link( density => { - marker.x = this.modelViewTransform( density ); - marker.visible = density < options.maxDensity! + 1e-5; // Allow rounding error - } ); ManualConstraint.create( this, [ labelContainer, arrow ], ( labelContainerProxy, arrowProxy ) => { if ( index === 0 ) { labelContainerProxy.centerBottom = arrowProxy.centerTop; @@ -216,8 +221,13 @@ export default class DensityNumberLineNode extends Node { } ); // This instance lives for the lifetime of the simulation, so we don't need to remove this listener - visibleProperty && visibleProperty.link( visible => { - marker.visible = visible; + Multilink.multilink( [ + densityProperty, + visibleProperty, + isHiddenProperty + ], ( density, isVisible, isHidden ) => { + marker.x = this.modelViewTransform( density ); + marker.visible = isVisible && !isHidden && density < options.maxDensity! + 1e-5; } ); } ); @@ -235,20 +245,21 @@ export class DensityNumberLineLegend extends VBox { displayDensities.forEach( ( { densityProperty, + nameProperty, visibleProperty, - color, - nameProperty + isHiddenProperty, + color }, index ) => { legendChildren.push( [ createArrow( index, color ), - new RichText( createDensityStringProperty( densityProperty, nameProperty ), { + new RichText( createDensityStringProperty( densityProperty, nameProperty, isHiddenProperty ), { font: new PhetFont( 16 ), - maxWidth: 100 + maxWidth: 110 } ) ] ); - legendVisibilities.push( visibleProperty! ); + legendVisibilities.push( visibleProperty ); } ); super( {