Skip to content

Commit

Permalink
factor out OpticalImageLabelNode, which handles object numbering and …
Browse files Browse the repository at this point in the history
…real/virtual, #380
  • Loading branch information
pixelzoom committed Mar 15, 2022
1 parent 85c8613 commit 8793271
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 62 deletions.
54 changes: 5 additions & 49 deletions js/common/view/labels/ArrowObjectSceneLabelsNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,7 @@ import BooleanProperty from '../../../../../axon/js/BooleanProperty.js';
import ArrowObject from '../../model/ArrowObject.js';
import Optic from '../../model/Optic.js';
import OpticalObjectLabelNode, { OpticalObjectLabelNodeOptions } from './OpticalObjectLabelNode.js';
import LabelNode, { LabelNodeOptions } from './LabelNode.js';
import optionize from '../../../../../phet-core/js/optionize.js';
import { OpticalImageType } from '../../model/OpticalImageType.js';
import Property from '../../../../../axon/js/Property.js';
import StringUtils from '../../../../../phetcommon/js/util/StringUtils.js';
import geometricOpticsStrings from '../../../geometricOpticsStrings.js';
import OpticalImageLabelNode, { OpticalImageLabelNodeOptions } from './OpticalImageLabelNode.js';

type SelfOptions = {
isBasicsVersion: boolean;
Expand Down Expand Up @@ -119,14 +114,8 @@ class ArrowObjectLabelNode extends OpticalObjectLabelNode {
}
}

type ArrowImageLabelNodeSelfOptions = {
isNumberedProperty?: IReadOnlyProperty<boolean>;
};

type ArrowImageLabelNodeOptions = ArrowImageLabelNodeSelfOptions & LabelNodeOptions;

