Skip to content

Commit

Permalink
feat(event-display): highly optimize and generalize color by options
Browse files Browse the repository at this point in the history
  • Loading branch information
9inpachi committed Apr 24, 2021
1 parent 4acca1a commit 595d9e5
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 110 deletions.
260 changes: 154 additions & 106 deletions packages/phoenix-event-display/src/managers/ui-manager/color-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,166 +2,214 @@ import { PrettySymbols } from '../../helpers/pretty-symbols';
import { ColoringManager } from '../three-manager/coloring-manager';
import { PhoenixMenuNode } from './phoenix-menu/phoenix-menu-node';

export enum ColorByOptionKeys {
CHARGE = 'charge',
MOM = 'mom',
}

type ColorByOption = {
key: ColorByOptionKeys;
name: string;
initialize: () => void;
apply: () => void;
};

/**
* Color options with functions to color event data.
*/
export class ColorOptions {
private collectionName: string;
private allColorByOptions: ColorByOption[] = [
{
key: ColorByOptionKeys.CHARGE,
name: 'Charge ' + PrettySymbols.getPrettySymbol('charge'),
initialize: this.initChargeColorOptions.bind(this),
apply: this.applyChargeColorOptions.bind(this),
},
{
key: ColorByOptionKeys.MOM,
name: 'Momentum ' + PrettySymbols.getPrettySymbol('mom'),
initialize: this.initMomColorOptions.bind(this),
apply: this.applyMomColorOptions.bind(this),
},
];
private colorByOptions: ColorByOption[];
private selectedColorByOption: ColorByOptionKeys;

// Charge options.
private chargeColors = {
'-1': '#ff0000',
'0': '#ff0000',
'1': '#ff0000',
};

// Momentum options.
private momColors = {
min: {
value: 0,
color: '#ff0000',
},
max: {
value: 50000,
color: '#ff0000',
},
};

/**
* Create the color options.
* @param coloringManager Coloring manager for three.js functions related to coloring of objects.
*/
constructor(private coloringManager: ColoringManager) {}

/**
* Add color options for tracks.
* @param collectionFolder Phoenix menu node of a collection.
*/
public trackColorOptions(collectionFolder: PhoenixMenuNode) {
const collectionName = collectionFolder.name;

const colorByOptions = {
charge: 'Charge ' + PrettySymbols.getPrettySymbol('charge'),
mom: 'Momentum ' + PrettySymbols.getPrettySymbol('charge'),
};

const chargeColors = {
'-1': '#ff0000',
'0': '#ff0000',
'1': '#ff0000',
};

const momColors = {
min: {
value: 0,
color: '#ff0000',
},
max: {
value: 50000,
color: '#ff0000',
},
};

const momMidValue = () => (momColors.min.value + momColors.max.value) / 2;
constructor(
private coloringManager: ColoringManager,
private collectionFolder: PhoenixMenuNode,
colorByOptionsToInclude: ColorByOptionKeys[]
) {
this.collectionName = collectionFolder.name;

this.colorByOptions = this.allColorByOptions.filter((colorByOption) =>
colorByOptionsToInclude.includes(colorByOption.key)
);

if (this.colorByOptions?.length > 0) {
this.init();
this.colorByOptions.forEach((colorByOption) =>
colorByOption.initialize()
);
}
}

let selectedColorByOption = colorByOptions.charge;
private init() {
this.selectedColorByOption = this.colorByOptions[0].key;

// Configurations
collectionFolder.addConfig('label', {
this.collectionFolder.addConfig('label', {
label: 'Color options',
});

collectionFolder.addConfig('select', {
this.collectionFolder.addConfig('select', {
label: 'Color by',
options: Object.values(colorByOptions),
options: this.colorByOptions.map((colorByOption) => colorByOption.name),
onChange: (updatedColorByOption: string) => {
selectedColorByOption = updatedColorByOption;

switch (updatedColorByOption) {
case colorByOptions.charge:
[-1, 0, 1].forEach((chargeValue) => {
this.coloringManager.colorObjectsByProperty(
chargeColors[chargeValue],
collectionName,
(objectUserData) =>
this.shouldColorByCharge(objectUserData, chargeValue)
);
});
break;
case colorByOptions.mom:
colorByMomentum('min', momColors.min.color);
colorByMomentum('max', momColors.max.color);
break;
}
const newColorByOption = this.colorByOptions.find(
(colorByOption) => colorByOption.name === updatedColorByOption
);

this.selectedColorByOption = newColorByOption?.key;
newColorByOption?.apply();
},
});
}

// Charge options.

private initChargeColorOptions() {
// Charge configurations
[-1, 0, 1].forEach((chargeValue) => {
collectionFolder.addConfig('color', {
this.collectionFolder.addConfig('color', {
label: `${PrettySymbols.getPrettySymbol('charge')}=${chargeValue}`,
color: chargeColors[chargeValue],
color: this.chargeColors[chargeValue],
onChange: (color: any) => {
chargeColors[chargeValue] = color;
this.chargeColors[chargeValue] = color;

if (selectedColorByOption === colorByOptions.charge) {
if (this.selectedColorByOption === ColorByOptionKeys.CHARGE) {
this.coloringManager.colorObjectsByProperty(
color,
collectionName,
this.collectionName,
(objectUserData) =>
this.shouldColorByCharge(objectUserData, chargeValue)
);
}
},
});
});
}

// Momentum helper functions
const colorByMomentum = (minOrMax: string, color: any) => {
private applyChargeColorOptions() {
[-1, 0, 1].forEach((chargeValue) => {
this.coloringManager.colorObjectsByProperty(
color,
'Tracks',
(objectParams) => {
const mom = this.getMomentum(objectParams);
const mid = momMidValue();

if (minOrMax === 'max' && mom > mid && mom < momColors.max.value) {
return true;
} else if (
minOrMax === 'min' &&
mom < mid &&
mom > momColors.min.value
) {
return true;
}
}
this.chargeColors[chargeValue],
this.collectionName,
(objectUserData) =>
this.shouldColorByCharge(objectUserData, chargeValue)
);
};
});
}

/**
* Check if object should be colored based on charge value.
* @param objectParams Object parameters associated to the 3D object.
* @param chargeValue Value of charge (-1, 0, 1).
* @returns Whether the charge is equal to the value.
*/
private shouldColorByCharge(objectParams: any, chargeValue: number) {
// For ATLAS data, the charge is calculated from dparams[4] otherwise it exists as an object's userData
if (Math.sign(1 / parseInt(objectParams?.dparams?.[4])) === chargeValue) {
return true;
} else if (objectParams?.charge === chargeValue) {
return true;
}
}

// Momentum options.

private initMomColorOptions() {
// Momentum configurations
Object.entries(momColors).forEach(([key, value]) => {
collectionFolder.addConfig('slider', {
Object.entries(this.momColors).forEach(([key, momValue]) => {
this.collectionFolder.addConfig('slider', {
label: PrettySymbols.getPrettySymbol('mom') + ' ' + key,
min: momColors.min.value,
max: momColors.max.value,
value: momColors[key].value,
min: this.momColors.min.value,
max: this.momColors.max.value,
value: this.momColors[key].value,
step: 10,
allowCustomValue: true,
onChange: (value: number) => {
momColors[key].value = value;
if (selectedColorByOption === colorByOptions.mom) {
colorByMomentum('min', momColors.min.color);
colorByMomentum('max', momColors.max.color);
onChange: (sliderValue: number) => {
this.momColors[key].value = sliderValue;

if (this.selectedColorByOption === ColorByOptionKeys.MOM) {
this.colorByMomentum('min');
this.colorByMomentum('max');
}
},
});

collectionFolder.addConfig('color', {
this.collectionFolder.addConfig('color', {
label: PrettySymbols.getPrettySymbol('mom') + ' ' + key + ' color',
color: value.color,
color: momValue.color,
onChange: (color: any) => {
value.color = color;
this.momColors[key].color = color;

if (selectedColorByOption === colorByOptions.mom) {
colorByMomentum(key, color);
if (this.selectedColorByOption === ColorByOptionKeys.MOM) {
this.colorByMomentum(key);
}
},
});
});
}

/**
* Check if object should be colored based on charge value.
* @param objectParams Object parameters associated to the 3D object.
* @param chargeValue Value of charge (-1, 0, 1).
* @returns Whether the charge is equal to the value.
*/
private shouldColorByCharge(objectParams: any, chargeValue: number) {
// For ATLAS data, the charge is calculated from dparams[4] otherwise it exists as an object's userData
if (Math.sign(1 / parseInt(objectParams?.dparams?.[4])) === chargeValue) {
return true;
} else if (objectParams?.charge === chargeValue) {
return true;
}
private applyMomColorOptions() {
this.colorByMomentum('min');
this.colorByMomentum('max');
}

private colorByMomentum(minOrMax: string) {
this.coloringManager.colorObjectsByProperty(
this.momColors[minOrMax].color,
this.collectionName,
(objectParams) => {
const mom = this.getMomentum(objectParams);
const mid = (this.momColors.min.value + this.momColors.max.value) / 2;

if (minOrMax === 'max' && mom > mid && mom < this.momColors.max.value) {
return true;
} else if (
minOrMax === 'min' &&
mom < mid &&
mom > this.momColors.min.value
) {
return true;
}
}
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ThreeManager } from '../../three-manager';
import { PhoenixMenuNode } from './phoenix-menu-node';
import { Cut } from '../../../extras/cut.model';
import { PrettySymbols } from '../../../helpers/pretty-symbols';
import { ColorOptions } from '../color-options';
import { ColorByOptionKeys, ColorOptions } from '../color-options';

/**
* A wrapper class for Phoenix menu to perform UI related operations.
Expand Down Expand Up @@ -34,8 +34,6 @@ export class PhoenixMenuUI {
}
this.phoenixMenu = phoenixMenu;

this.colorOptions = new ColorOptions(three.getColoringManager());

this.geomFolder = null;
this.eventFolder = null;
this.labelsFolder = null;
Expand Down Expand Up @@ -283,7 +281,10 @@ export class PhoenixMenuUI {

// Extra config options specific to tracks
if (typeFolder.name === 'Tracks') {
this.colorOptions.trackColorOptions(collectionNode);
new ColorOptions(this.three.getColoringManager(), collectionNode, [
ColorByOptionKeys.CHARGE,
ColorByOptionKeys.MOM,
]);
}
}

Expand Down

0 comments on commit 595d9e5

Please sign in to comment.