diff --git a/src/atoms/AtomsViewer.js b/src/atoms/AtomsViewer.js index e1b57b0..6af7013 100644 --- a/src/atoms/AtomsViewer.js +++ b/src/atoms/AtomsViewer.js @@ -36,7 +36,7 @@ class AtomsViewer { this._showBondedAtoms = viewerSettings._showBondedAtoms; this._showCell = viewerSettings._showCell; this._boundary = viewerSettings._boundary; - this.atomScale = viewerSettings.atomScale; + this._atomScale = viewerSettings._atomScale; this.backgroundColor = viewerSettings.backgroundColor; this._selectedAtomsIndices = new Array(); // Store selected atoms this.debug = viewerSettings.debug; @@ -198,6 +198,7 @@ class AtomsViewer { this._cell = null; this._atoms = null; this._currentFrame = 0; + this.selectedAtomsIndices = []; // set cell this.cellManager.cell = this.atoms.cell; // initialize the bond settings @@ -255,64 +256,7 @@ class AtomsViewer { set modelStyle(newValue) { newValue = parseInt(newValue); this.logger.debug("updateModelStyle: ", newValue); - if (this.selectedAtomsIndices.length > 0) { - if (newValue === 0) { - this.selectedAtomsIndices.forEach((atomIndex) => { - this.atomScales[atomIndex] = 1; - this.modelSticks[atomIndex] = newValue; - this.modelPolyhedras[atomIndex] = 0; - }); - } else if (newValue === 1) { - this.selectedAtomsIndices.forEach((atomIndex) => { - this.atomScales[atomIndex] = 0.4; - this.modelSticks[atomIndex] = newValue; - this.modelPolyhedras[atomIndex] = 0; - }); - } else if (newValue === 2) { - this.selectedAtomsIndices.forEach((atomIndex) => { - this.atomScales[atomIndex] = 0.4; - this.modelSticks[atomIndex] = newValue; - this.modelPolyhedras[atomIndex] = 1; - }); - } else if (newValue === 3) { - this.selectedAtomsIndices.forEach((atomIndex) => { - this.atomScales[atomIndex] = 0; - this.modelSticks[atomIndex] = newValue; - this.modelPolyhedras[atomIndex] = 0; - }); - } else if (newValue === 4) { - this.selectedAtomsIndices.forEach((atomIndex) => { - this.atomScales[atomIndex] = 0; - this.modelSticks[atomIndex] = newValue; - this.modelPolyhedras[atomIndex] = 0; - }); - } - } else { - this._modelStyle = parseInt(newValue); - // clear this.models - this.modelSticks = new Array(this.atoms.getAtomsCount()).fill(0); - this.modelPolyhedras = new Array(this.atoms.getAtomsCount()).fill(0); - if (this._modelStyle === 0) { - this.atomScales = new Array(this.atoms.getAtomsCount()).fill(1); - } else if (this._modelStyle === 1) { - this.atomScales = new Array(this.atoms.getAtomsCount()).fill(0.4); - this.modelSticks = new Array(this.atoms.getAtomsCount()).fill(1); - } else if (this._modelStyle === 2) { - this.atomScales = new Array(this.atoms.getAtomsCount()).fill(0.4); - this.modelSticks = new Array(this.atoms.getAtomsCount()).fill(2); - this.modelPolyhedras = new Array(this.atoms.getAtomsCount()).fill(1); - } else if (this._modelStyle === 3) { - this.atomScales = new Array(this.atoms.getAtomsCount()).fill(0); - this.modelSticks = new Array(this.atoms.getAtomsCount()).fill(3); - } else if (this._modelStyle === 4) { - this.atomScales = new Array(this.atoms.getAtomsCount()).fill(0); - this.modelSticks = new Array(this.atoms.getAtomsCount()).fill(4); - } - } - // avoid the recursive loop - if (this.guiManager.modelStyleController && this.guiManager.modelStyleController.getValue() !== newValue) { - this.guiManager.modelStyleController.setValue(newValue); // Update the GUI - } + this.updateModelStyles(newValue); this.weas.eventHandlers.dispatchViewerUpdated({ modelStyle: newValue }); } @@ -321,14 +265,13 @@ class AtomsViewer { } set radiusType(newValue) { - this._radiusType = newValue; - if (this.guiManager.radiusTypeController && this.guiManager.radiusTypeController.getValue() !== newValue) { - this.guiManager.radiusTypeController.setValue(newValue); // Update the GUI + if (this._radiusType !== newValue) { + this._radiusType = newValue; + this.weas.eventHandlers.dispatchViewerUpdated({ radiusType: newValue }); + this.atomManager.init(); + this.bondManager.init(); + this.polyhedraManager.init(); } - this.weas.eventHandlers.dispatchViewerUpdated({ radiusType: newValue }); - this.atomManager.init(); - this.bondManager.init(); - this.polyhedraManager.init(); } get colorBy() { @@ -447,6 +390,18 @@ class AtomsViewer { this.weas.eventHandlers.dispatchViewerUpdated({ showBondedAtoms: newValue }); } + get atomScale() { + return this._atomScale; + } + + set atomScale(newValue) { + if (this._atomScale !== newValue) { + this._atomScale = newValue; + this.weas.eventHandlers.dispatchViewerUpdated({ atomScale: newValue }); + this.atomManager.updateAtomScale(newValue); + } + } + get atomScales() { return this._atomScales; } @@ -728,6 +683,63 @@ class AtomsViewer { atoms.newAttribute(name, values, domain); }); } + + updateModelStyles(newValue) { + if (this.selectedAtomsIndices.length > 0) { + if (newValue === 0) { + this.selectedAtomsIndices.forEach((atomIndex) => { + this.atomScales[atomIndex] = 1; + this.modelSticks[atomIndex] = newValue; + this.modelPolyhedras[atomIndex] = 0; + }); + } else if (newValue === 1) { + this.selectedAtomsIndices.forEach((atomIndex) => { + this.atomScales[atomIndex] = 0.4; + this.modelSticks[atomIndex] = newValue; + this.modelPolyhedras[atomIndex] = 0; + }); + } else if (newValue === 2) { + this.selectedAtomsIndices.forEach((atomIndex) => { + this.atomScales[atomIndex] = 0.4; + this.modelSticks[atomIndex] = newValue; + this.modelPolyhedras[atomIndex] = 1; + }); + } else if (newValue === 3) { + this.selectedAtomsIndices.forEach((atomIndex) => { + this.atomScales[atomIndex] = 0; + this.modelSticks[atomIndex] = newValue; + this.modelPolyhedras[atomIndex] = 0; + }); + } else if (newValue === 4) { + this.selectedAtomsIndices.forEach((atomIndex) => { + this.atomScales[atomIndex] = 0; + this.modelSticks[atomIndex] = newValue; + this.modelPolyhedras[atomIndex] = 0; + }); + } + } else { + // clear this.models + this._modelStyle = newValue; + this.modelSticks = new Array(this.atoms.getAtomsCount()).fill(0); + this.modelPolyhedras = new Array(this.atoms.getAtomsCount()).fill(0); + if (newValue === 0) { + this.atomScales = new Array(this.atoms.getAtomsCount()).fill(1); + } else if (newValue === 1) { + this.atomScales = new Array(this.atoms.getAtomsCount()).fill(0.4); + this.modelSticks = new Array(this.atoms.getAtomsCount()).fill(1); + } else if (newValue === 2) { + this.atomScales = new Array(this.atoms.getAtomsCount()).fill(0.4); + this.modelSticks = new Array(this.atoms.getAtomsCount()).fill(2); + this.modelPolyhedras = new Array(this.atoms.getAtomsCount()).fill(1); + } else if (newValue === 3) { + this.atomScales = new Array(this.atoms.getAtomsCount()).fill(0); + this.modelSticks = new Array(this.atoms.getAtomsCount()).fill(3); + } else if (newValue === 4) { + this.atomScales = new Array(this.atoms.getAtomsCount()).fill(0); + this.modelSticks = new Array(this.atoms.getAtomsCount()).fill(4); + } + } + } } export { AtomsViewer }; diff --git a/src/atoms/atomsGui.js b/src/atoms/atomsGui.js index bd8c18c..4b562eb 100644 --- a/src/atoms/atomsGui.js +++ b/src/atoms/atomsGui.js @@ -17,6 +17,11 @@ class AtomsGUI { this.div = document.createElement("div"); this.viewer.tjs.containerElement.appendChild(this.div); + // Listen to viewer events + this.viewer.tjs.containerElement.addEventListener("viewerUpdated", (event) => { + this.updateViewerControl(event.detail); + }); + if (this.guiConfig.controls.atomsControl) { this.addAtomsControl(); } @@ -50,12 +55,12 @@ class AtomsGUI { // Radius Type Control this.radiusTypeController = atomsFolder - .add({ radiusType: this.viewer.radiusType }, "radiusType", radiusTypes) + .add(this.viewer, "radiusType", radiusTypes) + .name("Radius Type") .onChange((value) => { this.viewer.radiusType = value; this.viewer.drawModels(); - }) - .name("Radius Type"); + }); // Atom Label Control this.atomLabelTypeController = atomsFolder @@ -75,7 +80,12 @@ class AtomsGUI { .name("Material Type"); // Atom Scale Control - atomsFolder.add(this.viewer, "atomScale", 0.1, 2.0).onChange(this.viewer.atomManager.updateAtomScale.bind(this.viewer.atomManager)).name("Atom Scale"); + this.atomScaleController = atomsFolder + .add(this.viewer, "atomScale", 0.1, 2.0) + .name("Atom Scale") + .onChange((value) => { + this.viewer.atomScale = value; // Viewer setter handles the update + }); // Show Cell Control this.showCellController = atomsFolder @@ -325,6 +335,74 @@ class AtomsGUI { legendContainer.style.left = position.includes("left") ? "10px" : ""; legendContainer.style.right = position.includes("right") ? "10px" : ""; } + + updateViewerControl(detail) { + // detail is a object containing the updated viewer properties + // Update the GUI controls with the new values + Object.entries(detail).forEach(([key, value]) => { + switch (key) { + case "modelStyle": + this.updateModelStyle(value); + break; + case "radiusType": + this.updateRadiusType(value); + break; + case "atomLabelType": + // this.updateAtomLabelType(value); + break; + case "materialType": + // this.updateMaterialType(value); + break; + case "atomScale": + this.updateAtomScale(value); + break; + case "showCell": + // this.updateShowCell(value); + break; + case "showBondedAtoms": + // this.updateShowBondedAtoms(value); + break; + case "colorBy": + // this.updateColorBy(value); + break; + case "colorType": + // this.updateColorType(value); + break; + case "backgroundColor": + // this.updateBackgroundColor(value); + break; + case "isPlaying": + // this.updateIsPlaying(value); + break; + case "currentFrame": + // this.updateCurrentFrame(value); + break; + case "boundary": + // this.updateBoundary(value); + break; + default: + break; + } + }); + } + updateAtomScale(newValue) { + if (this.atomScaleController && this.atomScaleController.getValue() !== newValue) { + this.atomScaleController.setValue(newValue); + } + } + + updateModelStyle(newValue) { + if (this.modelStyleController && this.modelStyleController.getValue() !== newValue) { + this.modelStyleController.setValue(newValue); + this.viewer.drawModels(); + } + } + + updateRadiusType(newValue) { + if (this.radiusTypeController && this.radiusTypeController.getValue() !== newValue) { + this.radiusTypeController.setValue(newValue); + } + } } export { AtomsGUI }; diff --git a/src/atoms/plugins/atom.js b/src/atoms/plugins/atom.js index dfc54b6..c029d98 100644 --- a/src/atoms/plugins/atom.js +++ b/src/atoms/plugins/atom.js @@ -186,27 +186,37 @@ export class AtomManager { } } // Method to update the scale of atoms - updateAtomScale() { + updateAtomScale(value) { + if (value === undefined) { + value = this.viewer.atomScale; + } let mesh = this.meshes["atom"]; - this.updateMeshScale(mesh, this.viewer.atoms.symbols, this.viewer.atomScale); + // only update the selected atoms if there are selected atoms + const indices = this.viewer.selectedAtomsIndices.length > 0 ? this.viewer.selectedAtomsIndices : [...Array(this.viewer.atoms.positions.length).keys()]; + this.updateMeshScale(mesh, indices, this.viewer.atoms.symbols, value); // update the boundary atoms mesh = this.meshes["image"]; if (mesh) { const symbols = []; + const imageAtomsIndices = []; for (let i = 0; i < this.viewer.imageAtomsList.length; i++) { symbols.push(this.viewer.atoms.symbols[this.viewer.imageAtomsList[i][0]]); + if (this.viewer.selectedAtomsIndices.includes(this.viewer.imageAtomsList[i][0])) { + imageAtomsIndices.push(i); + } } - this.updateMeshScale(mesh, symbols, this.viewer.atomScale); + this.updateMeshScale(mesh, imageAtomsIndices, symbols, value); } + this.viewer.tjs.render(); } - updateMeshScale(mesh, symbols, atomScale) { + updateMeshScale(mesh, indices, symbols, atomScale) { const position = new THREE.Vector3(); const rotation = new THREE.Quaternion(); const scale = new THREE.Vector3(); console.log("settings: ", this.settings); - for (let i = 0; i < mesh.count; i++) { + indices.forEach((i) => { const instanceMatrix = new THREE.Matrix4(); console.log("symbols[i]: ", symbols[i]); const radius = this.settings[symbols[i]].radius || 1; @@ -218,7 +228,7 @@ export class AtomManager { // Recompose the matrix with the new scale instanceMatrix.compose(position, rotation, scale); mesh.setMatrixAt(i, instanceMatrix); - } + }); mesh.instanceMatrix.needsUpdate = true; } } diff --git a/src/atoms/plugins/bond.js b/src/atoms/plugins/bond.js index b656bbc..0921bbb 100644 --- a/src/atoms/plugins/bond.js +++ b/src/atoms/plugins/bond.js @@ -5,6 +5,7 @@ import { elementsWithPolyhedra, covalentRadii, elementColors, default_bond_pairs import { convertColor } from "../utils.js"; import { kdTree } from "../../geometry/kdTree.js"; import { searchBoundary } from "./boundary.js"; +import { clearObject } from "../../utils.js"; // default bond radius export const defaultBondRadius = 0.1; @@ -42,7 +43,7 @@ export class BondManager { this.viewer = viewer; this.scene = this.viewer.tjs.scene; this.settings = {}; - this.meshes = []; + this.meshes = {}; this.hideLongBonds = hideLongBonds; this.showHydrogenBonds = showHydrogenBonds; this.bondRadius = 0.1; @@ -134,10 +135,12 @@ export class BondManager { clearMeshes() { /* Remove highlighted atom meshes from the selectedAtomsMesh group */ - this.meshes.forEach((mesh) => { - clearObject(this.scene, mesh); + Object.values(this.meshes).forEach((mesh) => { + if (mesh) { + clearObject(this.scene, mesh); + } }); - this.meshes = []; + this.meshes = {}; } drawBonds() { diff --git a/src/config.js b/src/config.js index d0d2bad..486a584 100644 --- a/src/config.js +++ b/src/config.js @@ -16,7 +16,7 @@ const defaultViewerSettings = { [0, 1], [0, 1], ], - atomScale: 0.4, // Default atom scale + _atomScale: 0.4, // Default atom scale backgroundColor: "#ffffff", // Default background color (white) logLevel: "warn", // Default log level };