phetsims / build-a-nucleus

"Build a Nucleus" is an educational simulation in HTML5, by PhET Interactive Simulations.
GNU General Public License v3.0
0 stars 5 forks source link

Can arrow buttons and creator nodes be an HBox and its own class? #185

Closed zepumph closed 1 year ago

zepumph commented 1 year ago

While discussing https://github.com/phetsims/build-a-nucleus/issues/170 with @Luisav1, it would be nice if we used a layout box to get the row of creators at the bottom of the screen view. Right now it is very manual, and kinda strange to pass in the creator Nodes to the arrow buttons for the enabled logic. This should all get moved into a separate class.

Let's name it NucleonCreatorsNode.

zepumph commented 1 year ago

Taking a look at this now.

zepumph commented 1 year ago

patch so far

```diff Subject: [PATCH] add intermediate versions for migration testing also, https://github.com/phetsims/phet-io/issues/1944 --- Index: js/common/view/NucleonArrowButtons.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/js/common/view/NucleonArrowButtons.ts b/js/common/view/NucleonCreatorsNode.ts rename from js/common/view/NucleonArrowButtons.ts rename to js/common/view/NucleonCreatorsNode.ts --- a/js/common/view/NucleonArrowButtons.ts (revision 9db90e80afeeb30bdee7150d84a91fde0eb6bd18) +++ b/js/common/view/NucleonCreatorsNode.ts (date 1693332377344) @@ -10,7 +10,7 @@ import buildANucleus from '../../buildANucleus.js'; import ParticleType from '../model/ParticleType.js'; import AtomIdentifier from '../../../../shred/js/AtomIdentifier.js'; -import { Node, ProfileColorProperty, VBox } from '../../../../scenery/js/imports.js'; +import { HBox, Node, PressListenerEvent, ProfileColorProperty, Text, VBox } from '../../../../scenery/js/imports.js'; import DerivedProperty from '../../../../axon/js/DerivedProperty.js'; import DoubleArrowButton, { ArrowButtonDirection } from './DoubleArrowButton.js'; import merge from '../../../../phet-core/js/merge.js'; @@ -21,11 +21,21 @@ import ArrowButton from '../../../../sun/js/buttons/ArrowButton.js'; import Particle from '../../../../shred/js/model/Particle.js'; import Range from '../../../../dot/js/Range.js'; +import TReadOnlyProperty from '../../../../axon/js/TReadOnlyProperty.js'; +import NucleonCreatorNode from './NucleonCreatorNode.js'; +import Vector2 from '../../../../dot/js/Vector2.js'; +import ModelViewTransform2 from '../../../../phetcommon/js/view/ModelViewTransform2.js'; +import BuildANucleusStrings from '../../BuildANucleusStrings.js'; +import PhetFont from '../../../../scenery-phet/js/PhetFont.js'; // constants const TOUCH_AREA_Y_DILATION = 3; +const NUCLEON_LABL_TEXT_OPTIONS = { font: new PhetFont( 20 ), maxWidth: 150 }; + +const HORIZONTAL_DISTANCE_BETWEEN_ARROW_BUTTONS = 40; -class NucleonArrowButtons extends Node { + +class NucleonCreatorsNode extends HBox { // public for positioning only public readonly doubleArrowButtons: Node; @@ -37,91 +47,58 @@ private readonly neutronNumberRange: Range; private readonly createParticleFromStack: ( particleType: ParticleType ) => Particle; private readonly returnParticleToStack: ( particleType: ParticleType ) => void; + private model: BANModel; + - public constructor( model: BANModel, protonsCreatorNode: Node, - neutronsCreatorNode: Node, + // the NucleonCreatorNode for the protons and neutrons + public readonly protonsCreatorNode: Node; + public readonly neutronsCreatorNode: Node; + + public readonly protonsCreatorNodeModelCenter: Vector2; + public readonly neutronsCreatorNodeModelCenter: Vector2; + + public constructor( model: BANModel, getLocalPoint: ( point: Vector2 ) => Vector2, + addAndDragParticle: ( event: PressListenerEvent, particle: Particle ) => void, + particleTransform: ModelViewTransform2, createParticleFromStack: ( particleType: ParticleType ) => Particle, returnParticleToStack: ( particleType: ParticleType ) => void ) { - super(); + super( { + align: 'bottom', + spacing: HORIZONTAL_DISTANCE_BETWEEN_ARROW_BUTTONS, + maxWidth: 450 + } ); + + // create and add the Protons and Neutrons label + const protonsLabel = new Text( BuildANucleusStrings.protonsStringProperty, NUCLEON_LABL_TEXT_OPTIONS ); + + // create and add the NucleonCreatorNode for the protons + this.protonsCreatorNode = new NucleonCreatorNode( ParticleType.PROTON, getLocalPoint, addAndDragParticle, + particleTransform ); + + // create and add the NucleonCreatorNode for the neutrons + this.neutronsCreatorNode = new NucleonCreatorNode( ParticleType.NEUTRON, getLocalPoint, addAndDragParticle, + particleTransform ); + const neutronsLabel = new Text( BuildANucleusStrings.neutronsUppercaseStringProperty, NUCLEON_LABL_TEXT_OPTIONS ); + + // store to know origin when creating / returning particles from stack + this.protonsCreatorNodeModelCenter = particleTransform.viewToModelPosition( this.protonsCreatorNode.center ); + this.neutronsCreatorNodeModelCenter = particleTransform.viewToModelPosition( this.neutronsCreatorNode.center ); + + + this.model = model; this.protonNumberRange = model.protonNumberRange; this.neutronNumberRange = model.neutronNumberRange; this.createParticleFromStack = createParticleFromStack; this.returnParticleToStack = returnParticleToStack; - // function to create the arrow enabled properties - const createArrowEnabledProperty = ( direction: ArrowButtonDirection, firstParticleType: ParticleType, secondParticleType?: ParticleType ) => { - return new DerivedProperty( [ - model.particleAtom.protonCountProperty, - model.particleAtom.neutronCountProperty, - model.incomingProtons.lengthProperty, - model.incomingNeutrons.lengthProperty, - model.userControlledProtons.lengthProperty, - model.userControlledNeutrons.lengthProperty - ], ( atomProtonNumber, atomNeutronNumber, incomingProtonsNumber, incomingNeutronsNumber, - userControlledProtonNumber, userControlledNeutronNumber ) => { - - const protonNumber = atomProtonNumber + incomingProtonsNumber + userControlledProtonNumber; - const neutronNumber = atomNeutronNumber + incomingNeutronsNumber + userControlledNeutronNumber; - const userControlledNucleonNumber = userControlledNeutronNumber + userControlledProtonNumber; - const doesNuclideExist = AtomIdentifier.doesExist( protonNumber, neutronNumber ); - const massNumber = atomProtonNumber + atomNeutronNumber; - - // Disable all buttons if the nuclide doesn't exist and one of the two cases: - // Something is being user controlled OR Particle Atom is not empty - if ( !doesNuclideExist && ( massNumber !== 0 || userControlledNucleonNumber !== 0 ) ) { - - // disable all arrow buttons if the nuclide does not exist - NucleonArrowButtons.toggleCreatorNodeEnabled( protonsCreatorNode, false ); - NucleonArrowButtons.toggleCreatorNodeEnabled( neutronsCreatorNode, false ); - return false; - } - else { - // Else handle each enabled case specifically - - // Turn creator nodes back on to a default, (enabled:true) state - NucleonArrowButtons.toggleCreatorNodeEnabled( protonsCreatorNode, true ); - NucleonArrowButtons.toggleCreatorNodeEnabled( neutronsCreatorNode, true ); - - // true when the potential spot to go to does not "exist". If there is a second particle type, check by - // changing both particle numbers. - const nextIsoDoesNotExist = secondParticleType ? - !NucleonArrowButtons.hasNextIso( direction, 'both', protonNumber, neutronNumber ) : - !NucleonArrowButtons.hasNextIso( direction, firstParticleType, protonNumber, neutronNumber ); - - // In the up direction, you can create one extra past an atom that does exist. - const allowIncreaseToNonExistent = direction === 'up' && AtomIdentifier.doesExist( protonNumber, neutronNumber ); - - // Covers cases where you can't remove a particle into a nuclide that doesn't exist, but you can add one - // extra (for learning) before it is animated back to an existent state. - if ( !allowIncreaseToNonExistent && nextIsoDoesNotExist ) { - return false; - } - - // If there are no atoms actually in the atom (only potentially animating to the atom), see https://github.com/phetsims/build-a-nucleus/issues/74 - if ( direction === 'down' && _.some( [ firstParticleType, secondParticleType ], particleType => { - return ( particleType === ParticleType.NEUTRON && atomNeutronNumber === 0 ) || - ( particleType === ParticleType.PROTON && atomProtonNumber === 0 ); - } ) ) { - return false; - } - - // Finally, disable any buttons that are at the range bound for that button. - const firstTypeNotAtRangeBound = this.isNucleonNumberNotAtRangeBounds( direction, firstParticleType, protonNumber, neutronNumber ); - return secondParticleType ? - firstTypeNotAtRangeBound && this.isNucleonNumberNotAtRangeBounds( direction, secondParticleType, protonNumber, neutronNumber ) : - firstTypeNotAtRangeBound; - } - } ); - }; - // create the arrow enabled properties - const protonUpArrowEnabledProperty = createArrowEnabledProperty( 'up', ParticleType.PROTON ); - const neutronUpArrowEnabledProperty = createArrowEnabledProperty( 'up', ParticleType.NEUTRON ); - const doubleUpArrowEnabledProperty = createArrowEnabledProperty( 'up', ParticleType.PROTON, ParticleType.NEUTRON ); - const protonDownArrowEnabledProperty = createArrowEnabledProperty( 'down', ParticleType.PROTON ); - const neutronDownArrowEnabledProperty = createArrowEnabledProperty( 'down', ParticleType.NEUTRON ); - const doubleDownArrowEnabledProperty = createArrowEnabledProperty( 'down', ParticleType.PROTON, ParticleType.NEUTRON ); + const protonUpArrowEnabledProperty = this.createArrowEnabledProperty( 'up', ParticleType.PROTON ); + const neutronUpArrowEnabledProperty = this.createArrowEnabledProperty( 'up', ParticleType.NEUTRON ); + const doubleUpArrowEnabledProperty = this.createArrowEnabledProperty( 'up', ParticleType.PROTON, ParticleType.NEUTRON ); + const protonDownArrowEnabledProperty = this.createArrowEnabledProperty( 'down', ParticleType.PROTON ); + const neutronDownArrowEnabledProperty = this.createArrowEnabledProperty( 'down', ParticleType.NEUTRON ); + const doubleDownArrowEnabledProperty = this.createArrowEnabledProperty( 'down', ParticleType.PROTON, ParticleType.NEUTRON ); // arrow buttons spacing and size options const arrowButtonSpacing = 7; // spacing between the 'up' arrow buttons and 'down' arrow buttons @@ -151,7 +128,7 @@ children: [ createDoubleArrowButtons( 'up' ), createDoubleArrowButtons( 'down' ) ], spacing: arrowButtonSpacing } ); - this.addChild( this.doubleArrowButtons ); + // function to create the single arrow buttons const createSingleArrowButtons = ( nucleonType: ParticleType, nucleonColorProperty: ProfileColorProperty ): Node => { @@ -176,9 +153,120 @@ // create and add the single arrow buttons this.protonArrowButtons = createSingleArrowButtons( ParticleType.PROTON, BANColors.protonColorProperty ); - this.addChild( this.protonArrowButtons ); + this.neutronArrowButtons = createSingleArrowButtons( ParticleType.NEUTRON, BANColors.neutronColorProperty ); - this.addChild( this.neutronArrowButtons ); + + + // positioning + // nucleonCreatorsNode positioning must be first since others depend on them + this.protonArrowButtons.right = this.doubleArrowButtons.left - HORIZONTAL_DISTANCE_BETWEEN_ARROW_BUTTONS; + this.neutronArrowButtons.left = this.doubleArrowButtons.right + HORIZONTAL_DISTANCE_BETWEEN_ARROW_BUTTONS; + // protonsLabel.boundsProperty.link( () => { + // protonsLabel.bottom = this.doubleArrowButtons.bottom; + // protonsLabel.centerX = ( this.doubleArrowButtons.left - this.protonArrowButtons.right ) / 2 + this.protonArrowButtons.right; + // } ); + // neutronsLabel.boundsProperty.link( () => { + // neutronsLabel.bottom = this.doubleArrowButtons.bottom; + // neutronsLabel.centerX = ( this.neutronArrowButtons.left - this.doubleArrowButtons.right ) / 2 + this.doubleArrowButtons.right; + // } ); + // position creator nodes last since dependent on and nucleon labels + this.protonsCreatorNode.top = this.doubleArrowButtons.top; + this.protonsCreatorNode.centerX = protonsLabel.centerX; + + this.neutronsCreatorNode.top = this.doubleArrowButtons.top; + + this.neutronsCreatorNode.centerX = neutronsLabel.centerX; + + const spacing = 15; + const maxHeight = this.protonArrowButtons.height; + this.children = [ + this.protonArrowButtons, + new VBox( { + spacing: spacing, + maxHeight: maxHeight, + children: [ + this.protonsCreatorNode, + protonsLabel + ] + } ), + this.doubleArrowButtons, + new VBox( { + spacing: spacing, + maxHeight: maxHeight, + children: [ + this.neutronsCreatorNode, + neutronsLabel + ] + } ), + this.neutronArrowButtons + ]; + } + + private createArrowEnabledProperty( direction: ArrowButtonDirection, firstParticleType: ParticleType, secondParticleType?: ParticleType ): TReadOnlyProperty { + + // function to create the arrow enabled properties + return new DerivedProperty( [ + this.model.particleAtom.protonCountProperty, + this.model.particleAtom.neutronCountProperty, + this.model.incomingProtons.lengthProperty, + this.model.incomingNeutrons.lengthProperty, + this.model.userControlledProtons.lengthProperty, + this.model.userControlledNeutrons.lengthProperty + ], ( atomProtonNumber, atomNeutronNumber, incomingProtonsNumber, incomingNeutronsNumber, + userControlledProtonNumber, userControlledNeutronNumber ) => { + + const protonNumber = atomProtonNumber + incomingProtonsNumber + userControlledProtonNumber; + const neutronNumber = atomNeutronNumber + incomingNeutronsNumber + userControlledNeutronNumber; + const userControlledNucleonNumber = userControlledNeutronNumber + userControlledProtonNumber; + const doesNuclideExist = AtomIdentifier.doesExist( protonNumber, neutronNumber ); + const massNumber = atomProtonNumber + atomNeutronNumber; + + // Disable all buttons if the nuclide doesn't exist and one of the two cases: + // Something is being user controlled OR Particle Atom is not empty + if ( !doesNuclideExist && ( massNumber !== 0 || userControlledNucleonNumber !== 0 ) ) { + + // disable all arrow buttons if the nuclide does not exist + NucleonCreatorsNode.toggleCreatorNodeEnabled( this.protonsCreatorNode, false ); + NucleonCreatorsNode.toggleCreatorNodeEnabled( this.neutronsCreatorNode, false ); + return false; + } + else { + // Else handle each enabled case specifically + + // Turn creator nodes back on to a default, (enabled:true) state + NucleonCreatorsNode.toggleCreatorNodeEnabled( this.protonsCreatorNode, true ); + NucleonCreatorsNode.toggleCreatorNodeEnabled( this.neutronsCreatorNode, true ); + + // true when the potential spot to go to does not "exist". If there is a second particle type, check by + // changing both particle numbers. + const nextIsoDoesNotExist = secondParticleType ? + !NucleonCreatorsNode.hasNextIso( direction, 'both', protonNumber, neutronNumber ) : + !NucleonCreatorsNode.hasNextIso( direction, firstParticleType, protonNumber, neutronNumber ); + + // In the up direction, you can create one extra past an atom that does exist. + const allowIncreaseToNonExistent = direction === 'up' && AtomIdentifier.doesExist( protonNumber, neutronNumber ); + + // Covers cases where you can't remove a particle into a nuclide that doesn't exist, but you can add one + // extra (for learning) before it is animated back to an existent state. + if ( !allowIncreaseToNonExistent && nextIsoDoesNotExist ) { + return false; + } + + // If there are no atoms actually in the atom (only potentially animating to the atom), see https://github.com/phetsims/build-a-nucleus/issues/74 + if ( direction === 'down' && _.some( [ firstParticleType, secondParticleType ], particleType => { + return ( particleType === ParticleType.NEUTRON && atomNeutronNumber === 0 ) || + ( particleType === ParticleType.PROTON && atomProtonNumber === 0 ); + } ) ) { + return false; + } + + // Finally, disable any buttons that are at the range bound for that button. + const firstTypeNotAtRangeBound = this.isNucleonNumberNotAtRangeBounds( direction, firstParticleType, protonNumber, neutronNumber ); + return secondParticleType ? + firstTypeNotAtRangeBound && this.isNucleonNumberNotAtRangeBounds( direction, secondParticleType, protonNumber, neutronNumber ) : + firstTypeNotAtRangeBound; + } + } ); } /** @@ -279,5 +367,5 @@ } } -buildANucleus.register( 'NucleonArrowButtons', NucleonArrowButtons ); -export default NucleonArrowButtons; \ No newline at end of file +buildANucleus.register( 'NucleonCreatorsNode', NucleonCreatorsNode ); +export default NucleonCreatorsNode; \ No newline at end of file Index: js/common/view/BANScreenView.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/js/common/view/BANScreenView.ts b/js/common/view/BANScreenView.ts --- a/js/common/view/BANScreenView.ts (revision 9db90e80afeeb30bdee7150d84a91fde0eb6bd18) +++ b/js/common/view/BANScreenView.ts (date 1693332002365) @@ -12,15 +12,12 @@ import BANConstants from '../../common/BANConstants.js'; import optionize from '../../../../phet-core/js/optionize.js'; import BANModel from '../model/BANModel.js'; -import { Node, PressListenerEvent, Text } from '../../../../scenery/js/imports.js'; +import { Node, PressListenerEvent } from '../../../../scenery/js/imports.js'; import NucleonNumberPanel from './NucleonNumberPanel.js'; import AtomIdentifier from '../../../../shred/js/AtomIdentifier.js'; -import PhetFont from '../../../../scenery-phet/js/PhetFont.js'; import ParticleView from '../../../../shred/js/view/ParticleView.js'; import Particle from '../../../../shred/js/model/Particle.js'; import ModelViewTransform2 from '../../../../phetcommon/js/view/ModelViewTransform2.js'; -import BuildANucleusStrings from '../../BuildANucleusStrings.js'; -import NucleonCreatorNode from './NucleonCreatorNode.js'; import ParticleType from '../model/ParticleType.js'; import ParticleAtom from '../../../../shred/js/model/ParticleAtom.js'; import Vector2 from '../../../../dot/js/Vector2.js'; @@ -32,7 +29,7 @@ import TReadOnlyProperty from '../../../../axon/js/TReadOnlyProperty.js'; import AlphaParticle from '../model/AlphaParticle.js'; import ElementNameText from './ElementNameText.js'; -import NucleonArrowButtons from './NucleonArrowButtons.js'; +import NucleonCreatorsNode from './NucleonCreatorsNode.js'; // types type SelfOptions = { @@ -50,9 +47,6 @@ outgoingNucleons: number; }; -// constants -const HORIZONTAL_DISTANCE_BETWEEN_ARROW_BUTTONS = 160; - abstract class BANScreenView> extends ScreenView { protected model: M; @@ -67,15 +61,8 @@ // ParticleView.id => {ParticleView} - lookup map for efficiency. Used for storage only. protected readonly particleViewMap: ParticleViewMap = {}; - // the NucleonCreatorNode for the protons and neutrons - protected readonly protonsCreatorNode: Node; - protected readonly neutronsCreatorNode: Node; - - private readonly protonsCreatorNodeModelCenter: Vector2; - private readonly neutronsCreatorNodeModelCenter: Vector2; - // the spinner buttons - protected readonly nucleonArrowButtons: NucleonArrowButtons; + protected readonly nucleonCreatorsNode: NucleonCreatorsNode; protected readonly elementNameText: ElementNameText; @@ -109,58 +96,18 @@ this.model.nuclideExistsProperty ); this.addChild( this.elementNameText ); - const nucleonLabelTextOptions = { font: new PhetFont( 20 ), maxWidth: 150 }; - - // create and add the Protons and Neutrons label - const protonsLabel = new Text( BuildANucleusStrings.protonsStringProperty, nucleonLabelTextOptions ); - this.addChild( protonsLabel ); - const neutronsLabel = new Text( BuildANucleusStrings.neutronsUppercaseStringProperty, nucleonLabelTextOptions ); - this.addChild( neutronsLabel ); - this.particleTransform = ModelViewTransform2.createSinglePointScaleMapping( Vector2.ZERO, options.particleViewPosition, 1 ); - const addAndDragParticle = this.addAndDragParticle.bind( this ); - const getLocalPoint = this.globalToLocalPoint.bind( this ); - // create and add the NucleonCreatorNode for the protons - this.protonsCreatorNode = new NucleonCreatorNode( ParticleType.PROTON, getLocalPoint, addAndDragParticle, - this.particleTransform ); - this.addChild( this.protonsCreatorNode ); + this.nucleonCreatorsNode = new NucleonCreatorsNode( this.model, + this.globalToLocalPoint.bind( this ), this.addAndDragParticle.bind( this ), + this.particleTransform, this.createParticleFromStack.bind( this ), this.returnParticleToStack.bind( this ) ); - // create and add the NucleonCreatorNode for the neutrons - this.neutronsCreatorNode = new NucleonCreatorNode( ParticleType.NEUTRON, getLocalPoint, addAndDragParticle, - this.particleTransform ); - this.addChild( this.neutronsCreatorNode ); + this.nucleonCreatorsNode.centerX = atomCenter.x; + this.nucleonCreatorsNode.bottom = this.layoutBounds.maxY - BANConstants.SCREEN_VIEW_Y_MARGIN; - const nucleonArrowButtons = new NucleonArrowButtons( this.model, this.protonsCreatorNode, - this.neutronsCreatorNode, this.createParticleFromStack.bind( this ), this.returnParticleToStack.bind( this ) ); - this.addChild( nucleonArrowButtons ); + this.addChild( this.nucleonCreatorsNode ); - // positioning - // nucleonArrowButtons positioning must be first since others depend on them - nucleonArrowButtons.doubleArrowButtons.bottom = this.layoutBounds.maxY - BANConstants.SCREEN_VIEW_Y_MARGIN; - nucleonArrowButtons.doubleArrowButtons.centerX = atomCenter.x; - nucleonArrowButtons.protonArrowButtons.bottom = this.layoutBounds.maxY - BANConstants.SCREEN_VIEW_Y_MARGIN; - nucleonArrowButtons.protonArrowButtons.right = nucleonArrowButtons.doubleArrowButtons.left - HORIZONTAL_DISTANCE_BETWEEN_ARROW_BUTTONS; - nucleonArrowButtons.neutronArrowButtons.bottom = this.layoutBounds.maxY - BANConstants.SCREEN_VIEW_Y_MARGIN; - nucleonArrowButtons.neutronArrowButtons.left = nucleonArrowButtons.doubleArrowButtons.right + HORIZONTAL_DISTANCE_BETWEEN_ARROW_BUTTONS; - protonsLabel.boundsProperty.link( () => { - protonsLabel.bottom = nucleonArrowButtons.doubleArrowButtons.bottom; - protonsLabel.centerX = ( nucleonArrowButtons.doubleArrowButtons.left - nucleonArrowButtons.protonArrowButtons.right ) / 2 + nucleonArrowButtons.protonArrowButtons.right; - } ); - neutronsLabel.boundsProperty.link( () => { - neutronsLabel.bottom = nucleonArrowButtons.doubleArrowButtons.bottom; - neutronsLabel.centerX = ( nucleonArrowButtons.neutronArrowButtons.left - nucleonArrowButtons.doubleArrowButtons.right ) / 2 + nucleonArrowButtons.doubleArrowButtons.right; - } ); - // position creator nodes last since dependent on nucleonArrowButtons and nucleon labels - this.protonsCreatorNode.top = nucleonArrowButtons.doubleArrowButtons.top; - this.protonsCreatorNode.centerX = protonsLabel.centerX; - this.neutronsCreatorNode.top = nucleonArrowButtons.doubleArrowButtons.top; - this.neutronsCreatorNode.centerX = neutronsLabel.centerX; - - // store to know origin when creating / returning particles from stack - this.protonsCreatorNodeModelCenter = this.particleTransform.viewToModelPosition( this.protonsCreatorNode.center ); - this.neutronsCreatorNodeModelCenter = this.particleTransform.viewToModelPosition( this.neutronsCreatorNode.center ); this.resetAllButton = new ResetAllButton( { listener: () => { @@ -217,16 +164,13 @@ // create the particleAtomNode but add it in subclasses so particles are in top layer this.particleAtomNode = new ParticleAtomNode( this.model.particleAtom, atomCenter, this.model.protonNumberRange ); - // for use in positioning - this.nucleonArrowButtons = nucleonArrowButtons; - // update the cloud size as the massNumber changes this.model.particleAtom.protonCountProperty.link( protonNumber => this.particleAtomNode.updateCloudSize( protonNumber, 0.27, 10, 20 ) ); this.pdomPlayAreaNode.pdomOrder = [ - nucleonArrowButtons.protonArrowButtons, - nucleonArrowButtons.doubleArrowButtons, - nucleonArrowButtons.neutronArrowButtons + this.nucleonCreatorsNode.protonArrowButtons, + this.nucleonCreatorsNode.doubleArrowButtons, + this.nucleonCreatorsNode.neutronArrowButtons ]; this.pdomControlAreaNode.pdomOrder = [ this.resetAllButton ]; } @@ -236,7 +180,8 @@ */ private getInfoForParticleType( particleType: ParticleType ): ParticleTypeInfo { const maxNumber = particleType === ParticleType.PROTON ? this.model.protonNumberRange.max : this.model.neutronNumberRange.max; - const creatorNode = particleType === ParticleType.PROTON ? this.protonsCreatorNode : this.neutronsCreatorNode; + const creatorNode = particleType === ParticleType.PROTON ? this.nucleonCreatorsNode.protonsCreatorNode : + this.nucleonCreatorsNode.neutronsCreatorNode; const numberOfNucleons = [ ...this.model.particles ] .filter( particle => particle.type === particleType.particleTypeString ).length; const outgoingNucleons = [ ...this.model.outgoingParticles ] @@ -298,7 +243,8 @@ // create a particle at the center of its creator node const particle = new BANParticle( particleType.particleTypeString ); const origin = particleType === ParticleType.PROTON ? - this.protonsCreatorNodeModelCenter : this.neutronsCreatorNodeModelCenter; + this.nucleonCreatorsNode.protonsCreatorNodeModelCenter : + this.nucleonCreatorsNode.neutronsCreatorNodeModelCenter; particle.setPositionAndDestination( origin ); // send the particle the center of the particleAtom and add it to the model @@ -335,7 +281,8 @@ */ private returnParticleToStack( particleType: ParticleType ): void { const creatorNodePosition = particleType === ParticleType.PROTON ? - this.protonsCreatorNodeModelCenter : this.neutronsCreatorNodeModelCenter; + this.nucleonCreatorsNode.protonsCreatorNodeModelCenter : + this.nucleonCreatorsNode.neutronsCreatorNodeModelCenter; const particleToReturn = this.model.getParticleToReturn( particleType, creatorNodePosition ); @@ -466,7 +413,8 @@ */ private dragEndedListener( nucleon: Particle, atom: ParticleAtom ): void { const particleCreatorNodeCenter = nucleon.type === ParticleType.PROTON.particleTypeString ? - this.protonsCreatorNode.center : this.neutronsCreatorNode.center; + this.nucleonCreatorsNode.protonsCreatorNode.center : + this.nucleonCreatorsNode.neutronsCreatorNode.center; // if removing the nucleon will create a nuclide that does not exist, re-add the nucleon to the atom const currentlyNonExistentAtom = Index: js/chart-intro/view/ChartIntroScreenView.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/js/chart-intro/view/ChartIntroScreenView.ts b/js/chart-intro/view/ChartIntroScreenView.ts --- a/js/chart-intro/view/ChartIntroScreenView.ts (revision 9db90e80afeeb30bdee7150d84a91fde0eb6bd18) +++ b/js/chart-intro/view/ChartIntroScreenView.ts (date 1693332002364) @@ -130,14 +130,14 @@ // positioning this.elementNameText.boundsProperty.link( () => { - this.elementNameText.centerX = this.nucleonArrowButtons.doubleArrowButtons.centerX; + this.elementNameText.centerX = this.nucleonCreatorsNode.doubleArrowButtons.centerX; this.elementNameText.top = this.nucleonNumberPanel.top; } ); this.nucleonNumberPanel.left = this.layoutBounds.left + 20; const nuclearShellModelText = new NuclearShellModelText(); nuclearShellModelText.boundsProperty.link( () => { - nuclearShellModelText.centerX = this.nucleonArrowButtons.doubleArrowButtons.centerX; + nuclearShellModelText.centerX = this.nucleonCreatorsNode.doubleArrowButtons.centerX; nuclearShellModelText.centerY = periodicTableAndIsotopeSymbol.bottom + 20; } ); this.addChild( nuclearShellModelText ); @@ -157,7 +157,7 @@ // create and add the 'Energy' arrow const energyTextDistanceFromArrow = 10; const arrow = new ArrowNode( energyText.right + energyTextDistanceFromArrow, - this.nucleonArrowButtons.protonArrowButtons.top - 30, energyText.right + energyTextDistanceFromArrow, + this.nucleonCreatorsNode.protonArrowButtons.top - 30, energyText.right + energyTextDistanceFromArrow, periodicTableAndIsotopeSymbol.bottom + 15, { tailWidth: 2 } ); this.addChild( arrow );
zepumph commented 1 year ago

Lots of good work from pairing with @Luisav1 above. Here are the cleanup steps I'd like to take care:

zepumph commented 1 year ago

Everything in https://github.com/phetsims/build-a-nucleus/issues/185#issuecomment-1698188068 was done above. I think we are ready to close after @Luisav1 gives a small spot check.

Luisav1 commented 1 year ago

The changes are looking good, closing.