Skip to content

Commit

Permalink
factor out constants for level capacity, reuse color constants, and i…
Browse files Browse the repository at this point in the history
…nterpolate colors instead of hard coding the spectrum, #85
  • Loading branch information
zepumph committed Aug 2, 2023
1 parent 1f9c894 commit 2ac1eaa
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 54 deletions.
13 changes: 9 additions & 4 deletions js/chart-intro/model/ParticleNucleus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@ export type ParticleShellPosition = {
};

// constants
export const FIRST_LEVEL_CAPACITY = 2; // Number of particles available on the first energy level of a nucleus.
export const SECOND_LEVEL_CAPACITY = 6; // Number of particles available on the second and third energy levels of a nucleus.

// row is yPosition, number is xPosition
const ALLOWED_PARTICLE_POSITIONS = [
[ 2, 3 ],
[ 0, 1, 2, 3, 4, 5 ],
[ 0, 1, 2, 3, 4, 5 ]
];
assert && assert( ALLOWED_PARTICLE_POSITIONS[ 1 ].length === SECOND_LEVEL_CAPACITY, 'second level spots check' );
assert && assert( ALLOWED_PARTICLE_POSITIONS[ 2 ].length === SECOND_LEVEL_CAPACITY, 'third level spots check' );
assert && assert( ALLOWED_PARTICLE_POSITIONS[ 0 ].length === FIRST_LEVEL_CAPACITY, 'first level spots check' );