// Label for an arrow image.
class ArrowImageLabelNode extends LabelNode {
class ArrowImageLabelNode extends OpticalImageLabelNode {

/**
* @param arrowImage
Expand All @@ -143,22 +132,7 @@ class ArrowImageLabelNode extends LabelNode {
arrowObjectVisibleProperty: IReadOnlyProperty<boolean>,
lightPropagationEnabledProperty: IReadOnlyProperty<boolean>,
virtualImageVisibleProperty: IReadOnlyProperty<boolean>,
providedOptions?: ArrowImageLabelNodeOptions ) {

const options = optionize<ArrowImageLabelNodeOptions, ArrowImageLabelNodeSelfOptions, LabelNodeOptions>( {
isNumberedProperty: new BooleanProperty( true ),
visibleProperty: new DerivedProperty( [
lightPropagationEnabledProperty,
arrowObjectVisibleProperty,
arrowImage.visibleProperty,
arrowImage.opticalImageTypeProperty,
virtualImageVisibleProperty
],
( lightPropagationEnabled: boolean, arrowObjectVisible: boolean, arrowImageVisible: boolean,
opticalImageType: OpticalImageType, virtualImageVisible: boolean ) =>
( lightPropagationEnabled && arrowObjectVisible && arrowImageVisible && ( opticalImageType === 'real' || virtualImageVisible ) )
)
}, providedOptions );
providedOptions?: OpticalImageLabelNodeOptions ) {

const labelPositionProperty = new DerivedProperty(
[ arrowImage.positionProperty, optic.positionProperty ],
Expand All @@ -172,26 +146,8 @@ class ArrowImageLabelNode extends LabelNode {
}
);

super( '', labelPositionProperty, zoomTransformProperty, options );

Property.multilink( [ arrowImage.opticalImageTypeProperty, options.isNumberedProperty ],
( opticalImageType: OpticalImageType, isNumbered: boolean ) => {
if ( isNumbered ) {

// Switch between 'Real Image N' and 'Virtual Image N'
const stringParams = { imageNumber: arrowImage.opticalObject.opticalObjectNumber };
this.setText( opticalImageType === 'real' ?
StringUtils.fillIn( geometricOpticsStrings.label.realImageN, stringParams ) :
StringUtils.fillIn( geometricOpticsStrings.label.virtualImageN, stringParams ) );
}
else {

// Switch between 'Real Image' and 'Virtual Image'
this.setText( opticalImageType === 'real' ?
geometricOpticsStrings.label.realImage :
geometricOpticsStrings.label.virtualImage );
}
} );
super( arrowImage, labelPositionProperty, zoomTransformProperty, arrowObjectVisibleProperty,
lightPropagationEnabledProperty, virtualImageVisibleProperty, providedOptions );
}
}

Expand Down
18 changes: 5 additions & 13 deletions js/common/view/labels/FramedObjectSceneLabelsNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,17 @@

import DerivedProperty from '../../../../../axon/js/DerivedProperty.js';
import geometricOptics from '../../../geometricOptics.js';
import LabelNode from './LabelNode.js';
import VisibleProperties from '../VisibleProperties.js';
import ModelViewTransform2 from '../../../../../phetcommon/js/view/ModelViewTransform2.js';
import Bounds2 from '../../../../../dot/js/Bounds2.js';
import IReadOnlyProperty from '../../../../../axon/js/IReadOnlyProperty.js';
import FramedObjectScene from '../../model/FramedObjectScene.js';
import { OpticalImageType } from '../../model/OpticalImageType.js';
import IProperty from '../../../../../axon/js/IProperty.js';
import GOSceneLabelsNode, { GOSceneLabelsNodeOptions } from './GOSceneLabelsNode.js';
import OpticalObjectLabelNode from './OpticalObjectLabelNode.js';
import BooleanProperty from '../../../../../axon/js/BooleanProperty.js';
import geometricOpticsStrings from '../../../geometricOpticsStrings.js';
import OpticalImageLabelNode from './OpticalImageLabelNode.js';

class FramedObjectSceneLabelsNode extends GOSceneLabelsNode {

Expand Down Expand Up @@ -64,17 +63,10 @@ class FramedObjectSceneLabelsNode extends GOSceneLabelsNode {
( bounds: Bounds2 ) => bounds.centerTop
);

const imageLabel = new LabelNode( '', imageLabelPositionProperty, zoomTransformProperty, {
visibleProperty: new DerivedProperty( [
lightPropagationEnabledProperty,
scene.framedImage1.visibleProperty,
scene.framedImage1.opticalImageTypeProperty,
visibleProperties.virtualImageVisibleProperty
],
( lightPropagationEnabled: boolean, imageVisible: boolean, opticalImageType: OpticalImageType, virtualImageVisible: boolean ) =>
( lightPropagationEnabled && imageVisible && ( opticalImageType === 'real' || virtualImageVisible ) )
)
} );
const imageLabel = new OpticalImageLabelNode( scene.framedImage1, imageLabelPositionProperty, zoomTransformProperty,
new BooleanProperty( true ), lightPropagationEnabledProperty, visibleProperties.virtualImageVisibleProperty, {
isNumberedProperty: isNumberedProperty
} );
this.addChild( imageLabel );

// Switch between 'Real Image' and 'Virtual Image'
Expand Down
89 changes: 89 additions & 0 deletions js/common/view/labels/OpticalImageLabelNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright 2021-2022, University of Colorado Boulder

/**
* OpticalImageLabelNode is the base class of labeling optical images, and distinguishes between real and virtual.
* It can label them as simply 'Real Image', or it can number them like 'Real Image 1'.
* Numbering is dynamic to support PhET-iO.
*
* @author Chris Malley (PixelZoom, Inc.)
*/
import LabelNode, { LabelNodeOptions } from './LabelNode.js';
import geometricOpticsStrings from '../../../geometricOpticsStrings.js';
import geometricOptics from '../../../geometricOptics.js';
import StringUtils from '../../../../../phetcommon/js/util/StringUtils.js';
import BooleanProperty from '../../../../../axon/js/BooleanProperty.js';
import optionize from '../../../../../phet-core/js/optionize.js';
import IReadOnlyProperty from '../../../../../axon/js/IReadOnlyProperty.js';
import Vector2 from '../../../../../dot/js/Vector2.js';
import ModelViewTransform2 from '../../../../../phetcommon/js/view/ModelViewTransform2.js';
import OpticalImage from '../../model/OpticalImage.js';
import { OpticalImageType } from '../../model/OpticalImageType.js';
import Property from '../../../../../axon/js/Property.js';
import DerivedProperty from '../../../../../axon/js/DerivedProperty.js';

type SelfOptions = {

// Whether the object should be numbered, like 'Object 1'
isNumberedProperty?: IReadOnlyProperty<boolean>;
};

export type OpticalImageLabelNodeOptions = SelfOptions & LabelNodeOptions;

class OpticalImageLabelNode extends LabelNode {

/**
* @param opticalImage
* @param labelPositionProperty
* @param zoomTransformProperty
* @param objectVisibleProperty
* @param lightPropagationEnabledProperty
* @param virtualImageVisibleProperty
* @param providedOptions
*/
constructor( opticalImage: OpticalImage,
labelPositionProperty: IReadOnlyProperty<Vector2>,
zoomTransformProperty: IReadOnlyProperty<ModelViewTransform2>,
objectVisibleProperty: IReadOnlyProperty<boolean>,
lightPropagationEnabledProperty: IReadOnlyProperty<boolean>,
virtualImageVisibleProperty: IReadOnlyProperty<boolean>,
providedOptions?: OpticalImageLabelNodeOptions ) {

const options = optionize<OpticalImageLabelNodeOptions, SelfOptions, LabelNodeOptions>( {
isNumberedProperty: new BooleanProperty( true ),
visibleProperty: new DerivedProperty( [
objectVisibleProperty,
lightPropagationEnabledProperty,
opticalImage.visibleProperty,
opticalImage.opticalImageTypeProperty,
virtualImageVisibleProperty
],
( objectVisible: boolean, lightPropagationEnabled: boolean, imageVisible: boolean,
opticalImageType: OpticalImageType, virtualImageVisible: boolean ) =>
( objectVisible && lightPropagationEnabled && imageVisible && ( opticalImageType === 'real' || virtualImageVisible ) ) )
}, providedOptions );

super( '', labelPositionProperty, zoomTransformProperty, options );

Property.multilink( [ opticalImage.opticalImageTypeProperty, options.isNumberedProperty ],
( opticalImageType: OpticalImageType, isNumbered: boolean ) => {
if ( isNumbered ) {

// Switch between 'Real Image N' and 'Virtual Image N'
const stringParams = { imageNumber: opticalImage.opticalObject.opticalObjectNumber };
this.setText( opticalImageType === 'real' ?
StringUtils.fillIn( geometricOpticsStrings.label.realImageN, stringParams ) :
StringUtils.fillIn( geometricOpticsStrings.label.virtualImageN, stringParams ) );
}
else {

// Switch between 'Real Image' and 'Virtual Image'
this.setText( opticalImageType === 'real' ?
geometricOpticsStrings.label.realImage :
geometricOpticsStrings.label.virtualImage );
}
} );
}
}

geometricOptics.register( 'OpticalImageLabelNode', OpticalImageLabelNode );
export default OpticalImageLabelNode;

0 comments on commit 8793271

Please sign in to comment.