Skip to content

Commit

Permalink
Enabled multi-shape selector
Browse files Browse the repository at this point in the history
  • Loading branch information
ceriottm authored and Luthaf committed Aug 29, 2023
1 parent da0cbc9 commit 44983ac
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 57 deletions.
44 changes: 33 additions & 11 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Settings } from './dataset';
* Possible HTML attributes to attach to a setting
*/
// this is mostly to catch typo early. Feel free to add more!
type Attribute = 'value' | 'checked' | 'innerText';
type Attribute = 'value' | 'checked' | 'innerText' | 'options';

/// Type mapping for options
interface OptionsTypeMap {
Expand Down Expand Up @@ -146,8 +146,17 @@ export class HTMLOption<T extends OptionsType> {
*/
public changed(origin: OptionModificationOrigin) {
for (const bound of this._boundList) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
(bound.element as any)[bound.attribute] = this._value;
if (bound.attribute === 'options') {
// options take a list of comma-separated values to allow multiple settings
const values = (this._value as string).split(',');
const element = bound.element as HTMLSelectElement;
for (const option of element.options) {
option.selected = values.includes(option.value);
}
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
(bound.element as any)[bound.attribute] = this._value;
}
}

for (const callback of this.onchange) {
Expand Down Expand Up @@ -175,14 +184,27 @@ export class HTMLOption<T extends OptionsType> {
}
element = element as HTMLElement;

const listener = (event: Event) => {
assert(event.target !== null);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
this._update((event.target as any)[attribute].toString(), 'DOM');
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
(element as any)[attribute] = this._value;
let listener: (event: Event) => void;
if (attribute === 'options') {
listener = (event: Event) => {
// we need a special handler for multi-select options
assert(event.target !== null);
const element = event.target as HTMLSelectElement;
const values: string[] = Array.from(element.options)
.filter((option) => option.selected)
.map((option) => option.value);

this._update(values.toString(), 'DOM');
};
} else {
listener = (event: Event) => {
assert(event.target !== null);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
this._update((event.target as any)[attribute].toString(), 'DOM');
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
(element as any)[attribute] = this._value;
}
element.addEventListener('change', listener);

this._boundList.push({ element, attribute, listener });
Expand Down
10 changes: 8 additions & 2 deletions src/structure/options.html.in
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,14 @@
</div>
<div class="chsp-hide-if-no-shapes" style="margin-top: 1em">
<div class="input-group input-group-sm">
<label class="input-group-text" for="shapes" style="width: 5em">Shapes:</label>
<select id="shapes" class="form-select" title="which shape to show for the particle"></select>
<label
class="input-group-text"
for="shapes"
style="width: 5em"
title="which shapes to display; hold CTRL/CMD to select multiple shapes"
>Shapes:</label
>
<select id="shapes" class="form-select" multiple></select>
</div>
</div>

Expand Down
97 changes: 53 additions & 44 deletions src/structure/viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,12 +433,15 @@ export class MoleculeViewer {

const selectShape = this._options.getModalElement<HTMLSelectElement>('shapes');
selectShape.options.length = 0;
selectShape.options.add(new Option('off', ''));
for (const key of Object.keys(structure['shapes'])) {
selectShape.options.add(new Option(key, key));
}

this._options.shape.bind(selectShape, 'value');
// leave space for up to 3 shapes in the settings, the other one
// will be accessible with a scrollbar
selectShape.size = Math.min(Object.keys(structure['shapes']).length, 3);

this._options.shape.bind(selectShape, 'options');
}

this._updateStyle();
Expand Down Expand Up @@ -916,52 +919,58 @@ export class MoleculeViewer {
assert(this._current.atomLabels.length === 0);

const structure = this._current.structure;

assert(!(structure.shapes === undefined));
const current_shape = structure.shapes[this._options.shape.value];
assert(!(current_shape === undefined));

const supercell_a = this._options.supercell[0].value;
const supercell_b = this._options.supercell[1].value;
const supercell_c = this._options.supercell[2].value;
let cell = this._current.structure.cell;
const active_shapes = this._options.shape.value.split(',');

if ((supercell_a > 1 || supercell_b > 1 || supercell_c > 1) && cell === undefined) {
return;
} else if (cell === undefined) {
cell = [1, 0, 0, 0, 1, 0, 0, 0, 1];
}
for (const shape of active_shapes) {
if (shape === '') {
continue;
}
assert(shape in structure.shapes);
const current_shape = structure.shapes[shape];
const supercell_a = this._options.supercell[0].value;
const supercell_b = this._options.supercell[1].value;
const supercell_c = this._options.supercell[2].value;
let cell = this._current.structure.cell;

if ((supercell_a > 1 || supercell_b > 1 || supercell_c > 1) && cell === undefined) {
return;
} else if (cell === undefined) {
cell = [1, 0, 0, 0, 1, 0, 0, 0, 1];
}

for (let a = 0; a < supercell_a; a++) {
for (let b = 0; b < supercell_b; b++) {
for (let c = 0; c < supercell_c; c++) {
for (let i = 0; i < structure.size; i++) {
const name = structure.names[i];
const position: [number, number, number] = [
structure.x[i] + a * cell[0] + b * cell[3] + c * cell[6],
structure.y[i] + a * cell[1] + b * cell[4] + c * cell[7],
structure.z[i] + a * cell[2] + b * cell[5] + c * cell[8],
];

if (current_shape[i].kind === 'ellipsoid') {
const data = current_shape[i] as unknown as EllipsoidData;
const shape = new Ellipsoid(position, data);
this._viewer.addCustom(
shape.outputTo3Dmol($3Dmol.elementColors.Jmol[name] || 0x000000)
);
} else if (current_shape[i].kind === 'custom') {
const data = current_shape[i] as unknown as CustomShapeData;
const shape = new CustomShape(position, data);
this._viewer.addCustom(
shape.outputTo3Dmol($3Dmol.elementColors.Jmol[name] || 0x000000)
);
} else {
assert(current_shape[i].kind === 'sphere');
const data = current_shape[i] as unknown as SphereData;
const shape = new Sphere(position, data);
this._viewer.addCustom(
shape.outputTo3Dmol($3Dmol.elementColors.Jmol[name] || 0x000000)
);
for (let a = 0; a < supercell_a; a++) {
for (let b = 0; b < supercell_b; b++) {
for (let c = 0; c < supercell_c; c++) {
for (let i = 0; i < structure.size; i++) {
const name = structure.names[i];
const position: [number, number, number] = [
structure.x[i] + a * cell[0] + b * cell[3] + c * cell[6],
structure.y[i] + a * cell[1] + b * cell[4] + c * cell[7],
structure.z[i] + a * cell[2] + b * cell[5] + c * cell[8],
];

if (current_shape[i].kind === 'ellipsoid') {
const data = current_shape[i] as unknown as EllipsoidData;
const shape = new Ellipsoid(position, data);
this._viewer.addCustom(
shape.outputTo3Dmol($3Dmol.elementColors.Jmol[name] || 0x000000)
);
} else if (current_shape[i].kind === 'custom') {
const data = current_shape[i] as unknown as CustomShapeData;
const shape = new CustomShape(position, data);
this._viewer.addCustom(
shape.outputTo3Dmol($3Dmol.elementColors.Jmol[name] || 0x000000)
);
} else {
assert(current_shape[i].kind === 'sphere');
const data = current_shape[i] as unknown as SphereData;
const shape = new Sphere(position, data);
this._viewer.addCustom(
shape.outputTo3Dmol($3Dmol.elementColors.Jmol[name] || 0x000000)
);
}
}
}
}
Expand Down

0 comments on commit 44983ac

Please sign in to comment.