@judah-silva/rnacanvas 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +19 -4
- package/dist/index.d.ts +19 -4
- package/dist/index.js +174 -117
- package/dist/index.mjs +174 -117
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -16,8 +16,9 @@ declare class Residue extends Group<MeshObject> {
|
|
|
16
16
|
/**
|
|
17
17
|
* Cretes a material with the given color and sets it to the mesh
|
|
18
18
|
* @param color String in the format of #RRGGBB
|
|
19
|
+
* @param highlight Whether to apply a highlight effect to the residue
|
|
19
20
|
*/
|
|
20
|
-
colorResidue(color: string): void;
|
|
21
|
+
colorResidue(color: string, highlight?: boolean): void;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -34,10 +35,15 @@ declare class MeshObject {
|
|
|
34
35
|
applyHighlight(): void;
|
|
35
36
|
resetHighlight(): void;
|
|
36
37
|
/**
|
|
37
|
-
*
|
|
38
|
+
* Creates a material with the given color and sets it to the mesh
|
|
38
39
|
* @param color String in the format of #RRGGBB
|
|
39
40
|
*/
|
|
40
41
|
createAndSetMaterial(color: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Sets the material of the mesh object to the given color
|
|
44
|
+
* @param color String in the format of #RRGGBB
|
|
45
|
+
*/
|
|
46
|
+
colorMaterial(color: string): void;
|
|
41
47
|
setNewMesh(mesh: Mesh): MeshObject;
|
|
42
48
|
get mesh(): Mesh;
|
|
43
49
|
get uuid(): string;
|
|
@@ -300,12 +306,21 @@ declare class RenderScene {
|
|
|
300
306
|
private _eventManager;
|
|
301
307
|
private _isDisposed;
|
|
302
308
|
isRunning: boolean;
|
|
309
|
+
/**
|
|
310
|
+
*
|
|
311
|
+
* @param canvas HTML Canvas Element
|
|
312
|
+
* @param hexColor Color in the format of #RRGGBB
|
|
313
|
+
* @param cameraPositionZ Z position of the camera
|
|
314
|
+
* @param renderWidth Width of the render window
|
|
315
|
+
* @param renderHeight Height of the render window
|
|
316
|
+
*/
|
|
303
317
|
constructor(canvas: HTMLCanvasElement, hexColor: string, cameraPositionZ: number, renderWidth: number, renderHeight: number);
|
|
304
318
|
start(): void;
|
|
305
319
|
stop(): void;
|
|
306
320
|
dispose(): void;
|
|
307
321
|
add(motif: Motif): void;
|
|
308
322
|
remove(motif: Motif): void;
|
|
323
|
+
removeAll(): void;
|
|
309
324
|
setBackgroundColor(hexColor: string): void;
|
|
310
325
|
private _reattachToScene;
|
|
311
326
|
private _handleResize;
|
|
@@ -469,8 +484,8 @@ declare class CanvasDataManager {
|
|
|
469
484
|
private static _listeners;
|
|
470
485
|
static get selectedMotifIds(): Set<string>;
|
|
471
486
|
static setSelectedMotifIds(selectedMotifIds: Set<string>): void;
|
|
472
|
-
static get lockedMotifIds(): string
|
|
473
|
-
static setLockedMotifIds(lockedMotifIds: string
|
|
487
|
+
static get lockedMotifIds(): Set<string>;
|
|
488
|
+
static setLockedMotifIds(lockedMotifIds: Set<string>): void;
|
|
474
489
|
static get hardLockedMotifIds(): string[];
|
|
475
490
|
static setHardLockedMotifIds(hardLockedMotifIds: string[]): void;
|
|
476
491
|
static get scoreRMSD(): ScoreInfo[][];
|
package/dist/index.d.ts
CHANGED
|
@@ -16,8 +16,9 @@ declare class Residue extends Group<MeshObject> {
|
|
|
16
16
|
/**
|
|
17
17
|
* Cretes a material with the given color and sets it to the mesh
|
|
18
18
|
* @param color String in the format of #RRGGBB
|
|
19
|
+
* @param highlight Whether to apply a highlight effect to the residue
|
|
19
20
|
*/
|
|
20
|
-
colorResidue(color: string): void;
|
|
21
|
+
colorResidue(color: string, highlight?: boolean): void;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -34,10 +35,15 @@ declare class MeshObject {
|
|
|
34
35
|
applyHighlight(): void;
|
|
35
36
|
resetHighlight(): void;
|
|
36
37
|
/**
|
|
37
|
-
*
|
|
38
|
+
* Creates a material with the given color and sets it to the mesh
|
|
38
39
|
* @param color String in the format of #RRGGBB
|
|
39
40
|
*/
|
|
40
41
|
createAndSetMaterial(color: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Sets the material of the mesh object to the given color
|
|
44
|
+
* @param color String in the format of #RRGGBB
|
|
45
|
+
*/
|
|
46
|
+
colorMaterial(color: string): void;
|
|
41
47
|
setNewMesh(mesh: Mesh): MeshObject;
|
|
42
48
|
get mesh(): Mesh;
|
|
43
49
|
get uuid(): string;
|
|
@@ -300,12 +306,21 @@ declare class RenderScene {
|
|
|
300
306
|
private _eventManager;
|
|
301
307
|
private _isDisposed;
|
|
302
308
|
isRunning: boolean;
|
|
309
|
+
/**
|
|
310
|
+
*
|
|
311
|
+
* @param canvas HTML Canvas Element
|
|
312
|
+
* @param hexColor Color in the format of #RRGGBB
|
|
313
|
+
* @param cameraPositionZ Z position of the camera
|
|
314
|
+
* @param renderWidth Width of the render window
|
|
315
|
+
* @param renderHeight Height of the render window
|
|
316
|
+
*/
|
|
303
317
|
constructor(canvas: HTMLCanvasElement, hexColor: string, cameraPositionZ: number, renderWidth: number, renderHeight: number);
|
|
304
318
|
start(): void;
|
|
305
319
|
stop(): void;
|
|
306
320
|
dispose(): void;
|
|
307
321
|
add(motif: Motif): void;
|
|
308
322
|
remove(motif: Motif): void;
|
|
323
|
+
removeAll(): void;
|
|
309
324
|
setBackgroundColor(hexColor: string): void;
|
|
310
325
|
private _reattachToScene;
|
|
311
326
|
private _handleResize;
|
|
@@ -469,8 +484,8 @@ declare class CanvasDataManager {
|
|
|
469
484
|
private static _listeners;
|
|
470
485
|
static get selectedMotifIds(): Set<string>;
|
|
471
486
|
static setSelectedMotifIds(selectedMotifIds: Set<string>): void;
|
|
472
|
-
static get lockedMotifIds(): string
|
|
473
|
-
static setLockedMotifIds(lockedMotifIds: string
|
|
487
|
+
static get lockedMotifIds(): Set<string>;
|
|
488
|
+
static setLockedMotifIds(lockedMotifIds: Set<string>): void;
|
|
474
489
|
static get hardLockedMotifIds(): string[];
|
|
475
490
|
static setHardLockedMotifIds(hardLockedMotifIds: string[]): void;
|
|
476
491
|
static get scoreRMSD(): ScoreInfo[][];
|
package/dist/index.js
CHANGED
|
@@ -328,10 +328,14 @@ var Residue = class extends Group {
|
|
|
328
328
|
/**
|
|
329
329
|
* Cretes a material with the given color and sets it to the mesh
|
|
330
330
|
* @param color String in the format of #RRGGBB
|
|
331
|
+
* @param highlight Whether to apply a highlight effect to the residue
|
|
331
332
|
*/
|
|
332
|
-
colorResidue(color) {
|
|
333
|
+
colorResidue(color, highlight = false) {
|
|
333
334
|
this._children.forEach((child) => {
|
|
334
|
-
child.
|
|
335
|
+
child.colorMaterial(color);
|
|
336
|
+
if (highlight) {
|
|
337
|
+
child.applyHighlight();
|
|
338
|
+
}
|
|
335
339
|
});
|
|
336
340
|
}
|
|
337
341
|
};
|
|
@@ -363,23 +367,34 @@ var MeshObject = class {
|
|
|
363
367
|
}
|
|
364
368
|
applyHighlight() {
|
|
365
369
|
const mat = this._mesh.material;
|
|
366
|
-
mat.emissiveColor = mat.diffuseColor.scale(0.
|
|
370
|
+
mat.emissiveColor = mat.diffuseColor.scale(0.6);
|
|
367
371
|
}
|
|
368
372
|
resetHighlight() {
|
|
369
373
|
const mat = this._mesh.material;
|
|
370
374
|
mat.emissiveColor = import_core7.Color3.Black();
|
|
371
375
|
}
|
|
372
376
|
/**
|
|
373
|
-
*
|
|
377
|
+
* Creates a material with the given color and sets it to the mesh
|
|
374
378
|
* @param color String in the format of #RRGGBB
|
|
375
379
|
*/
|
|
376
380
|
createAndSetMaterial(color) {
|
|
377
381
|
const mat = new import_core7.StandardMaterial("mat");
|
|
378
|
-
const color3 = import_core7.Color3.FromHexString(
|
|
382
|
+
const color3 = import_core7.Color3.FromHexString(`${color.replace(/^0x/i, "")}`);
|
|
379
383
|
mat.diffuseColor = color3;
|
|
380
384
|
mat.specularColor = color3;
|
|
385
|
+
mat.backFaceCulling = false;
|
|
381
386
|
this._mesh.material = mat;
|
|
382
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* Sets the material of the mesh object to the given color
|
|
390
|
+
* @param color String in the format of #RRGGBB
|
|
391
|
+
*/
|
|
392
|
+
colorMaterial(color) {
|
|
393
|
+
const mat = this._mesh.material;
|
|
394
|
+
const color3 = import_core7.Color3.FromHexString(`${color.replace(/^0x/i, "")}`);
|
|
395
|
+
mat.diffuseColor = color3;
|
|
396
|
+
mat.specularColor = color3;
|
|
397
|
+
}
|
|
383
398
|
setNewMesh(mesh) {
|
|
384
399
|
this._mesh = mesh;
|
|
385
400
|
return this;
|
|
@@ -603,9 +618,19 @@ var EventManager = class {
|
|
|
603
618
|
canceled: false,
|
|
604
619
|
timestamp: performance.now()
|
|
605
620
|
};
|
|
606
|
-
if (keyboardInfo.type === import_core8.KeyboardEventTypes.KEYDOWN) {
|
|
621
|
+
if (keyboardInfo.type === import_core8.KeyboardEventTypes.KEYDOWN && /^[wasdqeWASD]$/.test(event.key)) {
|
|
622
|
+
if (event.key.charCodeAt(0) >= 97) {
|
|
623
|
+
this._activeKeys.delete(event.key.toUpperCase());
|
|
624
|
+
} else {
|
|
625
|
+
this._activeKeys.delete(event.key.toLowerCase());
|
|
626
|
+
}
|
|
607
627
|
this._activeKeys.add(event.key);
|
|
608
628
|
} else if (keyboardInfo.type === import_core8.KeyboardEventTypes.KEYUP) {
|
|
629
|
+
if (event.key.charCodeAt(0) >= 97) {
|
|
630
|
+
this._activeKeys.delete(event.key.toUpperCase());
|
|
631
|
+
} else {
|
|
632
|
+
this._activeKeys.delete(event.key.toLowerCase());
|
|
633
|
+
}
|
|
609
634
|
this._activeKeys.delete(event.key);
|
|
610
635
|
}
|
|
611
636
|
if (this._activeKeys.has("w")) keyboardEvent.rotationAxis.add(new Vec3(-1, 0, 0));
|
|
@@ -667,12 +692,20 @@ var RenderScene = class {
|
|
|
667
692
|
// State variables
|
|
668
693
|
_isDisposed = false;
|
|
669
694
|
isRunning = false;
|
|
695
|
+
/**
|
|
696
|
+
*
|
|
697
|
+
* @param canvas HTML Canvas Element
|
|
698
|
+
* @param hexColor Color in the format of #RRGGBB
|
|
699
|
+
* @param cameraPositionZ Z position of the camera
|
|
700
|
+
* @param renderWidth Width of the render window
|
|
701
|
+
* @param renderHeight Height of the render window
|
|
702
|
+
*/
|
|
670
703
|
constructor(canvas, hexColor, cameraPositionZ, renderWidth, renderHeight) {
|
|
671
704
|
this._canvas = canvas;
|
|
672
705
|
this._engine = new import_core9.Engine(this._canvas, true);
|
|
673
706
|
this._engine.setSize(renderWidth, renderHeight);
|
|
674
707
|
this._scene = new import_core9.Scene(this._engine);
|
|
675
|
-
this._scene.clearColor = import_core9.Color4.FromHexString(`${hexColor.replace(/^0x
|
|
708
|
+
this._scene.clearColor = import_core9.Color4.FromHexString(`${hexColor.replace(/^0x/i, "")}`);
|
|
676
709
|
this._camera = new import_core9.UniversalCamera("camera", new import_core9.Vector3(0, 0, cameraPositionZ));
|
|
677
710
|
this._camera.setTarget(new import_core9.Vector3(0, 0, 0));
|
|
678
711
|
this._camera.mode = import_core9.Camera.ORTHOGRAPHIC_CAMERA;
|
|
@@ -684,7 +717,6 @@ var RenderScene = class {
|
|
|
684
717
|
const light = new import_core9.HemisphericLight("light", import_core9.Vector3.Up(), this._scene);
|
|
685
718
|
light.intensity = 1.25;
|
|
686
719
|
this._eventManager = new EventManager();
|
|
687
|
-
window.addEventListener("resize", this._handleResize.bind(this));
|
|
688
720
|
}
|
|
689
721
|
// Start the render loop
|
|
690
722
|
start() {
|
|
@@ -725,7 +757,6 @@ var RenderScene = class {
|
|
|
725
757
|
// Stop and dispose of all resources
|
|
726
758
|
dispose() {
|
|
727
759
|
this.stop();
|
|
728
|
-
window.removeEventListener("resize", this._handleResize);
|
|
729
760
|
this._eventManager.dispose();
|
|
730
761
|
this._scene.dispose();
|
|
731
762
|
this._engine.dispose();
|
|
@@ -745,10 +776,18 @@ var RenderScene = class {
|
|
|
745
776
|
return;
|
|
746
777
|
}
|
|
747
778
|
this._children.delete(motif.uuid);
|
|
748
|
-
|
|
779
|
+
motif.node.dispose(false, true);
|
|
780
|
+
}
|
|
781
|
+
removeAll() {
|
|
782
|
+
this._scene.meshes.slice().forEach((mesh) => {
|
|
783
|
+
if (mesh && this._scene.getMeshById(mesh.id)) {
|
|
784
|
+
this._scene.removeMesh(mesh);
|
|
785
|
+
}
|
|
786
|
+
});
|
|
787
|
+
this._children.clear();
|
|
749
788
|
}
|
|
750
789
|
setBackgroundColor(hexColor) {
|
|
751
|
-
this._scene.clearColor = import_core9.Color4.FromHexString(`${hexColor.replace(/^0x
|
|
790
|
+
this._scene.clearColor = import_core9.Color4.FromHexString(`${hexColor.replace(/^0x/i, "")}`);
|
|
752
791
|
}
|
|
753
792
|
_reattachToScene(node, currObj) {
|
|
754
793
|
node._scene = this._scene;
|
|
@@ -762,7 +801,7 @@ var RenderScene = class {
|
|
|
762
801
|
geo?.applyToMesh(mesh);
|
|
763
802
|
mesh.material = mat;
|
|
764
803
|
currObj.setNewMesh(mesh);
|
|
765
|
-
node.dispose();
|
|
804
|
+
node.dispose(false, true);
|
|
766
805
|
}
|
|
767
806
|
if (!(currObj instanceof MeshObject)) {
|
|
768
807
|
currObj.children.forEach((childObj) => {
|
|
@@ -861,7 +900,7 @@ function getPoints(nucleotideData, includeAtoms) {
|
|
|
861
900
|
}
|
|
862
901
|
|
|
863
902
|
// src/3D/utils/GetMotif.ts
|
|
864
|
-
async function getMotif(motifName, motifMesh, motifColorHex = "
|
|
903
|
+
async function getMotif(motifName, motifMesh, motifColorHex = "#cc2900", includeAtoms = true) {
|
|
865
904
|
const motif = new Motif(`${motifName}_motif`);
|
|
866
905
|
for (const [key] of Object.entries(motifMesh)) {
|
|
867
906
|
const { vertices, indices } = getPoints(motifMesh[key], includeAtoms);
|
|
@@ -895,7 +934,7 @@ var CanvasAttributeTypes = /* @__PURE__ */ ((CanvasAttributeTypes2) => {
|
|
|
895
934
|
})(CanvasAttributeTypes || {});
|
|
896
935
|
var CanvasDataManager = class {
|
|
897
936
|
static _selectedMotifIds = /* @__PURE__ */ new Set();
|
|
898
|
-
static _lockedMotifIds =
|
|
937
|
+
static _lockedMotifIds = /* @__PURE__ */ new Set();
|
|
899
938
|
static _hardLockedMotifIds = [];
|
|
900
939
|
static _scoreRMSD = [];
|
|
901
940
|
static _kabschRMSD = [];
|
|
@@ -1152,28 +1191,27 @@ function Canvas({
|
|
|
1152
1191
|
}) {
|
|
1153
1192
|
const canvasRef = (0, import_react.useRef)(null);
|
|
1154
1193
|
const scene = (0, import_react.useRef)(null);
|
|
1155
|
-
const motifs = [];
|
|
1194
|
+
const motifs = (0, import_react.useRef)([]);
|
|
1156
1195
|
let hardLockedMotifIds = [];
|
|
1157
1196
|
motifProps.forEach((motifProp) => {
|
|
1158
|
-
motifs.push(motifProp.motif);
|
|
1159
1197
|
if (motifProp.locked) hardLockedMotifIds.push(motifProp.motif.uuid);
|
|
1160
1198
|
});
|
|
1161
1199
|
CanvasDataManager.setHardLockedMotifIds(hardLockedMotifIds);
|
|
1162
1200
|
const selectedMotifMeshState = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
1163
|
-
const lockedMotifIdState = (0, import_react.useRef)(
|
|
1201
|
+
const lockedMotifIdState = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
1164
1202
|
const [cursorStyle, setCursorStyle] = (0, import_react.useState)("auto");
|
|
1165
1203
|
const [selectedMotifIds, setSelectedmotifIds] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
1166
1204
|
const [scoreRMSD, setScoreRMSD] = (0, import_react.useState)([]);
|
|
1167
1205
|
const [kabschRMSD, setKabschRMSD] = (0, import_react.useState)([]);
|
|
1168
|
-
const [lockedMotifIds, setLockedMotifIds] = (0, import_react.useState)(
|
|
1206
|
+
const [lockedMotifIds, setLockedMotifIds] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
1169
1207
|
const addMotif = (motif) => {
|
|
1170
1208
|
if (selectedMotifMeshState.current.has(motif)) {
|
|
1171
1209
|
return;
|
|
1172
1210
|
}
|
|
1173
1211
|
const newSet = /* @__PURE__ */ new Set();
|
|
1174
|
-
for (let i = 0; i < motifs.length; i += 1) {
|
|
1175
|
-
if (selectedMotifMeshState.current.has(motifs[i]) || motifs[i].uuid === motif.uuid) {
|
|
1176
|
-
newSet.add(motifs[i].uuid);
|
|
1212
|
+
for (let i = 0; i < motifs.current.length; i += 1) {
|
|
1213
|
+
if (selectedMotifMeshState.current.has(motifs.current[i]) || motifs.current[i].uuid === motif.uuid) {
|
|
1214
|
+
newSet.add(motifs.current[i].uuid);
|
|
1177
1215
|
}
|
|
1178
1216
|
}
|
|
1179
1217
|
setSelectedmotifIds(newSet);
|
|
@@ -1191,7 +1229,7 @@ function Canvas({
|
|
|
1191
1229
|
});
|
|
1192
1230
|
};
|
|
1193
1231
|
function updateGlow() {
|
|
1194
|
-
motifs.forEach((motif) => {
|
|
1232
|
+
motifs.current.forEach((motif) => {
|
|
1195
1233
|
motif.children.forEach((residue) => {
|
|
1196
1234
|
residue.children.forEach((childMesh) => {
|
|
1197
1235
|
if (selectedMotifIds.has(motif.uuid)) {
|
|
@@ -1203,12 +1241,27 @@ function Canvas({
|
|
|
1203
1241
|
});
|
|
1204
1242
|
});
|
|
1205
1243
|
}
|
|
1244
|
+
function motifOutOfBounds(motif, deltaX, deltaY) {
|
|
1245
|
+
if (!canvasRef.current) {
|
|
1246
|
+
return false;
|
|
1247
|
+
}
|
|
1248
|
+
const canvasWidth = canvasRef.current.width;
|
|
1249
|
+
const canvasHeight = canvasRef.current.height;
|
|
1250
|
+
const left = -canvasWidth / 2;
|
|
1251
|
+
const right = canvasWidth / 2;
|
|
1252
|
+
const top = canvasHeight / 2;
|
|
1253
|
+
const bottom = -canvasHeight / 2;
|
|
1254
|
+
const newX = motif.position.x + deltaX;
|
|
1255
|
+
const newY = motif.position.y + deltaY;
|
|
1256
|
+
if (newX <= left || newX >= right || newY <= bottom || newY >= top) return true;
|
|
1257
|
+
return false;
|
|
1258
|
+
}
|
|
1206
1259
|
function onSelectMotif(event) {
|
|
1207
1260
|
if (event.type !== Events.EventType.OBJECT_SELECTED) {
|
|
1208
1261
|
return;
|
|
1209
1262
|
}
|
|
1210
1263
|
const { motif } = event;
|
|
1211
|
-
if (!motif || selectedMotifMeshState.current.has(motif)
|
|
1264
|
+
if (!motif || selectedMotifMeshState.current.has(motif)) {
|
|
1212
1265
|
return;
|
|
1213
1266
|
}
|
|
1214
1267
|
if (event.multiSelect && motif) {
|
|
@@ -1240,7 +1293,7 @@ function Canvas({
|
|
|
1240
1293
|
const deltaX = rawDeltaX / renderWidth * canvasRef.current.width;
|
|
1241
1294
|
const deltaY = rawDeltaY / renderHeight * canvasRef.current.height;
|
|
1242
1295
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1243
|
-
if (!lockedMotifIdState.current.
|
|
1296
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid) && !motifOutOfBounds(element, -deltaX, -deltaY)) {
|
|
1244
1297
|
element.translate(-deltaX, -deltaY, 0);
|
|
1245
1298
|
}
|
|
1246
1299
|
});
|
|
@@ -1253,11 +1306,11 @@ function Canvas({
|
|
|
1253
1306
|
if (scene.current) {
|
|
1254
1307
|
const angle = directionVec.length() / scene.current.renderWidth * (3 * Math.PI);
|
|
1255
1308
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1256
|
-
if (!lockedMotifIdState.current.
|
|
1309
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1257
1310
|
element.rotate(axisVec, angle);
|
|
1258
1311
|
}
|
|
1259
1312
|
});
|
|
1260
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1313
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1261
1314
|
}
|
|
1262
1315
|
}
|
|
1263
1316
|
}
|
|
@@ -1270,7 +1323,7 @@ function Canvas({
|
|
|
1270
1323
|
const zoomSpeed = 0.1;
|
|
1271
1324
|
const zoomDirection = event.originalEvent.deltaY > 0 ? -1 : 1;
|
|
1272
1325
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1273
|
-
if (!lockedMotifIdState.current.
|
|
1326
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid) && !(element.scale <= 1 && zoomDirection === -1) && !(element.scale >= 30 && zoomDirection === 1)) {
|
|
1274
1327
|
const scaleFactor = 1 + zoomDirection * zoomSpeed;
|
|
1275
1328
|
element.multiplyScalar(scaleFactor);
|
|
1276
1329
|
}
|
|
@@ -1298,19 +1351,19 @@ function Canvas({
|
|
|
1298
1351
|
}
|
|
1299
1352
|
const angle = event.rotationAxis.length() / 500 * (6 * Math.PI);
|
|
1300
1353
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1301
|
-
if (!lockedMotifIdState.current.
|
|
1354
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1302
1355
|
element.rotate(event.rotationAxis, angle);
|
|
1303
1356
|
}
|
|
1304
1357
|
});
|
|
1305
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1358
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1306
1359
|
}
|
|
1307
1360
|
function onKeyboardTranslate(event) {
|
|
1308
1361
|
if (event.translationDirection.equals(Vec3.Zero)) {
|
|
1309
1362
|
return;
|
|
1310
1363
|
}
|
|
1311
|
-
event.translationDirection.multiplyScalar(
|
|
1364
|
+
event.translationDirection.multiplyScalar(4.5);
|
|
1312
1365
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1313
|
-
if (!lockedMotifIdState.current.
|
|
1366
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid) && !motifOutOfBounds(element, event.translationDirection.x, event.translationDirection.y)) {
|
|
1314
1367
|
element.translate(
|
|
1315
1368
|
event.translationDirection.x,
|
|
1316
1369
|
event.translationDirection.y,
|
|
@@ -1323,10 +1376,10 @@ function Canvas({
|
|
|
1323
1376
|
if (!event.rotationAxis.equals(Vec3.Zero) || !event.translationDirection.equals(Vec3.Zero)) {
|
|
1324
1377
|
return;
|
|
1325
1378
|
}
|
|
1326
|
-
if (!/^[1-9]$/.test(event.key) || Number(event.key) > motifs.length) {
|
|
1379
|
+
if (!/^[1-9]$/.test(event.key) || Number(event.key) > motifs.current.length) {
|
|
1327
1380
|
return;
|
|
1328
1381
|
}
|
|
1329
|
-
const motif = motifs[Number(event.key) - 1];
|
|
1382
|
+
const motif = motifs.current[Number(event.key) - 1];
|
|
1330
1383
|
if (selectedMotifMeshState.current.has(motif)) {
|
|
1331
1384
|
removeMotif(motif);
|
|
1332
1385
|
} else {
|
|
@@ -1349,8 +1402,8 @@ function Canvas({
|
|
|
1349
1402
|
return positions;
|
|
1350
1403
|
};
|
|
1351
1404
|
const updateMotifs = () => {
|
|
1352
|
-
const positions = calculatePositions(motifs.length);
|
|
1353
|
-
motifs.forEach((motifMesh, index) => {
|
|
1405
|
+
const positions = calculatePositions(motifs.current.length);
|
|
1406
|
+
motifs.current.forEach((motifMesh, index) => {
|
|
1354
1407
|
if (!scene.current?.children.has(motifMesh.uuid)) return;
|
|
1355
1408
|
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
1356
1409
|
motifMesh.setPosition(positions[index].x, positions[index].y, positions[index].z);
|
|
@@ -1360,9 +1413,6 @@ function Canvas({
|
|
|
1360
1413
|
motifMesh.setScale(scale);
|
|
1361
1414
|
});
|
|
1362
1415
|
};
|
|
1363
|
-
(0, import_react.useEffect)(() => {
|
|
1364
|
-
updateMotifs();
|
|
1365
|
-
}, [motifProps]);
|
|
1366
1416
|
(0, import_react.useEffect)(() => {
|
|
1367
1417
|
const unsubscribe = CanvasDataManager.subscribe("selectedMotifs" /* SELECTED_MOTIFS */, () => {
|
|
1368
1418
|
setSelectedmotifIds(CanvasDataManager.selectedMotifIds);
|
|
@@ -1374,13 +1424,13 @@ function Canvas({
|
|
|
1374
1424
|
CanvasDataManager.setSelectedMotifIds(selectedMotifIds);
|
|
1375
1425
|
}
|
|
1376
1426
|
selectedMotifMeshState.current.clear();
|
|
1377
|
-
motifs.forEach((motif) => {
|
|
1427
|
+
motifs.current.forEach((motif) => {
|
|
1378
1428
|
if (selectedMotifIds.has(motif.uuid)) {
|
|
1379
1429
|
selectedMotifMeshState.current.add(motif);
|
|
1380
1430
|
}
|
|
1381
1431
|
});
|
|
1382
1432
|
updateGlow();
|
|
1383
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1433
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1384
1434
|
}, [selectedMotifIds]);
|
|
1385
1435
|
(0, import_react.useEffect)(() => {
|
|
1386
1436
|
const unsubscribe = CanvasDataManager.subscribe("lockedMotifIds" /* LOCKED_MOTIF_IDS */, () => {
|
|
@@ -1421,8 +1471,8 @@ function Canvas({
|
|
|
1421
1471
|
if (!showRMSD) return;
|
|
1422
1472
|
if (CanvasDataManager.kabschRMSD !== kabschRMSD) {
|
|
1423
1473
|
CanvasDataManager.setKabschRMSD(kabschRMSD);
|
|
1424
|
-
} else if (CanvasDataManager.kabschRMSD.length !== motifs.length) {
|
|
1425
|
-
CanvasDataManager.setKabschRMSD(calculateAllKabschRMSD(motifs));
|
|
1474
|
+
} else if (CanvasDataManager.kabschRMSD.length !== motifs.current.length) {
|
|
1475
|
+
CanvasDataManager.setKabschRMSD(calculateAllKabschRMSD(motifs.current));
|
|
1426
1476
|
}
|
|
1427
1477
|
}, [kabschRMSD]);
|
|
1428
1478
|
(0, import_react.useEffect)(() => {
|
|
@@ -1441,84 +1491,91 @@ function Canvas({
|
|
|
1441
1491
|
rendererSizeIsWindow ? window.innerWidth : rendererWidth,
|
|
1442
1492
|
rendererSizeIsWindow ? window.innerHeight : rendererHeight
|
|
1443
1493
|
);
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1494
|
+
const eventManager = scene.current?.eventManager;
|
|
1495
|
+
eventManager.on(Events.EventType.OBJECT_SELECTED, onSelectMotif);
|
|
1496
|
+
eventManager.on(Events.EventType.OBJECT_DESELECTED, onDeselectMotif);
|
|
1497
|
+
eventManager.on(Events.EventType.POINTER_MOVE, onMouseMove);
|
|
1498
|
+
eventManager.on(Events.EventType.POINTER_WHEEL, onMouseScroll);
|
|
1499
|
+
eventManager.on(Events.EventType.POINTER_DOWN, onMouseDown);
|
|
1500
|
+
eventManager.on(Events.EventType.POINTER_UP, onMouseUp);
|
|
1501
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardRotate);
|
|
1502
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardTranslate);
|
|
1503
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardSelect);
|
|
1504
|
+
if (customEventProps) {
|
|
1505
|
+
customEventProps.forEach((customEventProp) => {
|
|
1506
|
+
switch (customEventProp.eventType) {
|
|
1507
|
+
// Handle Pointer Events
|
|
1508
|
+
case Events.EventType.POINTER_DOWN:
|
|
1509
|
+
case Events.EventType.POINTER_UP:
|
|
1510
|
+
case Events.EventType.POINTER_MOVE:
|
|
1511
|
+
case Events.EventType.POINTER_WHEEL:
|
|
1512
|
+
case Events.EventType.TOUCH_END:
|
|
1513
|
+
case Events.EventType.TOUCH_MOVE:
|
|
1514
|
+
case Events.EventType.TOUCH_START:
|
|
1515
|
+
eventManager.on(
|
|
1516
|
+
customEventProp.eventType,
|
|
1517
|
+
customEventProp.callback
|
|
1518
|
+
);
|
|
1519
|
+
break;
|
|
1520
|
+
// Handle Keyboard Events
|
|
1521
|
+
case Events.EventType.KEY_DOWN:
|
|
1522
|
+
case Events.EventType.KEY_UP:
|
|
1523
|
+
eventManager.on(
|
|
1524
|
+
customEventProp.eventType,
|
|
1525
|
+
customEventProp.callback
|
|
1526
|
+
);
|
|
1527
|
+
break;
|
|
1528
|
+
// Handle Pinch Events
|
|
1529
|
+
case Events.EventType.PINCH:
|
|
1530
|
+
case Events.EventType.PINCH_END:
|
|
1531
|
+
case Events.EventType.PINCH_START:
|
|
1532
|
+
eventManager.on(
|
|
1533
|
+
customEventProp.eventType,
|
|
1534
|
+
customEventProp.callback
|
|
1535
|
+
);
|
|
1536
|
+
break;
|
|
1537
|
+
// Handle Selection Events
|
|
1538
|
+
case Events.EventType.OBJECT_SELECTED:
|
|
1539
|
+
case Events.EventType.OBJECT_DESELECTED:
|
|
1540
|
+
eventManager.on(
|
|
1541
|
+
customEventProp.eventType,
|
|
1542
|
+
customEventProp.callback
|
|
1543
|
+
);
|
|
1544
|
+
break;
|
|
1545
|
+
// Handle Events
|
|
1546
|
+
default:
|
|
1547
|
+
eventManager.on(
|
|
1548
|
+
customEventProp.eventType,
|
|
1549
|
+
customEventProp.callback
|
|
1550
|
+
);
|
|
1551
|
+
break;
|
|
1552
|
+
}
|
|
1457
1553
|
});
|
|
1458
|
-
const eventManager = scene.current?.eventManager;
|
|
1459
|
-
eventManager.on(Events.EventType.OBJECT_SELECTED, onSelectMotif);
|
|
1460
|
-
eventManager.on(Events.EventType.OBJECT_DESELECTED, onDeselectMotif);
|
|
1461
|
-
eventManager.on(Events.EventType.POINTER_MOVE, onMouseMove);
|
|
1462
|
-
eventManager.on(Events.EventType.POINTER_WHEEL, onMouseScroll);
|
|
1463
|
-
eventManager.on(Events.EventType.POINTER_DOWN, onMouseDown);
|
|
1464
|
-
eventManager.on(Events.EventType.POINTER_UP, onMouseUp);
|
|
1465
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardRotate);
|
|
1466
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardTranslate);
|
|
1467
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardSelect);
|
|
1468
|
-
if (customEventProps) {
|
|
1469
|
-
customEventProps.forEach((customEventProp) => {
|
|
1470
|
-
switch (customEventProp.eventType) {
|
|
1471
|
-
// Handle Pointer Events
|
|
1472
|
-
case Events.EventType.POINTER_DOWN:
|
|
1473
|
-
case Events.EventType.POINTER_UP:
|
|
1474
|
-
case Events.EventType.POINTER_MOVE:
|
|
1475
|
-
case Events.EventType.POINTER_WHEEL:
|
|
1476
|
-
case Events.EventType.TOUCH_END:
|
|
1477
|
-
case Events.EventType.TOUCH_MOVE:
|
|
1478
|
-
case Events.EventType.TOUCH_START:
|
|
1479
|
-
eventManager.on(
|
|
1480
|
-
customEventProp.eventType,
|
|
1481
|
-
customEventProp.callback
|
|
1482
|
-
);
|
|
1483
|
-
break;
|
|
1484
|
-
// Handle Keyboard Events
|
|
1485
|
-
case Events.EventType.KEY_DOWN:
|
|
1486
|
-
case Events.EventType.KEY_UP:
|
|
1487
|
-
eventManager.on(
|
|
1488
|
-
customEventProp.eventType,
|
|
1489
|
-
customEventProp.callback
|
|
1490
|
-
);
|
|
1491
|
-
break;
|
|
1492
|
-
// Handle Pinch Events
|
|
1493
|
-
case Events.EventType.PINCH:
|
|
1494
|
-
case Events.EventType.PINCH_END:
|
|
1495
|
-
case Events.EventType.PINCH_START:
|
|
1496
|
-
eventManager.on(
|
|
1497
|
-
customEventProp.eventType,
|
|
1498
|
-
customEventProp.callback
|
|
1499
|
-
);
|
|
1500
|
-
break;
|
|
1501
|
-
// Handle Selection Events
|
|
1502
|
-
case Events.EventType.OBJECT_SELECTED:
|
|
1503
|
-
case Events.EventType.OBJECT_DESELECTED:
|
|
1504
|
-
eventManager.on(
|
|
1505
|
-
customEventProp.eventType,
|
|
1506
|
-
customEventProp.callback
|
|
1507
|
-
);
|
|
1508
|
-
break;
|
|
1509
|
-
// Handle Events
|
|
1510
|
-
default:
|
|
1511
|
-
eventManager.on(
|
|
1512
|
-
customEventProp.eventType,
|
|
1513
|
-
customEventProp.callback
|
|
1514
|
-
);
|
|
1515
|
-
break;
|
|
1516
|
-
}
|
|
1517
|
-
});
|
|
1518
|
-
}
|
|
1519
1554
|
}
|
|
1555
|
+
scene.current.start();
|
|
1556
|
+
}
|
|
1557
|
+
}, []);
|
|
1558
|
+
(0, import_react.useEffect)(() => {
|
|
1559
|
+
if (!scene.current || !canvasRef.current) return;
|
|
1560
|
+
motifs.current.length = 0;
|
|
1561
|
+
motifProps.forEach((motifProp) => {
|
|
1562
|
+
motifs.current.push(motifProp.motif);
|
|
1563
|
+
});
|
|
1564
|
+
if (motifs.current.length > 0) {
|
|
1565
|
+
if (showRMSD) setKabschRMSD(calculateAllKabschRMSD(motifs.current));
|
|
1566
|
+
scene.current.removeAll();
|
|
1567
|
+
const positions = calculatePositions(motifs.current.length);
|
|
1568
|
+
motifs.current.forEach((motifMesh, index) => {
|
|
1569
|
+
scene.current?.add(motifMesh);
|
|
1570
|
+
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
1571
|
+
motifMesh.setPosition(positions[index].x, positions[index].y, positions[index].z);
|
|
1572
|
+
if (motifProps[index].rotation) motifMesh.setQuaternion(motifProps[index].rotation);
|
|
1573
|
+
let scale = canvasRef.current.width / 250;
|
|
1574
|
+
if (motifProps[index].scale) scale = motifProps[index].scale;
|
|
1575
|
+
motifMesh.setScale(scale);
|
|
1576
|
+
if (motifProps[index].locked) lockedMotifIdState.current.add(motifMesh.uuid);
|
|
1577
|
+
});
|
|
1520
1578
|
}
|
|
1521
|
-
scene.current?.start();
|
|
1522
1579
|
}, [rendererWidth, rendererHeight, rendererSizeIsWindow, motifProps]);
|
|
1523
1580
|
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("canvas", { ref: canvasRef }));
|
|
1524
1581
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -271,10 +271,14 @@ var Residue = class extends Group {
|
|
|
271
271
|
/**
|
|
272
272
|
* Cretes a material with the given color and sets it to the mesh
|
|
273
273
|
* @param color String in the format of #RRGGBB
|
|
274
|
+
* @param highlight Whether to apply a highlight effect to the residue
|
|
274
275
|
*/
|
|
275
|
-
colorResidue(color) {
|
|
276
|
+
colorResidue(color, highlight = false) {
|
|
276
277
|
this._children.forEach((child) => {
|
|
277
|
-
child.
|
|
278
|
+
child.colorMaterial(color);
|
|
279
|
+
if (highlight) {
|
|
280
|
+
child.applyHighlight();
|
|
281
|
+
}
|
|
278
282
|
});
|
|
279
283
|
}
|
|
280
284
|
};
|
|
@@ -306,23 +310,34 @@ var MeshObject = class {
|
|
|
306
310
|
}
|
|
307
311
|
applyHighlight() {
|
|
308
312
|
const mat = this._mesh.material;
|
|
309
|
-
mat.emissiveColor = mat.diffuseColor.scale(0.
|
|
313
|
+
mat.emissiveColor = mat.diffuseColor.scale(0.6);
|
|
310
314
|
}
|
|
311
315
|
resetHighlight() {
|
|
312
316
|
const mat = this._mesh.material;
|
|
313
317
|
mat.emissiveColor = Color3.Black();
|
|
314
318
|
}
|
|
315
319
|
/**
|
|
316
|
-
*
|
|
320
|
+
* Creates a material with the given color and sets it to the mesh
|
|
317
321
|
* @param color String in the format of #RRGGBB
|
|
318
322
|
*/
|
|
319
323
|
createAndSetMaterial(color) {
|
|
320
324
|
const mat = new StandardMaterial("mat");
|
|
321
|
-
const color3 = Color3.FromHexString(
|
|
325
|
+
const color3 = Color3.FromHexString(`${color.replace(/^0x/i, "")}`);
|
|
322
326
|
mat.diffuseColor = color3;
|
|
323
327
|
mat.specularColor = color3;
|
|
328
|
+
mat.backFaceCulling = false;
|
|
324
329
|
this._mesh.material = mat;
|
|
325
330
|
}
|
|
331
|
+
/**
|
|
332
|
+
* Sets the material of the mesh object to the given color
|
|
333
|
+
* @param color String in the format of #RRGGBB
|
|
334
|
+
*/
|
|
335
|
+
colorMaterial(color) {
|
|
336
|
+
const mat = this._mesh.material;
|
|
337
|
+
const color3 = Color3.FromHexString(`${color.replace(/^0x/i, "")}`);
|
|
338
|
+
mat.diffuseColor = color3;
|
|
339
|
+
mat.specularColor = color3;
|
|
340
|
+
}
|
|
326
341
|
setNewMesh(mesh) {
|
|
327
342
|
this._mesh = mesh;
|
|
328
343
|
return this;
|
|
@@ -546,9 +561,19 @@ var EventManager = class {
|
|
|
546
561
|
canceled: false,
|
|
547
562
|
timestamp: performance.now()
|
|
548
563
|
};
|
|
549
|
-
if (keyboardInfo.type === KeyboardEventTypes.KEYDOWN) {
|
|
564
|
+
if (keyboardInfo.type === KeyboardEventTypes.KEYDOWN && /^[wasdqeWASD]$/.test(event.key)) {
|
|
565
|
+
if (event.key.charCodeAt(0) >= 97) {
|
|
566
|
+
this._activeKeys.delete(event.key.toUpperCase());
|
|
567
|
+
} else {
|
|
568
|
+
this._activeKeys.delete(event.key.toLowerCase());
|
|
569
|
+
}
|
|
550
570
|
this._activeKeys.add(event.key);
|
|
551
571
|
} else if (keyboardInfo.type === KeyboardEventTypes.KEYUP) {
|
|
572
|
+
if (event.key.charCodeAt(0) >= 97) {
|
|
573
|
+
this._activeKeys.delete(event.key.toUpperCase());
|
|
574
|
+
} else {
|
|
575
|
+
this._activeKeys.delete(event.key.toLowerCase());
|
|
576
|
+
}
|
|
552
577
|
this._activeKeys.delete(event.key);
|
|
553
578
|
}
|
|
554
579
|
if (this._activeKeys.has("w")) keyboardEvent.rotationAxis.add(new Vec3(-1, 0, 0));
|
|
@@ -610,12 +635,20 @@ var RenderScene = class {
|
|
|
610
635
|
// State variables
|
|
611
636
|
_isDisposed = false;
|
|
612
637
|
isRunning = false;
|
|
638
|
+
/**
|
|
639
|
+
*
|
|
640
|
+
* @param canvas HTML Canvas Element
|
|
641
|
+
* @param hexColor Color in the format of #RRGGBB
|
|
642
|
+
* @param cameraPositionZ Z position of the camera
|
|
643
|
+
* @param renderWidth Width of the render window
|
|
644
|
+
* @param renderHeight Height of the render window
|
|
645
|
+
*/
|
|
613
646
|
constructor(canvas, hexColor, cameraPositionZ, renderWidth, renderHeight) {
|
|
614
647
|
this._canvas = canvas;
|
|
615
648
|
this._engine = new Engine(this._canvas, true);
|
|
616
649
|
this._engine.setSize(renderWidth, renderHeight);
|
|
617
650
|
this._scene = new Scene5(this._engine);
|
|
618
|
-
this._scene.clearColor = Color4.FromHexString(`${hexColor.replace(/^0x
|
|
651
|
+
this._scene.clearColor = Color4.FromHexString(`${hexColor.replace(/^0x/i, "")}`);
|
|
619
652
|
this._camera = new UniversalCamera("camera", new Vector33(0, 0, cameraPositionZ));
|
|
620
653
|
this._camera.setTarget(new Vector33(0, 0, 0));
|
|
621
654
|
this._camera.mode = Camera.ORTHOGRAPHIC_CAMERA;
|
|
@@ -627,7 +660,6 @@ var RenderScene = class {
|
|
|
627
660
|
const light = new HemisphericLight("light", Vector33.Up(), this._scene);
|
|
628
661
|
light.intensity = 1.25;
|
|
629
662
|
this._eventManager = new EventManager();
|
|
630
|
-
window.addEventListener("resize", this._handleResize.bind(this));
|
|
631
663
|
}
|
|
632
664
|
// Start the render loop
|
|
633
665
|
start() {
|
|
@@ -668,7 +700,6 @@ var RenderScene = class {
|
|
|
668
700
|
// Stop and dispose of all resources
|
|
669
701
|
dispose() {
|
|
670
702
|
this.stop();
|
|
671
|
-
window.removeEventListener("resize", this._handleResize);
|
|
672
703
|
this._eventManager.dispose();
|
|
673
704
|
this._scene.dispose();
|
|
674
705
|
this._engine.dispose();
|
|
@@ -688,10 +719,18 @@ var RenderScene = class {
|
|
|
688
719
|
return;
|
|
689
720
|
}
|
|
690
721
|
this._children.delete(motif.uuid);
|
|
691
|
-
|
|
722
|
+
motif.node.dispose(false, true);
|
|
723
|
+
}
|
|
724
|
+
removeAll() {
|
|
725
|
+
this._scene.meshes.slice().forEach((mesh) => {
|
|
726
|
+
if (mesh && this._scene.getMeshById(mesh.id)) {
|
|
727
|
+
this._scene.removeMesh(mesh);
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
this._children.clear();
|
|
692
731
|
}
|
|
693
732
|
setBackgroundColor(hexColor) {
|
|
694
|
-
this._scene.clearColor = Color4.FromHexString(`${hexColor.replace(/^0x
|
|
733
|
+
this._scene.clearColor = Color4.FromHexString(`${hexColor.replace(/^0x/i, "")}`);
|
|
695
734
|
}
|
|
696
735
|
_reattachToScene(node, currObj) {
|
|
697
736
|
node._scene = this._scene;
|
|
@@ -705,7 +744,7 @@ var RenderScene = class {
|
|
|
705
744
|
geo?.applyToMesh(mesh);
|
|
706
745
|
mesh.material = mat;
|
|
707
746
|
currObj.setNewMesh(mesh);
|
|
708
|
-
node.dispose();
|
|
747
|
+
node.dispose(false, true);
|
|
709
748
|
}
|
|
710
749
|
if (!(currObj instanceof MeshObject)) {
|
|
711
750
|
currObj.children.forEach((childObj) => {
|
|
@@ -804,7 +843,7 @@ function getPoints(nucleotideData, includeAtoms) {
|
|
|
804
843
|
}
|
|
805
844
|
|
|
806
845
|
// src/3D/utils/GetMotif.ts
|
|
807
|
-
async function getMotif(motifName, motifMesh, motifColorHex = "
|
|
846
|
+
async function getMotif(motifName, motifMesh, motifColorHex = "#cc2900", includeAtoms = true) {
|
|
808
847
|
const motif = new Motif(`${motifName}_motif`);
|
|
809
848
|
for (const [key] of Object.entries(motifMesh)) {
|
|
810
849
|
const { vertices, indices } = getPoints(motifMesh[key], includeAtoms);
|
|
@@ -838,7 +877,7 @@ var CanvasAttributeTypes = /* @__PURE__ */ ((CanvasAttributeTypes2) => {
|
|
|
838
877
|
})(CanvasAttributeTypes || {});
|
|
839
878
|
var CanvasDataManager = class {
|
|
840
879
|
static _selectedMotifIds = /* @__PURE__ */ new Set();
|
|
841
|
-
static _lockedMotifIds =
|
|
880
|
+
static _lockedMotifIds = /* @__PURE__ */ new Set();
|
|
842
881
|
static _hardLockedMotifIds = [];
|
|
843
882
|
static _scoreRMSD = [];
|
|
844
883
|
static _kabschRMSD = [];
|
|
@@ -1095,28 +1134,27 @@ function Canvas({
|
|
|
1095
1134
|
}) {
|
|
1096
1135
|
const canvasRef = useRef(null);
|
|
1097
1136
|
const scene = useRef(null);
|
|
1098
|
-
const motifs = [];
|
|
1137
|
+
const motifs = useRef([]);
|
|
1099
1138
|
let hardLockedMotifIds = [];
|
|
1100
1139
|
motifProps.forEach((motifProp) => {
|
|
1101
|
-
motifs.push(motifProp.motif);
|
|
1102
1140
|
if (motifProp.locked) hardLockedMotifIds.push(motifProp.motif.uuid);
|
|
1103
1141
|
});
|
|
1104
1142
|
CanvasDataManager.setHardLockedMotifIds(hardLockedMotifIds);
|
|
1105
1143
|
const selectedMotifMeshState = useRef(/* @__PURE__ */ new Set());
|
|
1106
|
-
const lockedMotifIdState = useRef(
|
|
1144
|
+
const lockedMotifIdState = useRef(/* @__PURE__ */ new Set());
|
|
1107
1145
|
const [cursorStyle, setCursorStyle] = useState("auto");
|
|
1108
1146
|
const [selectedMotifIds, setSelectedmotifIds] = useState(/* @__PURE__ */ new Set());
|
|
1109
1147
|
const [scoreRMSD, setScoreRMSD] = useState([]);
|
|
1110
1148
|
const [kabschRMSD, setKabschRMSD] = useState([]);
|
|
1111
|
-
const [lockedMotifIds, setLockedMotifIds] = useState(
|
|
1149
|
+
const [lockedMotifIds, setLockedMotifIds] = useState(/* @__PURE__ */ new Set());
|
|
1112
1150
|
const addMotif = (motif) => {
|
|
1113
1151
|
if (selectedMotifMeshState.current.has(motif)) {
|
|
1114
1152
|
return;
|
|
1115
1153
|
}
|
|
1116
1154
|
const newSet = /* @__PURE__ */ new Set();
|
|
1117
|
-
for (let i = 0; i < motifs.length; i += 1) {
|
|
1118
|
-
if (selectedMotifMeshState.current.has(motifs[i]) || motifs[i].uuid === motif.uuid) {
|
|
1119
|
-
newSet.add(motifs[i].uuid);
|
|
1155
|
+
for (let i = 0; i < motifs.current.length; i += 1) {
|
|
1156
|
+
if (selectedMotifMeshState.current.has(motifs.current[i]) || motifs.current[i].uuid === motif.uuid) {
|
|
1157
|
+
newSet.add(motifs.current[i].uuid);
|
|
1120
1158
|
}
|
|
1121
1159
|
}
|
|
1122
1160
|
setSelectedmotifIds(newSet);
|
|
@@ -1134,7 +1172,7 @@ function Canvas({
|
|
|
1134
1172
|
});
|
|
1135
1173
|
};
|
|
1136
1174
|
function updateGlow() {
|
|
1137
|
-
motifs.forEach((motif) => {
|
|
1175
|
+
motifs.current.forEach((motif) => {
|
|
1138
1176
|
motif.children.forEach((residue) => {
|
|
1139
1177
|
residue.children.forEach((childMesh) => {
|
|
1140
1178
|
if (selectedMotifIds.has(motif.uuid)) {
|
|
@@ -1146,12 +1184,27 @@ function Canvas({
|
|
|
1146
1184
|
});
|
|
1147
1185
|
});
|
|
1148
1186
|
}
|
|
1187
|
+
function motifOutOfBounds(motif, deltaX, deltaY) {
|
|
1188
|
+
if (!canvasRef.current) {
|
|
1189
|
+
return false;
|
|
1190
|
+
}
|
|
1191
|
+
const canvasWidth = canvasRef.current.width;
|
|
1192
|
+
const canvasHeight = canvasRef.current.height;
|
|
1193
|
+
const left = -canvasWidth / 2;
|
|
1194
|
+
const right = canvasWidth / 2;
|
|
1195
|
+
const top = canvasHeight / 2;
|
|
1196
|
+
const bottom = -canvasHeight / 2;
|
|
1197
|
+
const newX = motif.position.x + deltaX;
|
|
1198
|
+
const newY = motif.position.y + deltaY;
|
|
1199
|
+
if (newX <= left || newX >= right || newY <= bottom || newY >= top) return true;
|
|
1200
|
+
return false;
|
|
1201
|
+
}
|
|
1149
1202
|
function onSelectMotif(event) {
|
|
1150
1203
|
if (event.type !== Events.EventType.OBJECT_SELECTED) {
|
|
1151
1204
|
return;
|
|
1152
1205
|
}
|
|
1153
1206
|
const { motif } = event;
|
|
1154
|
-
if (!motif || selectedMotifMeshState.current.has(motif)
|
|
1207
|
+
if (!motif || selectedMotifMeshState.current.has(motif)) {
|
|
1155
1208
|
return;
|
|
1156
1209
|
}
|
|
1157
1210
|
if (event.multiSelect && motif) {
|
|
@@ -1183,7 +1236,7 @@ function Canvas({
|
|
|
1183
1236
|
const deltaX = rawDeltaX / renderWidth * canvasRef.current.width;
|
|
1184
1237
|
const deltaY = rawDeltaY / renderHeight * canvasRef.current.height;
|
|
1185
1238
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1186
|
-
if (!lockedMotifIdState.current.
|
|
1239
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid) && !motifOutOfBounds(element, -deltaX, -deltaY)) {
|
|
1187
1240
|
element.translate(-deltaX, -deltaY, 0);
|
|
1188
1241
|
}
|
|
1189
1242
|
});
|
|
@@ -1196,11 +1249,11 @@ function Canvas({
|
|
|
1196
1249
|
if (scene.current) {
|
|
1197
1250
|
const angle = directionVec.length() / scene.current.renderWidth * (3 * Math.PI);
|
|
1198
1251
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1199
|
-
if (!lockedMotifIdState.current.
|
|
1252
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1200
1253
|
element.rotate(axisVec, angle);
|
|
1201
1254
|
}
|
|
1202
1255
|
});
|
|
1203
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1256
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1204
1257
|
}
|
|
1205
1258
|
}
|
|
1206
1259
|
}
|
|
@@ -1213,7 +1266,7 @@ function Canvas({
|
|
|
1213
1266
|
const zoomSpeed = 0.1;
|
|
1214
1267
|
const zoomDirection = event.originalEvent.deltaY > 0 ? -1 : 1;
|
|
1215
1268
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1216
|
-
if (!lockedMotifIdState.current.
|
|
1269
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid) && !(element.scale <= 1 && zoomDirection === -1) && !(element.scale >= 30 && zoomDirection === 1)) {
|
|
1217
1270
|
const scaleFactor = 1 + zoomDirection * zoomSpeed;
|
|
1218
1271
|
element.multiplyScalar(scaleFactor);
|
|
1219
1272
|
}
|
|
@@ -1241,19 +1294,19 @@ function Canvas({
|
|
|
1241
1294
|
}
|
|
1242
1295
|
const angle = event.rotationAxis.length() / 500 * (6 * Math.PI);
|
|
1243
1296
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1244
|
-
if (!lockedMotifIdState.current.
|
|
1297
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1245
1298
|
element.rotate(event.rotationAxis, angle);
|
|
1246
1299
|
}
|
|
1247
1300
|
});
|
|
1248
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1301
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1249
1302
|
}
|
|
1250
1303
|
function onKeyboardTranslate(event) {
|
|
1251
1304
|
if (event.translationDirection.equals(Vec3.Zero)) {
|
|
1252
1305
|
return;
|
|
1253
1306
|
}
|
|
1254
|
-
event.translationDirection.multiplyScalar(
|
|
1307
|
+
event.translationDirection.multiplyScalar(4.5);
|
|
1255
1308
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1256
|
-
if (!lockedMotifIdState.current.
|
|
1309
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid) && !motifOutOfBounds(element, event.translationDirection.x, event.translationDirection.y)) {
|
|
1257
1310
|
element.translate(
|
|
1258
1311
|
event.translationDirection.x,
|
|
1259
1312
|
event.translationDirection.y,
|
|
@@ -1266,10 +1319,10 @@ function Canvas({
|
|
|
1266
1319
|
if (!event.rotationAxis.equals(Vec3.Zero) || !event.translationDirection.equals(Vec3.Zero)) {
|
|
1267
1320
|
return;
|
|
1268
1321
|
}
|
|
1269
|
-
if (!/^[1-9]$/.test(event.key) || Number(event.key) > motifs.length) {
|
|
1322
|
+
if (!/^[1-9]$/.test(event.key) || Number(event.key) > motifs.current.length) {
|
|
1270
1323
|
return;
|
|
1271
1324
|
}
|
|
1272
|
-
const motif = motifs[Number(event.key) - 1];
|
|
1325
|
+
const motif = motifs.current[Number(event.key) - 1];
|
|
1273
1326
|
if (selectedMotifMeshState.current.has(motif)) {
|
|
1274
1327
|
removeMotif(motif);
|
|
1275
1328
|
} else {
|
|
@@ -1292,8 +1345,8 @@ function Canvas({
|
|
|
1292
1345
|
return positions;
|
|
1293
1346
|
};
|
|
1294
1347
|
const updateMotifs = () => {
|
|
1295
|
-
const positions = calculatePositions(motifs.length);
|
|
1296
|
-
motifs.forEach((motifMesh, index) => {
|
|
1348
|
+
const positions = calculatePositions(motifs.current.length);
|
|
1349
|
+
motifs.current.forEach((motifMesh, index) => {
|
|
1297
1350
|
if (!scene.current?.children.has(motifMesh.uuid)) return;
|
|
1298
1351
|
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
1299
1352
|
motifMesh.setPosition(positions[index].x, positions[index].y, positions[index].z);
|
|
@@ -1303,9 +1356,6 @@ function Canvas({
|
|
|
1303
1356
|
motifMesh.setScale(scale);
|
|
1304
1357
|
});
|
|
1305
1358
|
};
|
|
1306
|
-
useEffect(() => {
|
|
1307
|
-
updateMotifs();
|
|
1308
|
-
}, [motifProps]);
|
|
1309
1359
|
useEffect(() => {
|
|
1310
1360
|
const unsubscribe = CanvasDataManager.subscribe("selectedMotifs" /* SELECTED_MOTIFS */, () => {
|
|
1311
1361
|
setSelectedmotifIds(CanvasDataManager.selectedMotifIds);
|
|
@@ -1317,13 +1367,13 @@ function Canvas({
|
|
|
1317
1367
|
CanvasDataManager.setSelectedMotifIds(selectedMotifIds);
|
|
1318
1368
|
}
|
|
1319
1369
|
selectedMotifMeshState.current.clear();
|
|
1320
|
-
motifs.forEach((motif) => {
|
|
1370
|
+
motifs.current.forEach((motif) => {
|
|
1321
1371
|
if (selectedMotifIds.has(motif.uuid)) {
|
|
1322
1372
|
selectedMotifMeshState.current.add(motif);
|
|
1323
1373
|
}
|
|
1324
1374
|
});
|
|
1325
1375
|
updateGlow();
|
|
1326
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1376
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1327
1377
|
}, [selectedMotifIds]);
|
|
1328
1378
|
useEffect(() => {
|
|
1329
1379
|
const unsubscribe = CanvasDataManager.subscribe("lockedMotifIds" /* LOCKED_MOTIF_IDS */, () => {
|
|
@@ -1364,8 +1414,8 @@ function Canvas({
|
|
|
1364
1414
|
if (!showRMSD) return;
|
|
1365
1415
|
if (CanvasDataManager.kabschRMSD !== kabschRMSD) {
|
|
1366
1416
|
CanvasDataManager.setKabschRMSD(kabschRMSD);
|
|
1367
|
-
} else if (CanvasDataManager.kabschRMSD.length !== motifs.length) {
|
|
1368
|
-
CanvasDataManager.setKabschRMSD(calculateAllKabschRMSD(motifs));
|
|
1417
|
+
} else if (CanvasDataManager.kabschRMSD.length !== motifs.current.length) {
|
|
1418
|
+
CanvasDataManager.setKabschRMSD(calculateAllKabschRMSD(motifs.current));
|
|
1369
1419
|
}
|
|
1370
1420
|
}, [kabschRMSD]);
|
|
1371
1421
|
useEffect(() => {
|
|
@@ -1384,84 +1434,91 @@ function Canvas({
|
|
|
1384
1434
|
rendererSizeIsWindow ? window.innerWidth : rendererWidth,
|
|
1385
1435
|
rendererSizeIsWindow ? window.innerHeight : rendererHeight
|
|
1386
1436
|
);
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1437
|
+
const eventManager = scene.current?.eventManager;
|
|
1438
|
+
eventManager.on(Events.EventType.OBJECT_SELECTED, onSelectMotif);
|
|
1439
|
+
eventManager.on(Events.EventType.OBJECT_DESELECTED, onDeselectMotif);
|
|
1440
|
+
eventManager.on(Events.EventType.POINTER_MOVE, onMouseMove);
|
|
1441
|
+
eventManager.on(Events.EventType.POINTER_WHEEL, onMouseScroll);
|
|
1442
|
+
eventManager.on(Events.EventType.POINTER_DOWN, onMouseDown);
|
|
1443
|
+
eventManager.on(Events.EventType.POINTER_UP, onMouseUp);
|
|
1444
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardRotate);
|
|
1445
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardTranslate);
|
|
1446
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardSelect);
|
|
1447
|
+
if (customEventProps) {
|
|
1448
|
+
customEventProps.forEach((customEventProp) => {
|
|
1449
|
+
switch (customEventProp.eventType) {
|
|
1450
|
+
// Handle Pointer Events
|
|
1451
|
+
case Events.EventType.POINTER_DOWN:
|
|
1452
|
+
case Events.EventType.POINTER_UP:
|
|
1453
|
+
case Events.EventType.POINTER_MOVE:
|
|
1454
|
+
case Events.EventType.POINTER_WHEEL:
|
|
1455
|
+
case Events.EventType.TOUCH_END:
|
|
1456
|
+
case Events.EventType.TOUCH_MOVE:
|
|
1457
|
+
case Events.EventType.TOUCH_START:
|
|
1458
|
+
eventManager.on(
|
|
1459
|
+
customEventProp.eventType,
|
|
1460
|
+
customEventProp.callback
|
|
1461
|
+
);
|
|
1462
|
+
break;
|
|
1463
|
+
// Handle Keyboard Events
|
|
1464
|
+
case Events.EventType.KEY_DOWN:
|
|
1465
|
+
case Events.EventType.KEY_UP:
|
|
1466
|
+
eventManager.on(
|
|
1467
|
+
customEventProp.eventType,
|
|
1468
|
+
customEventProp.callback
|
|
1469
|
+
);
|
|
1470
|
+
break;
|
|
1471
|
+
// Handle Pinch Events
|
|
1472
|
+
case Events.EventType.PINCH:
|
|
1473
|
+
case Events.EventType.PINCH_END:
|
|
1474
|
+
case Events.EventType.PINCH_START:
|
|
1475
|
+
eventManager.on(
|
|
1476
|
+
customEventProp.eventType,
|
|
1477
|
+
customEventProp.callback
|
|
1478
|
+
);
|
|
1479
|
+
break;
|
|
1480
|
+
// Handle Selection Events
|
|
1481
|
+
case Events.EventType.OBJECT_SELECTED:
|
|
1482
|
+
case Events.EventType.OBJECT_DESELECTED:
|
|
1483
|
+
eventManager.on(
|
|
1484
|
+
customEventProp.eventType,
|
|
1485
|
+
customEventProp.callback
|
|
1486
|
+
);
|
|
1487
|
+
break;
|
|
1488
|
+
// Handle Events
|
|
1489
|
+
default:
|
|
1490
|
+
eventManager.on(
|
|
1491
|
+
customEventProp.eventType,
|
|
1492
|
+
customEventProp.callback
|
|
1493
|
+
);
|
|
1494
|
+
break;
|
|
1495
|
+
}
|
|
1400
1496
|
});
|
|
1401
|
-
const eventManager = scene.current?.eventManager;
|
|
1402
|
-
eventManager.on(Events.EventType.OBJECT_SELECTED, onSelectMotif);
|
|
1403
|
-
eventManager.on(Events.EventType.OBJECT_DESELECTED, onDeselectMotif);
|
|
1404
|
-
eventManager.on(Events.EventType.POINTER_MOVE, onMouseMove);
|
|
1405
|
-
eventManager.on(Events.EventType.POINTER_WHEEL, onMouseScroll);
|
|
1406
|
-
eventManager.on(Events.EventType.POINTER_DOWN, onMouseDown);
|
|
1407
|
-
eventManager.on(Events.EventType.POINTER_UP, onMouseUp);
|
|
1408
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardRotate);
|
|
1409
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardTranslate);
|
|
1410
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardSelect);
|
|
1411
|
-
if (customEventProps) {
|
|
1412
|
-
customEventProps.forEach((customEventProp) => {
|
|
1413
|
-
switch (customEventProp.eventType) {
|
|
1414
|
-
// Handle Pointer Events
|
|
1415
|
-
case Events.EventType.POINTER_DOWN:
|
|
1416
|
-
case Events.EventType.POINTER_UP:
|
|
1417
|
-
case Events.EventType.POINTER_MOVE:
|
|
1418
|
-
case Events.EventType.POINTER_WHEEL:
|
|
1419
|
-
case Events.EventType.TOUCH_END:
|
|
1420
|
-
case Events.EventType.TOUCH_MOVE:
|
|
1421
|
-
case Events.EventType.TOUCH_START:
|
|
1422
|
-
eventManager.on(
|
|
1423
|
-
customEventProp.eventType,
|
|
1424
|
-
customEventProp.callback
|
|
1425
|
-
);
|
|
1426
|
-
break;
|
|
1427
|
-
// Handle Keyboard Events
|
|
1428
|
-
case Events.EventType.KEY_DOWN:
|
|
1429
|
-
case Events.EventType.KEY_UP:
|
|
1430
|
-
eventManager.on(
|
|
1431
|
-
customEventProp.eventType,
|
|
1432
|
-
customEventProp.callback
|
|
1433
|
-
);
|
|
1434
|
-
break;
|
|
1435
|
-
// Handle Pinch Events
|
|
1436
|
-
case Events.EventType.PINCH:
|
|
1437
|
-
case Events.EventType.PINCH_END:
|
|
1438
|
-
case Events.EventType.PINCH_START:
|
|
1439
|
-
eventManager.on(
|
|
1440
|
-
customEventProp.eventType,
|
|
1441
|
-
customEventProp.callback
|
|
1442
|
-
);
|
|
1443
|
-
break;
|
|
1444
|
-
// Handle Selection Events
|
|
1445
|
-
case Events.EventType.OBJECT_SELECTED:
|
|
1446
|
-
case Events.EventType.OBJECT_DESELECTED:
|
|
1447
|
-
eventManager.on(
|
|
1448
|
-
customEventProp.eventType,
|
|
1449
|
-
customEventProp.callback
|
|
1450
|
-
);
|
|
1451
|
-
break;
|
|
1452
|
-
// Handle Events
|
|
1453
|
-
default:
|
|
1454
|
-
eventManager.on(
|
|
1455
|
-
customEventProp.eventType,
|
|
1456
|
-
customEventProp.callback
|
|
1457
|
-
);
|
|
1458
|
-
break;
|
|
1459
|
-
}
|
|
1460
|
-
});
|
|
1461
|
-
}
|
|
1462
1497
|
}
|
|
1498
|
+
scene.current.start();
|
|
1499
|
+
}
|
|
1500
|
+
}, []);
|
|
1501
|
+
useEffect(() => {
|
|
1502
|
+
if (!scene.current || !canvasRef.current) return;
|
|
1503
|
+
motifs.current.length = 0;
|
|
1504
|
+
motifProps.forEach((motifProp) => {
|
|
1505
|
+
motifs.current.push(motifProp.motif);
|
|
1506
|
+
});
|
|
1507
|
+
if (motifs.current.length > 0) {
|
|
1508
|
+
if (showRMSD) setKabschRMSD(calculateAllKabschRMSD(motifs.current));
|
|
1509
|
+
scene.current.removeAll();
|
|
1510
|
+
const positions = calculatePositions(motifs.current.length);
|
|
1511
|
+
motifs.current.forEach((motifMesh, index) => {
|
|
1512
|
+
scene.current?.add(motifMesh);
|
|
1513
|
+
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
1514
|
+
motifMesh.setPosition(positions[index].x, positions[index].y, positions[index].z);
|
|
1515
|
+
if (motifProps[index].rotation) motifMesh.setQuaternion(motifProps[index].rotation);
|
|
1516
|
+
let scale = canvasRef.current.width / 250;
|
|
1517
|
+
if (motifProps[index].scale) scale = motifProps[index].scale;
|
|
1518
|
+
motifMesh.setScale(scale);
|
|
1519
|
+
if (motifProps[index].locked) lockedMotifIdState.current.add(motifMesh.uuid);
|
|
1520
|
+
});
|
|
1463
1521
|
}
|
|
1464
|
-
scene.current?.start();
|
|
1465
1522
|
}, [rendererWidth, rendererHeight, rendererSizeIsWindow, motifProps]);
|
|
1466
1523
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("canvas", { ref: canvasRef }));
|
|
1467
1524
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@judah-silva/rnacanvas",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "A 3D Canvas for displaying and interacting with custom RNA models. Powered by BabylonJS.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/RNAStructureAnalysisLab/RNACanvas"
|
|
9
|
+
"url": "git+https://github.com/RNAStructureAnalysisLab/RNACanvas.git"
|
|
10
10
|
},
|
|
11
11
|
"module": "./dist/index.mjs",
|
|
12
12
|
"scripts": {
|