class ParticleNucleus extends ParticleAtom {

Expand Down Expand Up @@ -78,21 +83,21 @@ class ParticleNucleus extends ParticleAtom {

// update bound levels based on nucleon counts
this.protonCountProperty.link( protonCount => {
if ( protonCount >= 9 ) {
if ( protonCount >= FIRST_LEVEL_CAPACITY + SECOND_LEVEL_CAPACITY ) {
this.protonsLevelProperty.value = EnergyLevelType.SECOND;
}
else if ( protonCount >= 3 ) {
else if ( protonCount > FIRST_LEVEL_CAPACITY ) {
this.protonsLevelProperty.value = EnergyLevelType.FIRST;
}
else {
this.protonsLevelProperty.value = EnergyLevelType.NONE;
}
} );
this.neutronCountProperty.link( neutronCount => {
if ( neutronCount >= 9 ) {
if ( neutronCount >= FIRST_LEVEL_CAPACITY + SECOND_LEVEL_CAPACITY ) {
this.neutronsLevelProperty.value = EnergyLevelType.SECOND;
}
else if ( neutronCount >= 3 ) {
else if ( neutronCount > FIRST_LEVEL_CAPACITY ) {
this.neutronsLevelProperty.value = EnergyLevelType.FIRST;
}
else {
Expand Down
69 changes: 24 additions & 45 deletions js/chart-intro/view/NucleonShellView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,51 +15,23 @@ import TReadOnlyProperty from '../../../../axon/js/TReadOnlyProperty.js';
import ParticleType from '../../common/model/ParticleType.js';
import Vector2 from '../../../../dot/js/Vector2.js';
import optionize from '../../../../phet-core/js/optionize.js';
import { ParticleShellPosition } from '../model/ParticleNucleus.js';
import { FIRST_LEVEL_CAPACITY, ParticleShellPosition, SECOND_LEVEL_CAPACITY } from '../model/ParticleNucleus.js';

type SelfOptions = {
xOffset?: number;
};
type EnergyLevelNodeOptions = SelfOptions & NodeOptions;

// TODO: Remove color arrays, instead https://github.com/phetsims/build-a-nucleus/issues/85.
// nucleon number to energy level stroke color
const neutronNumberToColorLowerLevel = [
BANColors.zeroNucleonsEnergyLevelColorProperty, // 0
Color.interpolateRGBA( BANColors.zeroNucleonsEnergyLevelColorProperty.value, BANColors.neutronColorProperty.value, 0.5 ), // 1
BANColors.neutronColorProperty // 2
];
const neutronNumberToColorUpperLevel = [
BANColors.zeroNucleonsEnergyLevelColorProperty, // 0
new Color( 21, 21, 21 ), // 1
new Color( 43, 43, 43 ), // 2
new Color( 64, 64, 64 ), // 3
new Color( 85, 85, 85 ), // 4
new Color( 107, 107, 107 ), // 5
BANColors.neutronColorProperty // 6
];
const protonNumberToColorLowerLevel = [
BANColors.zeroNucleonsEnergyLevelColorProperty, // 0
Color.interpolateRGBA( BANColors.zeroNucleonsEnergyLevelColorProperty.value, BANColors.neutronColorProperty.value, 0.5 ), // 1
BANColors.protonColorProperty // 2
];
const protonNumberToColorUpperLevel = [
BANColors.zeroNucleonsEnergyLevelColorProperty, // 0
new Color( 43, 14, 0 ), // 1
new Color( 85, 28, 0 ), // 2
new Color( 128, 43, 0 ), // 3
new Color( 170, 57, 0 ), // 4
new Color( 213, 71, 0 ), // 5
BANColors.protonColorProperty // 6
];

class NucleonShellView extends Node {
private modelViewTransform: ModelViewTransform2;

public constructor( particleType: ParticleType, nucleonShellPositions: ParticleShellPosition[][],
nucleonCountProperty: TReadOnlyProperty<number>, particleViewPositionVector: Vector2,
providedOptions?: EnergyLevelNodeOptions ) {

assert && assert( particleType === ParticleType.NEUTRON || particleType === ParticleType.PROTON,
'only protons and neutrons supported in NucleonShellView' );

const options = optionize<EnergyLevelNodeOptions, SelfOptions, NodeOptions>()( {
xOffset: 0
}, providedOptions );
Expand All @@ -70,6 +42,14 @@ class NucleonShellView extends Node {

this.modelViewTransform = BANConstants.NUCLEON_ENERGY_LEVEL_ARRAY_MVT;

// Color when the layer is completely empty
const emptyLayerColor = BANColors.zeroNucleonsEnergyLevelColorProperty.value;

// Color when the layer is completely full
const fullLayerColor = particleType === ParticleType.NEUTRON ?
BANColors.neutronColorProperty.value :
BANColors.protonColorProperty.value;

// create and add the nucleon energy levels
const energyLevels: Line[] = [];
nucleonShellPositions.forEach( ( particleShellRow, energyLevel ) => {
Expand All @@ -93,28 +73,27 @@ class NucleonShellView extends Node {
// update the stroke color and width of the respective energy levels as the nucleon count changes
const boldEnergyLevelWidth = 4;
const defaultEnergyLevelWidth = 1;
const nucleonCountToColorLowerLevel = particleType === ParticleType.PROTON ? protonNumberToColorLowerLevel :
neutronNumberToColorLowerLevel;
const nucleonCountToColorUpperLevel = particleType === ParticleType.PROTON ? protonNumberToColorUpperLevel :
neutronNumberToColorUpperLevel;
nucleonCountProperty.link( nucleonCount => {
if ( nucleonCount <= 2 ) {
energyLevels[ 0 ].stroke = nucleonCountToColorLowerLevel[ nucleonCount ];
if ( nucleonCount <= FIRST_LEVEL_CAPACITY ) {
energyLevels[ 0 ].stroke = Color.interpolateRGBA( emptyLayerColor, fullLayerColor, nucleonCount / FIRST_LEVEL_CAPACITY );

// if the energy level is full (2 particles on the lower energy level), double the lineWidth
energyLevels[ 0 ].lineWidth = nucleonCount === 2 ? boldEnergyLevelWidth : defaultEnergyLevelWidth;
energyLevels[ 0 ].lineWidth = nucleonCount === FIRST_LEVEL_CAPACITY ? boldEnergyLevelWidth : defaultEnergyLevelWidth;
}
else {
let energyLevelNumber = 1;
if ( nucleonCount > 8 ) {
nucleonCount -= 6;
energyLevelNumber = 2;
if ( nucleonCount > SECOND_LEVEL_CAPACITY + FIRST_LEVEL_CAPACITY ) {
nucleonCount -= SECOND_LEVEL_CAPACITY;
energyLevelNumber = FIRST_LEVEL_CAPACITY;
}
nucleonCount -= 2;
energyLevels[ energyLevelNumber ].stroke = nucleonCountToColorUpperLevel[ nucleonCount ];
nucleonCount -= FIRST_LEVEL_CAPACITY; // REVIEW: instead of mutating the listener variable, it is better to name a new one (less confusing that way)
const stroke = Color.interpolateRGBA( emptyLayerColor, fullLayerColor, nucleonCount / SECOND_LEVEL_CAPACITY );

console.log( nucleonCount / SECOND_LEVEL_CAPACITY );
energyLevels[ energyLevelNumber ].stroke = stroke;

// if the energy level is full (6 particles on the upper and middle energy levels), double the lineWidth
energyLevels[ energyLevelNumber ].lineWidth = nucleonCount === 6 ? boldEnergyLevelWidth : defaultEnergyLevelWidth;
energyLevels[ energyLevelNumber ].lineWidth = nucleonCount === SECOND_LEVEL_CAPACITY ? boldEnergyLevelWidth : defaultEnergyLevelWidth;
}
} );
}
Expand Down
10 changes: 5 additions & 5 deletions js/common/BANColors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import { Color, ProfileColorProperty } from '../../../scenery/js/imports.js';
import buildANucleus from '../buildANucleus.js';
import PhetColorScheme from '../../../scenery-phet/js/PhetColorScheme.js';
import { PARTICLE_COLORS } from '../../../shred/js/model/Particle.js';

const BANColors = {

Expand All @@ -19,16 +19,16 @@ const BANColors = {

// particle colors
protonColorProperty: new ProfileColorProperty( buildANucleus, 'protonColor', {
default: PhetColorScheme.RED_COLORBLIND
default: PARTICLE_COLORS.proton
} ),
neutronColorProperty: new ProfileColorProperty( buildANucleus, 'neutronColor', {
default: Color.GRAY
default: PARTICLE_COLORS.neutron
} ),
electronColorProperty: new ProfileColorProperty( buildANucleus, 'electronColor', {
default: Color.BLUE
default: PARTICLE_COLORS.electron
} ),
positronColorProperty: new ProfileColorProperty( buildANucleus, 'positronColor', {
default: new Color( 53, 182, 74 )
default: PARTICLE_COLORS.positron
} ),

// decay colors
Expand Down
1 change: 1 addition & 0 deletions js/common/view/BANScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@ abstract class BANScreenView<M extends BANModel<ParticleAtom | ParticleNucleus>>
particle.dispose();
}
}

/**
* Add a particle to the model and immediately start dragging it with the provided event.
*/
Expand Down

0 comments on commit 2ac1eaa

Please sign in to comment.