@judah-silva/rnacanvas 0.0.7 → 0.0.9
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/README.md +4 -0
- package/dist/index.d.mts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +142 -108
- package/dist/index.mjs +142 -108
- package/package.json +1 -1
- package/judah-silva-rnacanvas-0.0.6.tgz +0 -0
package/README.md
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -8,7 +8,16 @@ import { Mesh, TransformNode, Scene, Matrix, Nullable, Quaternion, Observer, Eng
|
|
|
8
8
|
declare class Residue extends Group<MeshObject> {
|
|
9
9
|
constructor(name: string);
|
|
10
10
|
addChild(child: MeshObject): void;
|
|
11
|
+
/**
|
|
12
|
+
* Checks if the residue has a mesh with the given uuid
|
|
13
|
+
* @param uuid
|
|
14
|
+
*/
|
|
11
15
|
hasMesh(uuid: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Cretes a material with the given color and sets it to the mesh
|
|
18
|
+
* @param color String in the format of #RRGGBB
|
|
19
|
+
*/
|
|
20
|
+
colorResidue(color: string): void;
|
|
12
21
|
}
|
|
13
22
|
|
|
14
23
|
/**
|
|
@@ -297,6 +306,7 @@ declare class RenderScene {
|
|
|
297
306
|
dispose(): void;
|
|
298
307
|
add(motif: Motif): void;
|
|
299
308
|
remove(motif: Motif): void;
|
|
309
|
+
removeAll(): void;
|
|
300
310
|
setBackgroundColor(hexColor: string): void;
|
|
301
311
|
private _reattachToScene;
|
|
302
312
|
private _handleResize;
|
|
@@ -460,8 +470,8 @@ declare class CanvasDataManager {
|
|
|
460
470
|
private static _listeners;
|
|
461
471
|
static get selectedMotifIds(): Set<string>;
|
|
462
472
|
static setSelectedMotifIds(selectedMotifIds: Set<string>): void;
|
|
463
|
-
static get lockedMotifIds(): string
|
|
464
|
-
static setLockedMotifIds(lockedMotifIds: string
|
|
473
|
+
static get lockedMotifIds(): Set<string>;
|
|
474
|
+
static setLockedMotifIds(lockedMotifIds: Set<string>): void;
|
|
465
475
|
static get hardLockedMotifIds(): string[];
|
|
466
476
|
static setHardLockedMotifIds(hardLockedMotifIds: string[]): void;
|
|
467
477
|
static get scoreRMSD(): ScoreInfo[][];
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,16 @@ import { Mesh, TransformNode, Scene, Matrix, Nullable, Quaternion, Observer, Eng
|
|
|
8
8
|
declare class Residue extends Group<MeshObject> {
|
|
9
9
|
constructor(name: string);
|
|
10
10
|
addChild(child: MeshObject): void;
|
|
11
|
+
/**
|
|
12
|
+
* Checks if the residue has a mesh with the given uuid
|
|
13
|
+
* @param uuid
|
|
14
|
+
*/
|
|
11
15
|
hasMesh(uuid: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Cretes a material with the given color and sets it to the mesh
|
|
18
|
+
* @param color String in the format of #RRGGBB
|
|
19
|
+
*/
|
|
20
|
+
colorResidue(color: string): void;
|
|
12
21
|
}
|
|
13
22
|
|
|
14
23
|
/**
|
|
@@ -297,6 +306,7 @@ declare class RenderScene {
|
|
|
297
306
|
dispose(): void;
|
|
298
307
|
add(motif: Motif): void;
|
|
299
308
|
remove(motif: Motif): void;
|
|
309
|
+
removeAll(): void;
|
|
300
310
|
setBackgroundColor(hexColor: string): void;
|
|
301
311
|
private _reattachToScene;
|
|
302
312
|
private _handleResize;
|
|
@@ -460,8 +470,8 @@ declare class CanvasDataManager {
|
|
|
460
470
|
private static _listeners;
|
|
461
471
|
static get selectedMotifIds(): Set<string>;
|
|
462
472
|
static setSelectedMotifIds(selectedMotifIds: Set<string>): void;
|
|
463
|
-
static get lockedMotifIds(): string
|
|
464
|
-
static setLockedMotifIds(lockedMotifIds: string
|
|
473
|
+
static get lockedMotifIds(): Set<string>;
|
|
474
|
+
static setLockedMotifIds(lockedMotifIds: Set<string>): void;
|
|
465
475
|
static get hardLockedMotifIds(): string[];
|
|
466
476
|
static setHardLockedMotifIds(hardLockedMotifIds: string[]): void;
|
|
467
477
|
static get scoreRMSD(): ScoreInfo[][];
|
package/dist/index.js
CHANGED
|
@@ -312,7 +312,10 @@ var Residue = class extends Group {
|
|
|
312
312
|
child.setParent(this);
|
|
313
313
|
this._children.add(child);
|
|
314
314
|
}
|
|
315
|
-
|
|
315
|
+
/**
|
|
316
|
+
* Checks if the residue has a mesh with the given uuid
|
|
317
|
+
* @param uuid
|
|
318
|
+
*/
|
|
316
319
|
hasMesh(uuid) {
|
|
317
320
|
let found = false;
|
|
318
321
|
this._children.forEach((child) => {
|
|
@@ -322,6 +325,15 @@ var Residue = class extends Group {
|
|
|
322
325
|
});
|
|
323
326
|
return found;
|
|
324
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* Cretes a material with the given color and sets it to the mesh
|
|
330
|
+
* @param color String in the format of #RRGGBB
|
|
331
|
+
*/
|
|
332
|
+
colorResidue(color) {
|
|
333
|
+
this._children.forEach((child) => {
|
|
334
|
+
child.createAndSetMaterial(color);
|
|
335
|
+
});
|
|
336
|
+
}
|
|
325
337
|
};
|
|
326
338
|
|
|
327
339
|
// src/3D/MeshObject.ts
|
|
@@ -366,6 +378,7 @@ var MeshObject = class {
|
|
|
366
378
|
const color3 = import_core7.Color3.FromHexString(`#${color.replace(/^0x/, "")}`);
|
|
367
379
|
mat.diffuseColor = color3;
|
|
368
380
|
mat.specularColor = color3;
|
|
381
|
+
mat.backFaceCulling = false;
|
|
369
382
|
this._mesh.material = mat;
|
|
370
383
|
}
|
|
371
384
|
setNewMesh(mesh) {
|
|
@@ -591,9 +604,19 @@ var EventManager = class {
|
|
|
591
604
|
canceled: false,
|
|
592
605
|
timestamp: performance.now()
|
|
593
606
|
};
|
|
594
|
-
if (keyboardInfo.type === import_core8.KeyboardEventTypes.KEYDOWN) {
|
|
607
|
+
if (keyboardInfo.type === import_core8.KeyboardEventTypes.KEYDOWN && /^[wasdqeWASD]$/.test(event.key)) {
|
|
608
|
+
if (event.key.charCodeAt(0) >= 97) {
|
|
609
|
+
this._activeKeys.delete(event.key.toUpperCase());
|
|
610
|
+
} else {
|
|
611
|
+
this._activeKeys.delete(event.key.toLowerCase());
|
|
612
|
+
}
|
|
595
613
|
this._activeKeys.add(event.key);
|
|
596
614
|
} else if (keyboardInfo.type === import_core8.KeyboardEventTypes.KEYUP) {
|
|
615
|
+
if (event.key.charCodeAt(0) >= 97) {
|
|
616
|
+
this._activeKeys.delete(event.key.toUpperCase());
|
|
617
|
+
} else {
|
|
618
|
+
this._activeKeys.delete(event.key.toLowerCase());
|
|
619
|
+
}
|
|
597
620
|
this._activeKeys.delete(event.key);
|
|
598
621
|
}
|
|
599
622
|
if (this._activeKeys.has("w")) keyboardEvent.rotationAxis.add(new Vec3(-1, 0, 0));
|
|
@@ -733,7 +756,15 @@ var RenderScene = class {
|
|
|
733
756
|
return;
|
|
734
757
|
}
|
|
735
758
|
this._children.delete(motif.uuid);
|
|
736
|
-
|
|
759
|
+
motif.node.dispose(false, true);
|
|
760
|
+
}
|
|
761
|
+
removeAll() {
|
|
762
|
+
this._scene.meshes.slice().forEach((mesh) => {
|
|
763
|
+
if (mesh && this._scene.getMeshById(mesh.id)) {
|
|
764
|
+
this._scene.removeMesh(mesh);
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
this._children.clear();
|
|
737
768
|
}
|
|
738
769
|
setBackgroundColor(hexColor) {
|
|
739
770
|
this._scene.clearColor = import_core9.Color4.FromHexString(`${hexColor.replace(/^0x/, "")}`);
|
|
@@ -750,7 +781,7 @@ var RenderScene = class {
|
|
|
750
781
|
geo?.applyToMesh(mesh);
|
|
751
782
|
mesh.material = mat;
|
|
752
783
|
currObj.setNewMesh(mesh);
|
|
753
|
-
node.dispose();
|
|
784
|
+
node.dispose(false, true);
|
|
754
785
|
}
|
|
755
786
|
if (!(currObj instanceof MeshObject)) {
|
|
756
787
|
currObj.children.forEach((childObj) => {
|
|
@@ -883,7 +914,7 @@ var CanvasAttributeTypes = /* @__PURE__ */ ((CanvasAttributeTypes2) => {
|
|
|
883
914
|
})(CanvasAttributeTypes || {});
|
|
884
915
|
var CanvasDataManager = class {
|
|
885
916
|
static _selectedMotifIds = /* @__PURE__ */ new Set();
|
|
886
|
-
static _lockedMotifIds =
|
|
917
|
+
static _lockedMotifIds = /* @__PURE__ */ new Set();
|
|
887
918
|
static _hardLockedMotifIds = [];
|
|
888
919
|
static _scoreRMSD = [];
|
|
889
920
|
static _kabschRMSD = [];
|
|
@@ -1140,28 +1171,27 @@ function Canvas({
|
|
|
1140
1171
|
}) {
|
|
1141
1172
|
const canvasRef = (0, import_react.useRef)(null);
|
|
1142
1173
|
const scene = (0, import_react.useRef)(null);
|
|
1143
|
-
const motifs = [];
|
|
1174
|
+
const motifs = (0, import_react.useRef)([]);
|
|
1144
1175
|
let hardLockedMotifIds = [];
|
|
1145
1176
|
motifProps.forEach((motifProp) => {
|
|
1146
|
-
motifs.push(motifProp.motif);
|
|
1147
1177
|
if (motifProp.locked) hardLockedMotifIds.push(motifProp.motif.uuid);
|
|
1148
1178
|
});
|
|
1149
1179
|
CanvasDataManager.setHardLockedMotifIds(hardLockedMotifIds);
|
|
1150
1180
|
const selectedMotifMeshState = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
1151
|
-
const lockedMotifIdState = (0, import_react.useRef)(
|
|
1181
|
+
const lockedMotifIdState = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
1152
1182
|
const [cursorStyle, setCursorStyle] = (0, import_react.useState)("auto");
|
|
1153
1183
|
const [selectedMotifIds, setSelectedmotifIds] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
1154
1184
|
const [scoreRMSD, setScoreRMSD] = (0, import_react.useState)([]);
|
|
1155
1185
|
const [kabschRMSD, setKabschRMSD] = (0, import_react.useState)([]);
|
|
1156
|
-
const [lockedMotifIds, setLockedMotifIds] = (0, import_react.useState)(
|
|
1186
|
+
const [lockedMotifIds, setLockedMotifIds] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
1157
1187
|
const addMotif = (motif) => {
|
|
1158
1188
|
if (selectedMotifMeshState.current.has(motif)) {
|
|
1159
1189
|
return;
|
|
1160
1190
|
}
|
|
1161
1191
|
const newSet = /* @__PURE__ */ new Set();
|
|
1162
|
-
for (let i = 0; i < motifs.length; i += 1) {
|
|
1163
|
-
if (selectedMotifMeshState.current.has(motifs[i]) || motifs[i].uuid === motif.uuid) {
|
|
1164
|
-
newSet.add(motifs[i].uuid);
|
|
1192
|
+
for (let i = 0; i < motifs.current.length; i += 1) {
|
|
1193
|
+
if (selectedMotifMeshState.current.has(motifs.current[i]) || motifs.current[i].uuid === motif.uuid) {
|
|
1194
|
+
newSet.add(motifs.current[i].uuid);
|
|
1165
1195
|
}
|
|
1166
1196
|
}
|
|
1167
1197
|
setSelectedmotifIds(newSet);
|
|
@@ -1179,7 +1209,7 @@ function Canvas({
|
|
|
1179
1209
|
});
|
|
1180
1210
|
};
|
|
1181
1211
|
function updateGlow() {
|
|
1182
|
-
motifs.forEach((motif) => {
|
|
1212
|
+
motifs.current.forEach((motif) => {
|
|
1183
1213
|
motif.children.forEach((residue) => {
|
|
1184
1214
|
residue.children.forEach((childMesh) => {
|
|
1185
1215
|
if (selectedMotifIds.has(motif.uuid)) {
|
|
@@ -1196,7 +1226,7 @@ function Canvas({
|
|
|
1196
1226
|
return;
|
|
1197
1227
|
}
|
|
1198
1228
|
const { motif } = event;
|
|
1199
|
-
if (!motif || selectedMotifMeshState.current.has(motif)
|
|
1229
|
+
if (!motif || selectedMotifMeshState.current.has(motif)) {
|
|
1200
1230
|
return;
|
|
1201
1231
|
}
|
|
1202
1232
|
if (event.multiSelect && motif) {
|
|
@@ -1228,7 +1258,7 @@ function Canvas({
|
|
|
1228
1258
|
const deltaX = rawDeltaX / renderWidth * canvasRef.current.width;
|
|
1229
1259
|
const deltaY = rawDeltaY / renderHeight * canvasRef.current.height;
|
|
1230
1260
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1231
|
-
if (!lockedMotifIdState.current.
|
|
1261
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1232
1262
|
element.translate(-deltaX, -deltaY, 0);
|
|
1233
1263
|
}
|
|
1234
1264
|
});
|
|
@@ -1241,11 +1271,11 @@ function Canvas({
|
|
|
1241
1271
|
if (scene.current) {
|
|
1242
1272
|
const angle = directionVec.length() / scene.current.renderWidth * (3 * Math.PI);
|
|
1243
1273
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1244
|
-
if (!lockedMotifIdState.current.
|
|
1274
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1245
1275
|
element.rotate(axisVec, angle);
|
|
1246
1276
|
}
|
|
1247
1277
|
});
|
|
1248
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1278
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1249
1279
|
}
|
|
1250
1280
|
}
|
|
1251
1281
|
}
|
|
@@ -1258,7 +1288,7 @@ function Canvas({
|
|
|
1258
1288
|
const zoomSpeed = 0.1;
|
|
1259
1289
|
const zoomDirection = event.originalEvent.deltaY > 0 ? -1 : 1;
|
|
1260
1290
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1261
|
-
if (!lockedMotifIdState.current.
|
|
1291
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid) && !(element.scale <= 1 && zoomDirection === -1) && !(element.scale >= 30 && zoomDirection === 1)) {
|
|
1262
1292
|
const scaleFactor = 1 + zoomDirection * zoomSpeed;
|
|
1263
1293
|
element.multiplyScalar(scaleFactor);
|
|
1264
1294
|
}
|
|
@@ -1286,19 +1316,19 @@ function Canvas({
|
|
|
1286
1316
|
}
|
|
1287
1317
|
const angle = event.rotationAxis.length() / 500 * (6 * Math.PI);
|
|
1288
1318
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1289
|
-
if (!lockedMotifIdState.current.
|
|
1319
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1290
1320
|
element.rotate(event.rotationAxis, angle);
|
|
1291
1321
|
}
|
|
1292
1322
|
});
|
|
1293
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1323
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1294
1324
|
}
|
|
1295
1325
|
function onKeyboardTranslate(event) {
|
|
1296
1326
|
if (event.translationDirection.equals(Vec3.Zero)) {
|
|
1297
1327
|
return;
|
|
1298
1328
|
}
|
|
1299
|
-
event.translationDirection.multiplyScalar(
|
|
1329
|
+
event.translationDirection.multiplyScalar(4.5);
|
|
1300
1330
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1301
|
-
if (!lockedMotifIdState.current.
|
|
1331
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1302
1332
|
element.translate(
|
|
1303
1333
|
event.translationDirection.x,
|
|
1304
1334
|
event.translationDirection.y,
|
|
@@ -1311,10 +1341,10 @@ function Canvas({
|
|
|
1311
1341
|
if (!event.rotationAxis.equals(Vec3.Zero) || !event.translationDirection.equals(Vec3.Zero)) {
|
|
1312
1342
|
return;
|
|
1313
1343
|
}
|
|
1314
|
-
if (!/^[1-9]$/.test(event.key) || Number(event.key) > motifs.length) {
|
|
1344
|
+
if (!/^[1-9]$/.test(event.key) || Number(event.key) > motifs.current.length) {
|
|
1315
1345
|
return;
|
|
1316
1346
|
}
|
|
1317
|
-
const motif = motifs[Number(event.key) - 1];
|
|
1347
|
+
const motif = motifs.current[Number(event.key) - 1];
|
|
1318
1348
|
if (selectedMotifMeshState.current.has(motif)) {
|
|
1319
1349
|
removeMotif(motif);
|
|
1320
1350
|
} else {
|
|
@@ -1337,8 +1367,8 @@ function Canvas({
|
|
|
1337
1367
|
return positions;
|
|
1338
1368
|
};
|
|
1339
1369
|
const updateMotifs = () => {
|
|
1340
|
-
const positions = calculatePositions(motifs.length);
|
|
1341
|
-
motifs.forEach((motifMesh, index) => {
|
|
1370
|
+
const positions = calculatePositions(motifs.current.length);
|
|
1371
|
+
motifs.current.forEach((motifMesh, index) => {
|
|
1342
1372
|
if (!scene.current?.children.has(motifMesh.uuid)) return;
|
|
1343
1373
|
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
1344
1374
|
motifMesh.setPosition(positions[index].x, positions[index].y, positions[index].z);
|
|
@@ -1348,9 +1378,6 @@ function Canvas({
|
|
|
1348
1378
|
motifMesh.setScale(scale);
|
|
1349
1379
|
});
|
|
1350
1380
|
};
|
|
1351
|
-
(0, import_react.useEffect)(() => {
|
|
1352
|
-
updateMotifs();
|
|
1353
|
-
}, [motifProps]);
|
|
1354
1381
|
(0, import_react.useEffect)(() => {
|
|
1355
1382
|
const unsubscribe = CanvasDataManager.subscribe("selectedMotifs" /* SELECTED_MOTIFS */, () => {
|
|
1356
1383
|
setSelectedmotifIds(CanvasDataManager.selectedMotifIds);
|
|
@@ -1362,13 +1389,13 @@ function Canvas({
|
|
|
1362
1389
|
CanvasDataManager.setSelectedMotifIds(selectedMotifIds);
|
|
1363
1390
|
}
|
|
1364
1391
|
selectedMotifMeshState.current.clear();
|
|
1365
|
-
motifs.forEach((motif) => {
|
|
1392
|
+
motifs.current.forEach((motif) => {
|
|
1366
1393
|
if (selectedMotifIds.has(motif.uuid)) {
|
|
1367
1394
|
selectedMotifMeshState.current.add(motif);
|
|
1368
1395
|
}
|
|
1369
1396
|
});
|
|
1370
1397
|
updateGlow();
|
|
1371
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1398
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1372
1399
|
}, [selectedMotifIds]);
|
|
1373
1400
|
(0, import_react.useEffect)(() => {
|
|
1374
1401
|
const unsubscribe = CanvasDataManager.subscribe("lockedMotifIds" /* LOCKED_MOTIF_IDS */, () => {
|
|
@@ -1409,8 +1436,8 @@ function Canvas({
|
|
|
1409
1436
|
if (!showRMSD) return;
|
|
1410
1437
|
if (CanvasDataManager.kabschRMSD !== kabschRMSD) {
|
|
1411
1438
|
CanvasDataManager.setKabschRMSD(kabschRMSD);
|
|
1412
|
-
} else if (CanvasDataManager.kabschRMSD.length !== motifs.length) {
|
|
1413
|
-
CanvasDataManager.setKabschRMSD(calculateAllKabschRMSD(motifs));
|
|
1439
|
+
} else if (CanvasDataManager.kabschRMSD.length !== motifs.current.length) {
|
|
1440
|
+
CanvasDataManager.setKabschRMSD(calculateAllKabschRMSD(motifs.current));
|
|
1414
1441
|
}
|
|
1415
1442
|
}, [kabschRMSD]);
|
|
1416
1443
|
(0, import_react.useEffect)(() => {
|
|
@@ -1429,84 +1456,91 @@ function Canvas({
|
|
|
1429
1456
|
rendererSizeIsWindow ? window.innerWidth : rendererWidth,
|
|
1430
1457
|
rendererSizeIsWindow ? window.innerHeight : rendererHeight
|
|
1431
1458
|
);
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1459
|
+
const eventManager = scene.current?.eventManager;
|
|
1460
|
+
eventManager.on(Events.EventType.OBJECT_SELECTED, onSelectMotif);
|
|
1461
|
+
eventManager.on(Events.EventType.OBJECT_DESELECTED, onDeselectMotif);
|
|
1462
|
+
eventManager.on(Events.EventType.POINTER_MOVE, onMouseMove);
|
|
1463
|
+
eventManager.on(Events.EventType.POINTER_WHEEL, onMouseScroll);
|
|
1464
|
+
eventManager.on(Events.EventType.POINTER_DOWN, onMouseDown);
|
|
1465
|
+
eventManager.on(Events.EventType.POINTER_UP, onMouseUp);
|
|
1466
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardRotate);
|
|
1467
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardTranslate);
|
|
1468
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardSelect);
|
|
1469
|
+
if (customEventProps) {
|
|
1470
|
+
customEventProps.forEach((customEventProp) => {
|
|
1471
|
+
switch (customEventProp.eventType) {
|
|
1472
|
+
// Handle Pointer Events
|
|
1473
|
+
case Events.EventType.POINTER_DOWN:
|
|
1474
|
+
case Events.EventType.POINTER_UP:
|
|
1475
|
+
case Events.EventType.POINTER_MOVE:
|
|
1476
|
+
case Events.EventType.POINTER_WHEEL:
|
|
1477
|
+
case Events.EventType.TOUCH_END:
|
|
1478
|
+
case Events.EventType.TOUCH_MOVE:
|
|
1479
|
+
case Events.EventType.TOUCH_START:
|
|
1480
|
+
eventManager.on(
|
|
1481
|
+
customEventProp.eventType,
|
|
1482
|
+
customEventProp.callback
|
|
1483
|
+
);
|
|
1484
|
+
break;
|
|
1485
|
+
// Handle Keyboard Events
|
|
1486
|
+
case Events.EventType.KEY_DOWN:
|
|
1487
|
+
case Events.EventType.KEY_UP:
|
|
1488
|
+
eventManager.on(
|
|
1489
|
+
customEventProp.eventType,
|
|
1490
|
+
customEventProp.callback
|
|
1491
|
+
);
|
|
1492
|
+
break;
|
|
1493
|
+
// Handle Pinch Events
|
|
1494
|
+
case Events.EventType.PINCH:
|
|
1495
|
+
case Events.EventType.PINCH_END:
|
|
1496
|
+
case Events.EventType.PINCH_START:
|
|
1497
|
+
eventManager.on(
|
|
1498
|
+
customEventProp.eventType,
|
|
1499
|
+
customEventProp.callback
|
|
1500
|
+
);
|
|
1501
|
+
break;
|
|
1502
|
+
// Handle Selection Events
|
|
1503
|
+
case Events.EventType.OBJECT_SELECTED:
|
|
1504
|
+
case Events.EventType.OBJECT_DESELECTED:
|
|
1505
|
+
eventManager.on(
|
|
1506
|
+
customEventProp.eventType,
|
|
1507
|
+
customEventProp.callback
|
|
1508
|
+
);
|
|
1509
|
+
break;
|
|
1510
|
+
// Handle Events
|
|
1511
|
+
default:
|
|
1512
|
+
eventManager.on(
|
|
1513
|
+
customEventProp.eventType,
|
|
1514
|
+
customEventProp.callback
|
|
1515
|
+
);
|
|
1516
|
+
break;
|
|
1517
|
+
}
|
|
1445
1518
|
});
|
|
1446
|
-
const eventManager = scene.current?.eventManager;
|
|
1447
|
-
eventManager.on(Events.EventType.OBJECT_SELECTED, onSelectMotif);
|
|
1448
|
-
eventManager.on(Events.EventType.OBJECT_DESELECTED, onDeselectMotif);
|
|
1449
|
-
eventManager.on(Events.EventType.POINTER_MOVE, onMouseMove);
|
|
1450
|
-
eventManager.on(Events.EventType.POINTER_WHEEL, onMouseScroll);
|
|
1451
|
-
eventManager.on(Events.EventType.POINTER_DOWN, onMouseDown);
|
|
1452
|
-
eventManager.on(Events.EventType.POINTER_UP, onMouseUp);
|
|
1453
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardRotate);
|
|
1454
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardTranslate);
|
|
1455
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardSelect);
|
|
1456
|
-
if (customEventProps) {
|
|
1457
|
-
customEventProps.forEach((customEventProp) => {
|
|
1458
|
-
switch (customEventProp.eventType) {
|
|
1459
|
-
// Handle Pointer Events
|
|
1460
|
-
case Events.EventType.POINTER_DOWN:
|
|
1461
|
-
case Events.EventType.POINTER_UP:
|
|
1462
|
-
case Events.EventType.POINTER_MOVE:
|
|
1463
|
-
case Events.EventType.POINTER_WHEEL:
|
|
1464
|
-
case Events.EventType.TOUCH_END:
|
|
1465
|
-
case Events.EventType.TOUCH_MOVE:
|
|
1466
|
-
case Events.EventType.TOUCH_START:
|
|
1467
|
-
eventManager.on(
|
|
1468
|
-
customEventProp.eventType,
|
|
1469
|
-
customEventProp.callback
|
|
1470
|
-
);
|
|
1471
|
-
break;
|
|
1472
|
-
// Handle Keyboard Events
|
|
1473
|
-
case Events.EventType.KEY_DOWN:
|
|
1474
|
-
case Events.EventType.KEY_UP:
|
|
1475
|
-
eventManager.on(
|
|
1476
|
-
customEventProp.eventType,
|
|
1477
|
-
customEventProp.callback
|
|
1478
|
-
);
|
|
1479
|
-
break;
|
|
1480
|
-
// Handle Pinch Events
|
|
1481
|
-
case Events.EventType.PINCH:
|
|
1482
|
-
case Events.EventType.PINCH_END:
|
|
1483
|
-
case Events.EventType.PINCH_START:
|
|
1484
|
-
eventManager.on(
|
|
1485
|
-
customEventProp.eventType,
|
|
1486
|
-
customEventProp.callback
|
|
1487
|
-
);
|
|
1488
|
-
break;
|
|
1489
|
-
// Handle Selection Events
|
|
1490
|
-
case Events.EventType.OBJECT_SELECTED:
|
|
1491
|
-
case Events.EventType.OBJECT_DESELECTED:
|
|
1492
|
-
eventManager.on(
|
|
1493
|
-
customEventProp.eventType,
|
|
1494
|
-
customEventProp.callback
|
|
1495
|
-
);
|
|
1496
|
-
break;
|
|
1497
|
-
// Handle Events
|
|
1498
|
-
default:
|
|
1499
|
-
eventManager.on(
|
|
1500
|
-
customEventProp.eventType,
|
|
1501
|
-
customEventProp.callback
|
|
1502
|
-
);
|
|
1503
|
-
break;
|
|
1504
|
-
}
|
|
1505
|
-
});
|
|
1506
|
-
}
|
|
1507
1519
|
}
|
|
1520
|
+
scene.current.start();
|
|
1521
|
+
}
|
|
1522
|
+
}, []);
|
|
1523
|
+
(0, import_react.useEffect)(() => {
|
|
1524
|
+
if (!scene.current || !canvasRef.current) return;
|
|
1525
|
+
motifs.current.length = 0;
|
|
1526
|
+
motifProps.forEach((motifProp) => {
|
|
1527
|
+
motifs.current.push(motifProp.motif);
|
|
1528
|
+
});
|
|
1529
|
+
if (motifs.current.length > 0) {
|
|
1530
|
+
if (showRMSD) setKabschRMSD(calculateAllKabschRMSD(motifs.current));
|
|
1531
|
+
scene.current.removeAll();
|
|
1532
|
+
const positions = calculatePositions(motifs.current.length);
|
|
1533
|
+
motifs.current.forEach((motifMesh, index) => {
|
|
1534
|
+
scene.current?.add(motifMesh);
|
|
1535
|
+
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
1536
|
+
motifMesh.setPosition(positions[index].x, positions[index].y, positions[index].z);
|
|
1537
|
+
if (motifProps[index].rotation) motifMesh.setQuaternion(motifProps[index].rotation);
|
|
1538
|
+
let scale = canvasRef.current.width / 250;
|
|
1539
|
+
if (motifProps[index].scale) scale = motifProps[index].scale;
|
|
1540
|
+
motifMesh.setScale(scale);
|
|
1541
|
+
if (motifProps[index].locked) lockedMotifIdState.current.add(motifMesh.uuid);
|
|
1542
|
+
});
|
|
1508
1543
|
}
|
|
1509
|
-
scene.current?.start();
|
|
1510
1544
|
}, [rendererWidth, rendererHeight, rendererSizeIsWindow, motifProps]);
|
|
1511
1545
|
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("canvas", { ref: canvasRef }));
|
|
1512
1546
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -255,7 +255,10 @@ var Residue = class extends Group {
|
|
|
255
255
|
child.setParent(this);
|
|
256
256
|
this._children.add(child);
|
|
257
257
|
}
|
|
258
|
-
|
|
258
|
+
/**
|
|
259
|
+
* Checks if the residue has a mesh with the given uuid
|
|
260
|
+
* @param uuid
|
|
261
|
+
*/
|
|
259
262
|
hasMesh(uuid) {
|
|
260
263
|
let found = false;
|
|
261
264
|
this._children.forEach((child) => {
|
|
@@ -265,6 +268,15 @@ var Residue = class extends Group {
|
|
|
265
268
|
});
|
|
266
269
|
return found;
|
|
267
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* Cretes a material with the given color and sets it to the mesh
|
|
273
|
+
* @param color String in the format of #RRGGBB
|
|
274
|
+
*/
|
|
275
|
+
colorResidue(color) {
|
|
276
|
+
this._children.forEach((child) => {
|
|
277
|
+
child.createAndSetMaterial(color);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
268
280
|
};
|
|
269
281
|
|
|
270
282
|
// src/3D/MeshObject.ts
|
|
@@ -309,6 +321,7 @@ var MeshObject = class {
|
|
|
309
321
|
const color3 = Color3.FromHexString(`#${color.replace(/^0x/, "")}`);
|
|
310
322
|
mat.diffuseColor = color3;
|
|
311
323
|
mat.specularColor = color3;
|
|
324
|
+
mat.backFaceCulling = false;
|
|
312
325
|
this._mesh.material = mat;
|
|
313
326
|
}
|
|
314
327
|
setNewMesh(mesh) {
|
|
@@ -534,9 +547,19 @@ var EventManager = class {
|
|
|
534
547
|
canceled: false,
|
|
535
548
|
timestamp: performance.now()
|
|
536
549
|
};
|
|
537
|
-
if (keyboardInfo.type === KeyboardEventTypes.KEYDOWN) {
|
|
550
|
+
if (keyboardInfo.type === KeyboardEventTypes.KEYDOWN && /^[wasdqeWASD]$/.test(event.key)) {
|
|
551
|
+
if (event.key.charCodeAt(0) >= 97) {
|
|
552
|
+
this._activeKeys.delete(event.key.toUpperCase());
|
|
553
|
+
} else {
|
|
554
|
+
this._activeKeys.delete(event.key.toLowerCase());
|
|
555
|
+
}
|
|
538
556
|
this._activeKeys.add(event.key);
|
|
539
557
|
} else if (keyboardInfo.type === KeyboardEventTypes.KEYUP) {
|
|
558
|
+
if (event.key.charCodeAt(0) >= 97) {
|
|
559
|
+
this._activeKeys.delete(event.key.toUpperCase());
|
|
560
|
+
} else {
|
|
561
|
+
this._activeKeys.delete(event.key.toLowerCase());
|
|
562
|
+
}
|
|
540
563
|
this._activeKeys.delete(event.key);
|
|
541
564
|
}
|
|
542
565
|
if (this._activeKeys.has("w")) keyboardEvent.rotationAxis.add(new Vec3(-1, 0, 0));
|
|
@@ -676,7 +699,15 @@ var RenderScene = class {
|
|
|
676
699
|
return;
|
|
677
700
|
}
|
|
678
701
|
this._children.delete(motif.uuid);
|
|
679
|
-
|
|
702
|
+
motif.node.dispose(false, true);
|
|
703
|
+
}
|
|
704
|
+
removeAll() {
|
|
705
|
+
this._scene.meshes.slice().forEach((mesh) => {
|
|
706
|
+
if (mesh && this._scene.getMeshById(mesh.id)) {
|
|
707
|
+
this._scene.removeMesh(mesh);
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
this._children.clear();
|
|
680
711
|
}
|
|
681
712
|
setBackgroundColor(hexColor) {
|
|
682
713
|
this._scene.clearColor = Color4.FromHexString(`${hexColor.replace(/^0x/, "")}`);
|
|
@@ -693,7 +724,7 @@ var RenderScene = class {
|
|
|
693
724
|
geo?.applyToMesh(mesh);
|
|
694
725
|
mesh.material = mat;
|
|
695
726
|
currObj.setNewMesh(mesh);
|
|
696
|
-
node.dispose();
|
|
727
|
+
node.dispose(false, true);
|
|
697
728
|
}
|
|
698
729
|
if (!(currObj instanceof MeshObject)) {
|
|
699
730
|
currObj.children.forEach((childObj) => {
|
|
@@ -826,7 +857,7 @@ var CanvasAttributeTypes = /* @__PURE__ */ ((CanvasAttributeTypes2) => {
|
|
|
826
857
|
})(CanvasAttributeTypes || {});
|
|
827
858
|
var CanvasDataManager = class {
|
|
828
859
|
static _selectedMotifIds = /* @__PURE__ */ new Set();
|
|
829
|
-
static _lockedMotifIds =
|
|
860
|
+
static _lockedMotifIds = /* @__PURE__ */ new Set();
|
|
830
861
|
static _hardLockedMotifIds = [];
|
|
831
862
|
static _scoreRMSD = [];
|
|
832
863
|
static _kabschRMSD = [];
|
|
@@ -1083,28 +1114,27 @@ function Canvas({
|
|
|
1083
1114
|
}) {
|
|
1084
1115
|
const canvasRef = useRef(null);
|
|
1085
1116
|
const scene = useRef(null);
|
|
1086
|
-
const motifs = [];
|
|
1117
|
+
const motifs = useRef([]);
|
|
1087
1118
|
let hardLockedMotifIds = [];
|
|
1088
1119
|
motifProps.forEach((motifProp) => {
|
|
1089
|
-
motifs.push(motifProp.motif);
|
|
1090
1120
|
if (motifProp.locked) hardLockedMotifIds.push(motifProp.motif.uuid);
|
|
1091
1121
|
});
|
|
1092
1122
|
CanvasDataManager.setHardLockedMotifIds(hardLockedMotifIds);
|
|
1093
1123
|
const selectedMotifMeshState = useRef(/* @__PURE__ */ new Set());
|
|
1094
|
-
const lockedMotifIdState = useRef(
|
|
1124
|
+
const lockedMotifIdState = useRef(/* @__PURE__ */ new Set());
|
|
1095
1125
|
const [cursorStyle, setCursorStyle] = useState("auto");
|
|
1096
1126
|
const [selectedMotifIds, setSelectedmotifIds] = useState(/* @__PURE__ */ new Set());
|
|
1097
1127
|
const [scoreRMSD, setScoreRMSD] = useState([]);
|
|
1098
1128
|
const [kabschRMSD, setKabschRMSD] = useState([]);
|
|
1099
|
-
const [lockedMotifIds, setLockedMotifIds] = useState(
|
|
1129
|
+
const [lockedMotifIds, setLockedMotifIds] = useState(/* @__PURE__ */ new Set());
|
|
1100
1130
|
const addMotif = (motif) => {
|
|
1101
1131
|
if (selectedMotifMeshState.current.has(motif)) {
|
|
1102
1132
|
return;
|
|
1103
1133
|
}
|
|
1104
1134
|
const newSet = /* @__PURE__ */ new Set();
|
|
1105
|
-
for (let i = 0; i < motifs.length; i += 1) {
|
|
1106
|
-
if (selectedMotifMeshState.current.has(motifs[i]) || motifs[i].uuid === motif.uuid) {
|
|
1107
|
-
newSet.add(motifs[i].uuid);
|
|
1135
|
+
for (let i = 0; i < motifs.current.length; i += 1) {
|
|
1136
|
+
if (selectedMotifMeshState.current.has(motifs.current[i]) || motifs.current[i].uuid === motif.uuid) {
|
|
1137
|
+
newSet.add(motifs.current[i].uuid);
|
|
1108
1138
|
}
|
|
1109
1139
|
}
|
|
1110
1140
|
setSelectedmotifIds(newSet);
|
|
@@ -1122,7 +1152,7 @@ function Canvas({
|
|
|
1122
1152
|
});
|
|
1123
1153
|
};
|
|
1124
1154
|
function updateGlow() {
|
|
1125
|
-
motifs.forEach((motif) => {
|
|
1155
|
+
motifs.current.forEach((motif) => {
|
|
1126
1156
|
motif.children.forEach((residue) => {
|
|
1127
1157
|
residue.children.forEach((childMesh) => {
|
|
1128
1158
|
if (selectedMotifIds.has(motif.uuid)) {
|
|
@@ -1139,7 +1169,7 @@ function Canvas({
|
|
|
1139
1169
|
return;
|
|
1140
1170
|
}
|
|
1141
1171
|
const { motif } = event;
|
|
1142
|
-
if (!motif || selectedMotifMeshState.current.has(motif)
|
|
1172
|
+
if (!motif || selectedMotifMeshState.current.has(motif)) {
|
|
1143
1173
|
return;
|
|
1144
1174
|
}
|
|
1145
1175
|
if (event.multiSelect && motif) {
|
|
@@ -1171,7 +1201,7 @@ function Canvas({
|
|
|
1171
1201
|
const deltaX = rawDeltaX / renderWidth * canvasRef.current.width;
|
|
1172
1202
|
const deltaY = rawDeltaY / renderHeight * canvasRef.current.height;
|
|
1173
1203
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1174
|
-
if (!lockedMotifIdState.current.
|
|
1204
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1175
1205
|
element.translate(-deltaX, -deltaY, 0);
|
|
1176
1206
|
}
|
|
1177
1207
|
});
|
|
@@ -1184,11 +1214,11 @@ function Canvas({
|
|
|
1184
1214
|
if (scene.current) {
|
|
1185
1215
|
const angle = directionVec.length() / scene.current.renderWidth * (3 * Math.PI);
|
|
1186
1216
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1187
|
-
if (!lockedMotifIdState.current.
|
|
1217
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1188
1218
|
element.rotate(axisVec, angle);
|
|
1189
1219
|
}
|
|
1190
1220
|
});
|
|
1191
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1221
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1192
1222
|
}
|
|
1193
1223
|
}
|
|
1194
1224
|
}
|
|
@@ -1201,7 +1231,7 @@ function Canvas({
|
|
|
1201
1231
|
const zoomSpeed = 0.1;
|
|
1202
1232
|
const zoomDirection = event.originalEvent.deltaY > 0 ? -1 : 1;
|
|
1203
1233
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1204
|
-
if (!lockedMotifIdState.current.
|
|
1234
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid) && !(element.scale <= 1 && zoomDirection === -1) && !(element.scale >= 30 && zoomDirection === 1)) {
|
|
1205
1235
|
const scaleFactor = 1 + zoomDirection * zoomSpeed;
|
|
1206
1236
|
element.multiplyScalar(scaleFactor);
|
|
1207
1237
|
}
|
|
@@ -1229,19 +1259,19 @@ function Canvas({
|
|
|
1229
1259
|
}
|
|
1230
1260
|
const angle = event.rotationAxis.length() / 500 * (6 * Math.PI);
|
|
1231
1261
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1232
|
-
if (!lockedMotifIdState.current.
|
|
1262
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1233
1263
|
element.rotate(event.rotationAxis, angle);
|
|
1234
1264
|
}
|
|
1235
1265
|
});
|
|
1236
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1266
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1237
1267
|
}
|
|
1238
1268
|
function onKeyboardTranslate(event) {
|
|
1239
1269
|
if (event.translationDirection.equals(Vec3.Zero)) {
|
|
1240
1270
|
return;
|
|
1241
1271
|
}
|
|
1242
|
-
event.translationDirection.multiplyScalar(
|
|
1272
|
+
event.translationDirection.multiplyScalar(4.5);
|
|
1243
1273
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1244
|
-
if (!lockedMotifIdState.current.
|
|
1274
|
+
if (!lockedMotifIdState.current.has(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1245
1275
|
element.translate(
|
|
1246
1276
|
event.translationDirection.x,
|
|
1247
1277
|
event.translationDirection.y,
|
|
@@ -1254,10 +1284,10 @@ function Canvas({
|
|
|
1254
1284
|
if (!event.rotationAxis.equals(Vec3.Zero) || !event.translationDirection.equals(Vec3.Zero)) {
|
|
1255
1285
|
return;
|
|
1256
1286
|
}
|
|
1257
|
-
if (!/^[1-9]$/.test(event.key) || Number(event.key) > motifs.length) {
|
|
1287
|
+
if (!/^[1-9]$/.test(event.key) || Number(event.key) > motifs.current.length) {
|
|
1258
1288
|
return;
|
|
1259
1289
|
}
|
|
1260
|
-
const motif = motifs[Number(event.key) - 1];
|
|
1290
|
+
const motif = motifs.current[Number(event.key) - 1];
|
|
1261
1291
|
if (selectedMotifMeshState.current.has(motif)) {
|
|
1262
1292
|
removeMotif(motif);
|
|
1263
1293
|
} else {
|
|
@@ -1280,8 +1310,8 @@ function Canvas({
|
|
|
1280
1310
|
return positions;
|
|
1281
1311
|
};
|
|
1282
1312
|
const updateMotifs = () => {
|
|
1283
|
-
const positions = calculatePositions(motifs.length);
|
|
1284
|
-
motifs.forEach((motifMesh, index) => {
|
|
1313
|
+
const positions = calculatePositions(motifs.current.length);
|
|
1314
|
+
motifs.current.forEach((motifMesh, index) => {
|
|
1285
1315
|
if (!scene.current?.children.has(motifMesh.uuid)) return;
|
|
1286
1316
|
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
1287
1317
|
motifMesh.setPosition(positions[index].x, positions[index].y, positions[index].z);
|
|
@@ -1291,9 +1321,6 @@ function Canvas({
|
|
|
1291
1321
|
motifMesh.setScale(scale);
|
|
1292
1322
|
});
|
|
1293
1323
|
};
|
|
1294
|
-
useEffect(() => {
|
|
1295
|
-
updateMotifs();
|
|
1296
|
-
}, [motifProps]);
|
|
1297
1324
|
useEffect(() => {
|
|
1298
1325
|
const unsubscribe = CanvasDataManager.subscribe("selectedMotifs" /* SELECTED_MOTIFS */, () => {
|
|
1299
1326
|
setSelectedmotifIds(CanvasDataManager.selectedMotifIds);
|
|
@@ -1305,13 +1332,13 @@ function Canvas({
|
|
|
1305
1332
|
CanvasDataManager.setSelectedMotifIds(selectedMotifIds);
|
|
1306
1333
|
}
|
|
1307
1334
|
selectedMotifMeshState.current.clear();
|
|
1308
|
-
motifs.forEach((motif) => {
|
|
1335
|
+
motifs.current.forEach((motif) => {
|
|
1309
1336
|
if (selectedMotifIds.has(motif.uuid)) {
|
|
1310
1337
|
selectedMotifMeshState.current.add(motif);
|
|
1311
1338
|
}
|
|
1312
1339
|
});
|
|
1313
1340
|
updateGlow();
|
|
1314
|
-
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs));
|
|
1341
|
+
if (showRMSD) setScoreRMSD(calculateRMSD(Array.from(selectedMotifMeshState.current), motifs.current));
|
|
1315
1342
|
}, [selectedMotifIds]);
|
|
1316
1343
|
useEffect(() => {
|
|
1317
1344
|
const unsubscribe = CanvasDataManager.subscribe("lockedMotifIds" /* LOCKED_MOTIF_IDS */, () => {
|
|
@@ -1352,8 +1379,8 @@ function Canvas({
|
|
|
1352
1379
|
if (!showRMSD) return;
|
|
1353
1380
|
if (CanvasDataManager.kabschRMSD !== kabschRMSD) {
|
|
1354
1381
|
CanvasDataManager.setKabschRMSD(kabschRMSD);
|
|
1355
|
-
} else if (CanvasDataManager.kabschRMSD.length !== motifs.length) {
|
|
1356
|
-
CanvasDataManager.setKabschRMSD(calculateAllKabschRMSD(motifs));
|
|
1382
|
+
} else if (CanvasDataManager.kabschRMSD.length !== motifs.current.length) {
|
|
1383
|
+
CanvasDataManager.setKabschRMSD(calculateAllKabschRMSD(motifs.current));
|
|
1357
1384
|
}
|
|
1358
1385
|
}, [kabschRMSD]);
|
|
1359
1386
|
useEffect(() => {
|
|
@@ -1372,84 +1399,91 @@ function Canvas({
|
|
|
1372
1399
|
rendererSizeIsWindow ? window.innerWidth : rendererWidth,
|
|
1373
1400
|
rendererSizeIsWindow ? window.innerHeight : rendererHeight
|
|
1374
1401
|
);
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1402
|
+
const eventManager = scene.current?.eventManager;
|
|
1403
|
+
eventManager.on(Events.EventType.OBJECT_SELECTED, onSelectMotif);
|
|
1404
|
+
eventManager.on(Events.EventType.OBJECT_DESELECTED, onDeselectMotif);
|
|
1405
|
+
eventManager.on(Events.EventType.POINTER_MOVE, onMouseMove);
|
|
1406
|
+
eventManager.on(Events.EventType.POINTER_WHEEL, onMouseScroll);
|
|
1407
|
+
eventManager.on(Events.EventType.POINTER_DOWN, onMouseDown);
|
|
1408
|
+
eventManager.on(Events.EventType.POINTER_UP, onMouseUp);
|
|
1409
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardRotate);
|
|
1410
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardTranslate);
|
|
1411
|
+
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardSelect);
|
|
1412
|
+
if (customEventProps) {
|
|
1413
|
+
customEventProps.forEach((customEventProp) => {
|
|
1414
|
+
switch (customEventProp.eventType) {
|
|
1415
|
+
// Handle Pointer Events
|
|
1416
|
+
case Events.EventType.POINTER_DOWN:
|
|
1417
|
+
case Events.EventType.POINTER_UP:
|
|
1418
|
+
case Events.EventType.POINTER_MOVE:
|
|
1419
|
+
case Events.EventType.POINTER_WHEEL:
|
|
1420
|
+
case Events.EventType.TOUCH_END:
|
|
1421
|
+
case Events.EventType.TOUCH_MOVE:
|
|
1422
|
+
case Events.EventType.TOUCH_START:
|
|
1423
|
+
eventManager.on(
|
|
1424
|
+
customEventProp.eventType,
|
|
1425
|
+
customEventProp.callback
|
|
1426
|
+
);
|
|
1427
|
+
break;
|
|
1428
|
+
// Handle Keyboard Events
|
|
1429
|
+
case Events.EventType.KEY_DOWN:
|
|
1430
|
+
case Events.EventType.KEY_UP:
|
|
1431
|
+
eventManager.on(
|
|
1432
|
+
customEventProp.eventType,
|
|
1433
|
+
customEventProp.callback
|
|
1434
|
+
);
|
|
1435
|
+
break;
|
|
1436
|
+
// Handle Pinch Events
|
|
1437
|
+
case Events.EventType.PINCH:
|
|
1438
|
+
case Events.EventType.PINCH_END:
|
|
1439
|
+
case Events.EventType.PINCH_START:
|
|
1440
|
+
eventManager.on(
|
|
1441
|
+
customEventProp.eventType,
|
|
1442
|
+
customEventProp.callback
|
|
1443
|
+
);
|
|
1444
|
+
break;
|
|
1445
|
+
// Handle Selection Events
|
|
1446
|
+
case Events.EventType.OBJECT_SELECTED:
|
|
1447
|
+
case Events.EventType.OBJECT_DESELECTED:
|
|
1448
|
+
eventManager.on(
|
|
1449
|
+
customEventProp.eventType,
|
|
1450
|
+
customEventProp.callback
|
|
1451
|
+
);
|
|
1452
|
+
break;
|
|
1453
|
+
// Handle Events
|
|
1454
|
+
default:
|
|
1455
|
+
eventManager.on(
|
|
1456
|
+
customEventProp.eventType,
|
|
1457
|
+
customEventProp.callback
|
|
1458
|
+
);
|
|
1459
|
+
break;
|
|
1460
|
+
}
|
|
1388
1461
|
});
|
|
1389
|
-
const eventManager = scene.current?.eventManager;
|
|
1390
|
-
eventManager.on(Events.EventType.OBJECT_SELECTED, onSelectMotif);
|
|
1391
|
-
eventManager.on(Events.EventType.OBJECT_DESELECTED, onDeselectMotif);
|
|
1392
|
-
eventManager.on(Events.EventType.POINTER_MOVE, onMouseMove);
|
|
1393
|
-
eventManager.on(Events.EventType.POINTER_WHEEL, onMouseScroll);
|
|
1394
|
-
eventManager.on(Events.EventType.POINTER_DOWN, onMouseDown);
|
|
1395
|
-
eventManager.on(Events.EventType.POINTER_UP, onMouseUp);
|
|
1396
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardRotate);
|
|
1397
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardTranslate);
|
|
1398
|
-
eventManager.on(Events.EventType.KEY_DOWN, onKeyboardSelect);
|
|
1399
|
-
if (customEventProps) {
|
|
1400
|
-
customEventProps.forEach((customEventProp) => {
|
|
1401
|
-
switch (customEventProp.eventType) {
|
|
1402
|
-
// Handle Pointer Events
|
|
1403
|
-
case Events.EventType.POINTER_DOWN:
|
|
1404
|
-
case Events.EventType.POINTER_UP:
|
|
1405
|
-
case Events.EventType.POINTER_MOVE:
|
|
1406
|
-
case Events.EventType.POINTER_WHEEL:
|
|
1407
|
-
case Events.EventType.TOUCH_END:
|
|
1408
|
-
case Events.EventType.TOUCH_MOVE:
|
|
1409
|
-
case Events.EventType.TOUCH_START:
|
|
1410
|
-
eventManager.on(
|
|
1411
|
-
customEventProp.eventType,
|
|
1412
|
-
customEventProp.callback
|
|
1413
|
-
);
|
|
1414
|
-
break;
|
|
1415
|
-
// Handle Keyboard Events
|
|
1416
|
-
case Events.EventType.KEY_DOWN:
|
|
1417
|
-
case Events.EventType.KEY_UP:
|
|
1418
|
-
eventManager.on(
|
|
1419
|
-
customEventProp.eventType,
|
|
1420
|
-
customEventProp.callback
|
|
1421
|
-
);
|
|
1422
|
-
break;
|
|
1423
|
-
// Handle Pinch Events
|
|
1424
|
-
case Events.EventType.PINCH:
|
|
1425
|
-
case Events.EventType.PINCH_END:
|
|
1426
|
-
case Events.EventType.PINCH_START:
|
|
1427
|
-
eventManager.on(
|
|
1428
|
-
customEventProp.eventType,
|
|
1429
|
-
customEventProp.callback
|
|
1430
|
-
);
|
|
1431
|
-
break;
|
|
1432
|
-
// Handle Selection Events
|
|
1433
|
-
case Events.EventType.OBJECT_SELECTED:
|
|
1434
|
-
case Events.EventType.OBJECT_DESELECTED:
|
|
1435
|
-
eventManager.on(
|
|
1436
|
-
customEventProp.eventType,
|
|
1437
|
-
customEventProp.callback
|
|
1438
|
-
);
|
|
1439
|
-
break;
|
|
1440
|
-
// Handle Events
|
|
1441
|
-
default:
|
|
1442
|
-
eventManager.on(
|
|
1443
|
-
customEventProp.eventType,
|
|
1444
|
-
customEventProp.callback
|
|
1445
|
-
);
|
|
1446
|
-
break;
|
|
1447
|
-
}
|
|
1448
|
-
});
|
|
1449
|
-
}
|
|
1450
1462
|
}
|
|
1463
|
+
scene.current.start();
|
|
1464
|
+
}
|
|
1465
|
+
}, []);
|
|
1466
|
+
useEffect(() => {
|
|
1467
|
+
if (!scene.current || !canvasRef.current) return;
|
|
1468
|
+
motifs.current.length = 0;
|
|
1469
|
+
motifProps.forEach((motifProp) => {
|
|
1470
|
+
motifs.current.push(motifProp.motif);
|
|
1471
|
+
});
|
|
1472
|
+
if (motifs.current.length > 0) {
|
|
1473
|
+
if (showRMSD) setKabschRMSD(calculateAllKabschRMSD(motifs.current));
|
|
1474
|
+
scene.current.removeAll();
|
|
1475
|
+
const positions = calculatePositions(motifs.current.length);
|
|
1476
|
+
motifs.current.forEach((motifMesh, index) => {
|
|
1477
|
+
scene.current?.add(motifMesh);
|
|
1478
|
+
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
1479
|
+
motifMesh.setPosition(positions[index].x, positions[index].y, positions[index].z);
|
|
1480
|
+
if (motifProps[index].rotation) motifMesh.setQuaternion(motifProps[index].rotation);
|
|
1481
|
+
let scale = canvasRef.current.width / 250;
|
|
1482
|
+
if (motifProps[index].scale) scale = motifProps[index].scale;
|
|
1483
|
+
motifMesh.setScale(scale);
|
|
1484
|
+
if (motifProps[index].locked) lockedMotifIdState.current.add(motifMesh.uuid);
|
|
1485
|
+
});
|
|
1451
1486
|
}
|
|
1452
|
-
scene.current?.start();
|
|
1453
1487
|
}, [rendererWidth, rendererHeight, rendererSizeIsWindow, motifProps]);
|
|
1454
1488
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("canvas", { ref: canvasRef }));
|
|
1455
1489
|
}
|
package/package.json
CHANGED
|
Binary file
|