@judah-silva/rnacanvas 0.0.5 → 0.0.6
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 +0 -5
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +43 -42
- package/dist/index.mjs +41 -40
- package/package.json +6 -2
package/README.md
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -112,6 +112,7 @@ declare class Motif extends Group<Residue> {
|
|
|
112
112
|
rotateByQuaternion(quat: Quat): void;
|
|
113
113
|
setQuaternion(quat: Quat): void;
|
|
114
114
|
multiplyScalar(scalar: number): void;
|
|
115
|
+
setScale(scale: number): void;
|
|
115
116
|
get uuid(): string;
|
|
116
117
|
get quat(): Quat;
|
|
117
118
|
get scale(): number;
|
|
@@ -334,7 +335,7 @@ declare class RenderScene {
|
|
|
334
335
|
* @author Judah Silva <jusilva@csumb.edu>
|
|
335
336
|
*/
|
|
336
337
|
|
|
337
|
-
declare function
|
|
338
|
+
declare function parseAtomCoords(meshObject: MotifMesh): Promise<Vec3[]>;
|
|
338
339
|
|
|
339
340
|
/**
|
|
340
341
|
* Copyright (c) 2025 RNA3DS Lab CSUMB.
|
|
@@ -342,6 +343,7 @@ declare function updateAllMotifs(motifMeshArray: Motif[]): Promise<void>;
|
|
|
342
343
|
* @author Judah Silva
|
|
343
344
|
*/
|
|
344
345
|
|
|
346
|
+
type MotifMesh = Record<string, any>;
|
|
345
347
|
/**
|
|
346
348
|
* ________________________________________________________________________________________________
|
|
347
349
|
*/
|
|
@@ -356,7 +358,7 @@ declare function updateAllMotifs(motifMeshArray: Motif[]): Promise<void>;
|
|
|
356
358
|
* @returns {Promise<Motif>}
|
|
357
359
|
* @async
|
|
358
360
|
*/
|
|
359
|
-
declare function getMotif(
|
|
361
|
+
declare function getMotif(motifName: string, motifMesh: MotifMesh, motifColorHex?: string): Promise<Motif>;
|
|
360
362
|
|
|
361
363
|
/**
|
|
362
364
|
* Copyright (c) 2025 RNA3DS Lab CSUMB.
|
|
@@ -521,4 +523,4 @@ declare function calculateRMSDSlide(coordinates1: Vec3[], coordinates2: Vec3[]):
|
|
|
521
523
|
|
|
522
524
|
declare function rotateAllPoints(atomCoords: Vec3[], quat: Quat): Vec3[];
|
|
523
525
|
|
|
524
|
-
export { Canvas, CanvasAttributeTypes, CanvasDataManager, type CanvasProps, type CustomEventProps, EventManager, Events, Group, Matrix4, MeshObject, Motif, type MotifProps, Quat, RenderScene, Residue, type ScoreInfo, Vec3, calculateAllKabschRMSD, calculateRMSD, calculateRMSDSlide, getMotif, getPoints, getRMSD, kabschSlidingWindow,
|
|
526
|
+
export { Canvas, CanvasAttributeTypes, CanvasDataManager, type CanvasProps, type CustomEventProps, EventManager, Events, Group, Matrix4, MeshObject, Motif, type MotifMesh, type MotifProps, Quat, RenderScene, Residue, type ScoreInfo, Vec3, calculateAllKabschRMSD, calculateRMSD, calculateRMSDSlide, getMotif, getPoints, getRMSD, kabschSlidingWindow, parseAtomCoords, rotateAllPoints };
|
package/dist/index.d.ts
CHANGED
|
@@ -112,6 +112,7 @@ declare class Motif extends Group<Residue> {
|
|
|
112
112
|
rotateByQuaternion(quat: Quat): void;
|
|
113
113
|
setQuaternion(quat: Quat): void;
|
|
114
114
|
multiplyScalar(scalar: number): void;
|
|
115
|
+
setScale(scale: number): void;
|
|
115
116
|
get uuid(): string;
|
|
116
117
|
get quat(): Quat;
|
|
117
118
|
get scale(): number;
|
|
@@ -334,7 +335,7 @@ declare class RenderScene {
|
|
|
334
335
|
* @author Judah Silva <jusilva@csumb.edu>
|
|
335
336
|
*/
|
|
336
337
|
|
|
337
|
-
declare function
|
|
338
|
+
declare function parseAtomCoords(meshObject: MotifMesh): Promise<Vec3[]>;
|
|
338
339
|
|
|
339
340
|
/**
|
|
340
341
|
* Copyright (c) 2025 RNA3DS Lab CSUMB.
|
|
@@ -342,6 +343,7 @@ declare function updateAllMotifs(motifMeshArray: Motif[]): Promise<void>;
|
|
|
342
343
|
* @author Judah Silva
|
|
343
344
|
*/
|
|
344
345
|
|
|
346
|
+
type MotifMesh = Record<string, any>;
|
|
345
347
|
/**
|
|
346
348
|
* ________________________________________________________________________________________________
|
|
347
349
|
*/
|
|
@@ -356,7 +358,7 @@ declare function updateAllMotifs(motifMeshArray: Motif[]): Promise<void>;
|
|
|
356
358
|
* @returns {Promise<Motif>}
|
|
357
359
|
* @async
|
|
358
360
|
*/
|
|
359
|
-
declare function getMotif(
|
|
361
|
+
declare function getMotif(motifName: string, motifMesh: MotifMesh, motifColorHex?: string): Promise<Motif>;
|
|
360
362
|
|
|
361
363
|
/**
|
|
362
364
|
* Copyright (c) 2025 RNA3DS Lab CSUMB.
|
|
@@ -521,4 +523,4 @@ declare function calculateRMSDSlide(coordinates1: Vec3[], coordinates2: Vec3[]):
|
|
|
521
523
|
|
|
522
524
|
declare function rotateAllPoints(atomCoords: Vec3[], quat: Quat): Vec3[];
|
|
523
525
|
|
|
524
|
-
export { Canvas, CanvasAttributeTypes, CanvasDataManager, type CanvasProps, type CustomEventProps, EventManager, Events, Group, Matrix4, MeshObject, Motif, type MotifProps, Quat, RenderScene, Residue, type ScoreInfo, Vec3, calculateAllKabschRMSD, calculateRMSD, calculateRMSDSlide, getMotif, getPoints, getRMSD, kabschSlidingWindow,
|
|
526
|
+
export { Canvas, CanvasAttributeTypes, CanvasDataManager, type CanvasProps, type CustomEventProps, EventManager, Events, Group, Matrix4, MeshObject, Motif, type MotifMesh, type MotifProps, Quat, RenderScene, Residue, type ScoreInfo, Vec3, calculateAllKabschRMSD, calculateRMSD, calculateRMSDSlide, getMotif, getPoints, getRMSD, kabschSlidingWindow, parseAtomCoords, rotateAllPoints };
|
package/dist/index.js
CHANGED
|
@@ -50,8 +50,8 @@ __export(index_exports, {
|
|
|
50
50
|
getPoints: () => getPoints,
|
|
51
51
|
getRMSD: () => getRMSD,
|
|
52
52
|
kabschSlidingWindow: () => kabschSlidingWindow,
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
parseAtomCoords: () => parseAtomCoords,
|
|
54
|
+
rotateAllPoints: () => rotateAllPoints
|
|
55
55
|
});
|
|
56
56
|
module.exports = __toCommonJS(index_exports);
|
|
57
57
|
|
|
@@ -269,6 +269,13 @@ var Motif = class extends Group {
|
|
|
269
269
|
this._node.scaling.z * scalar
|
|
270
270
|
);
|
|
271
271
|
}
|
|
272
|
+
setScale(scale) {
|
|
273
|
+
this._node.scaling = new import_core5.Vector3(
|
|
274
|
+
scale,
|
|
275
|
+
scale,
|
|
276
|
+
scale
|
|
277
|
+
);
|
|
278
|
+
}
|
|
272
279
|
get uuid() {
|
|
273
280
|
return this._node.uniqueId.toString();
|
|
274
281
|
}
|
|
@@ -813,12 +820,10 @@ var RenderScene = class {
|
|
|
813
820
|
};
|
|
814
821
|
|
|
815
822
|
// src/3D/utils/GetAtomInfo.ts
|
|
816
|
-
async function parseAtomCoords(
|
|
817
|
-
const response = await fetch(`/${fileName}`);
|
|
818
|
-
const jsonData = await response.json();
|
|
823
|
+
async function parseAtomCoords(meshObject) {
|
|
819
824
|
const coordinates = [];
|
|
820
|
-
for (const [key] of Object.entries(
|
|
821
|
-
const atomMap =
|
|
825
|
+
for (const [key] of Object.entries(meshObject)) {
|
|
826
|
+
const atomMap = meshObject[key][0];
|
|
822
827
|
if (atomMap[`"C1'"`]) {
|
|
823
828
|
coordinates.push(
|
|
824
829
|
new Vec3(
|
|
@@ -831,20 +836,6 @@ async function parseAtomCoords(fileName) {
|
|
|
831
836
|
}
|
|
832
837
|
return coordinates;
|
|
833
838
|
}
|
|
834
|
-
async function getAtomCoords(fileName) {
|
|
835
|
-
const coordinates = await parseAtomCoords(fileName);
|
|
836
|
-
return coordinates;
|
|
837
|
-
}
|
|
838
|
-
async function updateAllMotifs(motifMeshArray) {
|
|
839
|
-
const fileNames = [];
|
|
840
|
-
for (const motif of motifMeshArray) {
|
|
841
|
-
fileNames.push(motif.userData.fileName);
|
|
842
|
-
}
|
|
843
|
-
const atomInfoLists = await Promise.all(fileNames.map((o) => getAtomCoords(o)));
|
|
844
|
-
for (let i = 0; i < motifMeshArray.length; i += 1) {
|
|
845
|
-
motifMeshArray[i].userData.atomInfo = atomInfoLists[i];
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
839
|
|
|
849
840
|
// src/3D/utils/GetPoints.ts
|
|
850
841
|
function getPoints(nucleotideData) {
|
|
@@ -858,12 +849,10 @@ function getPoints(nucleotideData) {
|
|
|
858
849
|
}
|
|
859
850
|
|
|
860
851
|
// src/3D/utils/GetMotif.ts
|
|
861
|
-
async function getMotif(
|
|
862
|
-
const motif = new Motif(`${
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
for (const [key] of Object.entries(jsonObject)) {
|
|
866
|
-
const { vertices, indices } = getPoints(jsonObject[key]);
|
|
852
|
+
async function getMotif(motifName, motifMesh, motifColorHex = "0xcc2900") {
|
|
853
|
+
const motif = new Motif(`${motifName}_motif`);
|
|
854
|
+
for (const [key] of Object.entries(motifMesh)) {
|
|
855
|
+
const { vertices, indices } = getPoints(motifMesh[key]);
|
|
867
856
|
const residue = new Residue("residue");
|
|
868
857
|
const backboneMesh = new MeshObject(`backbone_${key}`);
|
|
869
858
|
backboneMesh.applyVertexData(vertices[0], indices[0]);
|
|
@@ -875,7 +864,8 @@ async function getMotif(motifJSONFileName, motifColorHex = "0xcc2900") {
|
|
|
875
864
|
residue.addChild(ringMesh);
|
|
876
865
|
motif.addChild(residue);
|
|
877
866
|
}
|
|
878
|
-
motif.userData.fileName =
|
|
867
|
+
motif.userData.fileName = motifName;
|
|
868
|
+
motif.userData.atomInfo = await parseAtomCoords(motifMesh);
|
|
879
869
|
return motif;
|
|
880
870
|
}
|
|
881
871
|
|
|
@@ -970,6 +960,7 @@ function getRMSD(a, b) {
|
|
|
970
960
|
if (a instanceof Motif && b instanceof Motif) {
|
|
971
961
|
newCoords1 = rotateAllPoints(a.userData.atomInfo, a.quat);
|
|
972
962
|
newCoords2 = rotateAllPoints(b.userData.atomInfo, b.quat);
|
|
963
|
+
return calculateRMSDSlide(newCoords1, newCoords2);
|
|
973
964
|
} else {
|
|
974
965
|
return -1;
|
|
975
966
|
}
|
|
@@ -1179,7 +1170,6 @@ function Canvas({
|
|
|
1179
1170
|
if (!selectedMotifMeshState.current.has(motif)) {
|
|
1180
1171
|
return;
|
|
1181
1172
|
}
|
|
1182
|
-
console.log("removing motif: ", motif);
|
|
1183
1173
|
selectedMotifMeshState.current.delete(motif);
|
|
1184
1174
|
setSelectedmotifIds((prevState) => {
|
|
1185
1175
|
const newState = new Set(prevState);
|
|
@@ -1267,10 +1257,12 @@ function Canvas({
|
|
|
1267
1257
|
const zoomSpeed = 0.1;
|
|
1268
1258
|
const zoomDirection = event.originalEvent.deltaY > 0 ? -1 : 1;
|
|
1269
1259
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1270
|
-
if (!lockedMotifIdState.current.includes(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1260
|
+
if (!lockedMotifIdState.current.includes(element.uuid) && !hardLockedMotifIds.includes(element.uuid) && !(element.scale <= 1 && zoomDirection === -1) && !(element.scale >= 30 && zoomDirection === 1)) {
|
|
1271
1261
|
const scaleFactor = 1 + zoomDirection * zoomSpeed;
|
|
1272
1262
|
element.multiplyScalar(scaleFactor);
|
|
1273
1263
|
}
|
|
1264
|
+
if (element.scale < 1) element.setScale(1);
|
|
1265
|
+
if (element.scale > 30) element.setScale(30);
|
|
1274
1266
|
});
|
|
1275
1267
|
}
|
|
1276
1268
|
}
|
|
@@ -1323,10 +1315,8 @@ function Canvas({
|
|
|
1323
1315
|
}
|
|
1324
1316
|
const motif = motifs[Number(event.key) - 1];
|
|
1325
1317
|
if (selectedMotifMeshState.current.has(motif)) {
|
|
1326
|
-
console.log("removing motif");
|
|
1327
1318
|
removeMotif(motif);
|
|
1328
1319
|
} else {
|
|
1329
|
-
console.log("adding motif");
|
|
1330
1320
|
addMotif(motif);
|
|
1331
1321
|
}
|
|
1332
1322
|
}
|
|
@@ -1345,6 +1335,21 @@ function Canvas({
|
|
|
1345
1335
|
}
|
|
1346
1336
|
return positions;
|
|
1347
1337
|
};
|
|
1338
|
+
const updateMotifs = () => {
|
|
1339
|
+
const positions = calculatePositions(motifs.length);
|
|
1340
|
+
motifs.forEach((motifMesh, index) => {
|
|
1341
|
+
if (!scene.current?.children.has(motifMesh.uuid)) return;
|
|
1342
|
+
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
1343
|
+
motifMesh.setPosition(positions[index].x, positions[index].y, positions[index].z);
|
|
1344
|
+
if (motifProps[index].rotation) motifMesh.setQuaternion(motifProps[index].rotation);
|
|
1345
|
+
let scale = canvasRef.current.width / 250;
|
|
1346
|
+
if (motifProps[index].scale) scale = motifProps[index].scale;
|
|
1347
|
+
motifMesh.setScale(scale);
|
|
1348
|
+
});
|
|
1349
|
+
};
|
|
1350
|
+
(0, import_react.useEffect)(() => {
|
|
1351
|
+
updateMotifs();
|
|
1352
|
+
}, [motifProps]);
|
|
1348
1353
|
(0, import_react.useEffect)(() => {
|
|
1349
1354
|
const unsubscribe = CanvasDataManager.subscribe("selectedMotifs" /* SELECTED_MOTIFS */, () => {
|
|
1350
1355
|
setSelectedmotifIds(CanvasDataManager.selectedMotifIds);
|
|
@@ -1399,6 +1404,8 @@ function Canvas({
|
|
|
1399
1404
|
(0, import_react.useEffect)(() => {
|
|
1400
1405
|
if (CanvasDataManager.kabschRMSD !== kabschRMSD) {
|
|
1401
1406
|
CanvasDataManager.setKabschRMSD(kabschRMSD);
|
|
1407
|
+
} else if (CanvasDataManager.kabschRMSD.length !== motifs.length) {
|
|
1408
|
+
CanvasDataManager.setKabschRMSD(calculateAllKabschRMSD(motifs));
|
|
1402
1409
|
}
|
|
1403
1410
|
}, [kabschRMSD]);
|
|
1404
1411
|
(0, import_react.useEffect)(() => {
|
|
@@ -1418,12 +1425,10 @@ function Canvas({
|
|
|
1418
1425
|
rendererSizeIsWindow ? window.innerHeight : rendererHeight
|
|
1419
1426
|
);
|
|
1420
1427
|
}
|
|
1421
|
-
const positions = calculatePositions(motifs.length);
|
|
1422
1428
|
if (motifs.length > 0) {
|
|
1423
|
-
|
|
1424
|
-
setKabschRMSD(calculateAllKabschRMSD(motifs));
|
|
1425
|
-
});
|
|
1429
|
+
setKabschRMSD(calculateAllKabschRMSD(motifs));
|
|
1426
1430
|
if (scene.current.children.size !== motifs.length) {
|
|
1431
|
+
const positions = calculatePositions(motifs.length);
|
|
1427
1432
|
motifs.forEach((motifMesh, index) => {
|
|
1428
1433
|
scene.current?.add(motifMesh);
|
|
1429
1434
|
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
@@ -1494,10 +1499,6 @@ function Canvas({
|
|
|
1494
1499
|
}
|
|
1495
1500
|
});
|
|
1496
1501
|
}
|
|
1497
|
-
} else {
|
|
1498
|
-
motifs.forEach((motifMesh) => {
|
|
1499
|
-
scene.current?.add(motifMesh);
|
|
1500
|
-
});
|
|
1501
1502
|
}
|
|
1502
1503
|
}
|
|
1503
1504
|
scene.current?.start();
|
|
@@ -1526,6 +1527,6 @@ function Canvas({
|
|
|
1526
1527
|
getPoints,
|
|
1527
1528
|
getRMSD,
|
|
1528
1529
|
kabschSlidingWindow,
|
|
1529
|
-
|
|
1530
|
-
|
|
1530
|
+
parseAtomCoords,
|
|
1531
|
+
rotateAllPoints
|
|
1531
1532
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -212,6 +212,13 @@ var Motif = class extends Group {
|
|
|
212
212
|
this._node.scaling.z * scalar
|
|
213
213
|
);
|
|
214
214
|
}
|
|
215
|
+
setScale(scale) {
|
|
216
|
+
this._node.scaling = new Vector32(
|
|
217
|
+
scale,
|
|
218
|
+
scale,
|
|
219
|
+
scale
|
|
220
|
+
);
|
|
221
|
+
}
|
|
215
222
|
get uuid() {
|
|
216
223
|
return this._node.uniqueId.toString();
|
|
217
224
|
}
|
|
@@ -756,12 +763,10 @@ var RenderScene = class {
|
|
|
756
763
|
};
|
|
757
764
|
|
|
758
765
|
// src/3D/utils/GetAtomInfo.ts
|
|
759
|
-
async function parseAtomCoords(
|
|
760
|
-
const response = await fetch(`/${fileName}`);
|
|
761
|
-
const jsonData = await response.json();
|
|
766
|
+
async function parseAtomCoords(meshObject) {
|
|
762
767
|
const coordinates = [];
|
|
763
|
-
for (const [key] of Object.entries(
|
|
764
|
-
const atomMap =
|
|
768
|
+
for (const [key] of Object.entries(meshObject)) {
|
|
769
|
+
const atomMap = meshObject[key][0];
|
|
765
770
|
if (atomMap[`"C1'"`]) {
|
|
766
771
|
coordinates.push(
|
|
767
772
|
new Vec3(
|
|
@@ -774,20 +779,6 @@ async function parseAtomCoords(fileName) {
|
|
|
774
779
|
}
|
|
775
780
|
return coordinates;
|
|
776
781
|
}
|
|
777
|
-
async function getAtomCoords(fileName) {
|
|
778
|
-
const coordinates = await parseAtomCoords(fileName);
|
|
779
|
-
return coordinates;
|
|
780
|
-
}
|
|
781
|
-
async function updateAllMotifs(motifMeshArray) {
|
|
782
|
-
const fileNames = [];
|
|
783
|
-
for (const motif of motifMeshArray) {
|
|
784
|
-
fileNames.push(motif.userData.fileName);
|
|
785
|
-
}
|
|
786
|
-
const atomInfoLists = await Promise.all(fileNames.map((o) => getAtomCoords(o)));
|
|
787
|
-
for (let i = 0; i < motifMeshArray.length; i += 1) {
|
|
788
|
-
motifMeshArray[i].userData.atomInfo = atomInfoLists[i];
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
782
|
|
|
792
783
|
// src/3D/utils/GetPoints.ts
|
|
793
784
|
function getPoints(nucleotideData) {
|
|
@@ -801,12 +792,10 @@ function getPoints(nucleotideData) {
|
|
|
801
792
|
}
|
|
802
793
|
|
|
803
794
|
// src/3D/utils/GetMotif.ts
|
|
804
|
-
async function getMotif(
|
|
805
|
-
const motif = new Motif(`${
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
for (const [key] of Object.entries(jsonObject)) {
|
|
809
|
-
const { vertices, indices } = getPoints(jsonObject[key]);
|
|
795
|
+
async function getMotif(motifName, motifMesh, motifColorHex = "0xcc2900") {
|
|
796
|
+
const motif = new Motif(`${motifName}_motif`);
|
|
797
|
+
for (const [key] of Object.entries(motifMesh)) {
|
|
798
|
+
const { vertices, indices } = getPoints(motifMesh[key]);
|
|
810
799
|
const residue = new Residue("residue");
|
|
811
800
|
const backboneMesh = new MeshObject(`backbone_${key}`);
|
|
812
801
|
backboneMesh.applyVertexData(vertices[0], indices[0]);
|
|
@@ -818,7 +807,8 @@ async function getMotif(motifJSONFileName, motifColorHex = "0xcc2900") {
|
|
|
818
807
|
residue.addChild(ringMesh);
|
|
819
808
|
motif.addChild(residue);
|
|
820
809
|
}
|
|
821
|
-
motif.userData.fileName =
|
|
810
|
+
motif.userData.fileName = motifName;
|
|
811
|
+
motif.userData.atomInfo = await parseAtomCoords(motifMesh);
|
|
822
812
|
return motif;
|
|
823
813
|
}
|
|
824
814
|
|
|
@@ -913,6 +903,7 @@ function getRMSD(a, b) {
|
|
|
913
903
|
if (a instanceof Motif && b instanceof Motif) {
|
|
914
904
|
newCoords1 = rotateAllPoints(a.userData.atomInfo, a.quat);
|
|
915
905
|
newCoords2 = rotateAllPoints(b.userData.atomInfo, b.quat);
|
|
906
|
+
return calculateRMSDSlide(newCoords1, newCoords2);
|
|
916
907
|
} else {
|
|
917
908
|
return -1;
|
|
918
909
|
}
|
|
@@ -1122,7 +1113,6 @@ function Canvas({
|
|
|
1122
1113
|
if (!selectedMotifMeshState.current.has(motif)) {
|
|
1123
1114
|
return;
|
|
1124
1115
|
}
|
|
1125
|
-
console.log("removing motif: ", motif);
|
|
1126
1116
|
selectedMotifMeshState.current.delete(motif);
|
|
1127
1117
|
setSelectedmotifIds((prevState) => {
|
|
1128
1118
|
const newState = new Set(prevState);
|
|
@@ -1210,10 +1200,12 @@ function Canvas({
|
|
|
1210
1200
|
const zoomSpeed = 0.1;
|
|
1211
1201
|
const zoomDirection = event.originalEvent.deltaY > 0 ? -1 : 1;
|
|
1212
1202
|
selectedMotifMeshState.current.forEach((element) => {
|
|
1213
|
-
if (!lockedMotifIdState.current.includes(element.uuid) && !hardLockedMotifIds.includes(element.uuid)) {
|
|
1203
|
+
if (!lockedMotifIdState.current.includes(element.uuid) && !hardLockedMotifIds.includes(element.uuid) && !(element.scale <= 1 && zoomDirection === -1) && !(element.scale >= 30 && zoomDirection === 1)) {
|
|
1214
1204
|
const scaleFactor = 1 + zoomDirection * zoomSpeed;
|
|
1215
1205
|
element.multiplyScalar(scaleFactor);
|
|
1216
1206
|
}
|
|
1207
|
+
if (element.scale < 1) element.setScale(1);
|
|
1208
|
+
if (element.scale > 30) element.setScale(30);
|
|
1217
1209
|
});
|
|
1218
1210
|
}
|
|
1219
1211
|
}
|
|
@@ -1266,10 +1258,8 @@ function Canvas({
|
|
|
1266
1258
|
}
|
|
1267
1259
|
const motif = motifs[Number(event.key) - 1];
|
|
1268
1260
|
if (selectedMotifMeshState.current.has(motif)) {
|
|
1269
|
-
console.log("removing motif");
|
|
1270
1261
|
removeMotif(motif);
|
|
1271
1262
|
} else {
|
|
1272
|
-
console.log("adding motif");
|
|
1273
1263
|
addMotif(motif);
|
|
1274
1264
|
}
|
|
1275
1265
|
}
|
|
@@ -1288,6 +1278,21 @@ function Canvas({
|
|
|
1288
1278
|
}
|
|
1289
1279
|
return positions;
|
|
1290
1280
|
};
|
|
1281
|
+
const updateMotifs = () => {
|
|
1282
|
+
const positions = calculatePositions(motifs.length);
|
|
1283
|
+
motifs.forEach((motifMesh, index) => {
|
|
1284
|
+
if (!scene.current?.children.has(motifMesh.uuid)) return;
|
|
1285
|
+
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
1286
|
+
motifMesh.setPosition(positions[index].x, positions[index].y, positions[index].z);
|
|
1287
|
+
if (motifProps[index].rotation) motifMesh.setQuaternion(motifProps[index].rotation);
|
|
1288
|
+
let scale = canvasRef.current.width / 250;
|
|
1289
|
+
if (motifProps[index].scale) scale = motifProps[index].scale;
|
|
1290
|
+
motifMesh.setScale(scale);
|
|
1291
|
+
});
|
|
1292
|
+
};
|
|
1293
|
+
useEffect(() => {
|
|
1294
|
+
updateMotifs();
|
|
1295
|
+
}, [motifProps]);
|
|
1291
1296
|
useEffect(() => {
|
|
1292
1297
|
const unsubscribe = CanvasDataManager.subscribe("selectedMotifs" /* SELECTED_MOTIFS */, () => {
|
|
1293
1298
|
setSelectedmotifIds(CanvasDataManager.selectedMotifIds);
|
|
@@ -1342,6 +1347,8 @@ function Canvas({
|
|
|
1342
1347
|
useEffect(() => {
|
|
1343
1348
|
if (CanvasDataManager.kabschRMSD !== kabschRMSD) {
|
|
1344
1349
|
CanvasDataManager.setKabschRMSD(kabschRMSD);
|
|
1350
|
+
} else if (CanvasDataManager.kabschRMSD.length !== motifs.length) {
|
|
1351
|
+
CanvasDataManager.setKabschRMSD(calculateAllKabschRMSD(motifs));
|
|
1345
1352
|
}
|
|
1346
1353
|
}, [kabschRMSD]);
|
|
1347
1354
|
useEffect(() => {
|
|
@@ -1361,12 +1368,10 @@ function Canvas({
|
|
|
1361
1368
|
rendererSizeIsWindow ? window.innerHeight : rendererHeight
|
|
1362
1369
|
);
|
|
1363
1370
|
}
|
|
1364
|
-
const positions = calculatePositions(motifs.length);
|
|
1365
1371
|
if (motifs.length > 0) {
|
|
1366
|
-
|
|
1367
|
-
setKabschRMSD(calculateAllKabschRMSD(motifs));
|
|
1368
|
-
});
|
|
1372
|
+
setKabschRMSD(calculateAllKabschRMSD(motifs));
|
|
1369
1373
|
if (scene.current.children.size !== motifs.length) {
|
|
1374
|
+
const positions = calculatePositions(motifs.length);
|
|
1370
1375
|
motifs.forEach((motifMesh, index) => {
|
|
1371
1376
|
scene.current?.add(motifMesh);
|
|
1372
1377
|
if (motifProps[index].position) positions[index] = motifProps[index].position.clone();
|
|
@@ -1437,10 +1442,6 @@ function Canvas({
|
|
|
1437
1442
|
}
|
|
1438
1443
|
});
|
|
1439
1444
|
}
|
|
1440
|
-
} else {
|
|
1441
|
-
motifs.forEach((motifMesh) => {
|
|
1442
|
-
scene.current?.add(motifMesh);
|
|
1443
|
-
});
|
|
1444
1445
|
}
|
|
1445
1446
|
}
|
|
1446
1447
|
scene.current?.start();
|
|
@@ -1468,6 +1469,6 @@ export {
|
|
|
1468
1469
|
getPoints,
|
|
1469
1470
|
getRMSD,
|
|
1470
1471
|
kabschSlidingWindow,
|
|
1471
|
-
|
|
1472
|
-
|
|
1472
|
+
parseAtomCoords,
|
|
1473
|
+
rotateAllPoints
|
|
1473
1474
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@judah-silva/rnacanvas",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "A 3D Canvas for displaying and interacting with custom RNA models. Powered by BabylonJS.",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"main": "./dist/index.js",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/RNAStructureAnalysisLab/RNACanvas"
|
|
10
|
+
},
|
|
6
11
|
"module": "./dist/index.mjs",
|
|
7
12
|
"scripts": {
|
|
8
13
|
"build": "tsup"
|
|
@@ -14,7 +19,6 @@
|
|
|
14
19
|
"test"
|
|
15
20
|
],
|
|
16
21
|
"author": "Judah Silva",
|
|
17
|
-
"license": "MIT",
|
|
18
22
|
"dependencies": {
|
|
19
23
|
"@babylonjs/core": "^7.50.0",
|
|
20
24
|
"numeric": "^1.2.6",
|