@archvisioninc/canvas 3.3.7 → 3.3.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_DEV.md
CHANGED
|
@@ -30,7 +30,10 @@ You will need to be invited to the Archvision, Inc. team on [NPM](https://npmjs.
|
|
|
30
30
|
|
|
31
31
|
Since the canvas package is under Archvision, Inc. It will be identified as [@archvisioninc/canvas](https://npmjs.com/package/@archvisioninc/canvas).
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
> npm has updated their packaging publishing process that may require the developer to add 2FA to their account. Once this is added to the developer's account, they will need to run
|
|
34
|
+
>> npm login
|
|
35
|
+
>
|
|
36
|
+
> to reauthenticate with the 2FA enabled. This 2FA process will also be required when publishing a new version of canvas to npm.
|
|
34
37
|
|
|
35
38
|
## Project structure and organization
|
|
36
39
|
This project's main development environment is found in `/src`. Each file and folder, except the `/src/package` folder,
|
|
@@ -257,6 +257,60 @@ const dataUrlToBlob = dataURI => {
|
|
|
257
257
|
});
|
|
258
258
|
return blob;
|
|
259
259
|
};
|
|
260
|
+
const getActiveAnimationGroup = animationGroups => {
|
|
261
|
+
const selectedAnimationIndex = scene.metadata?.selectedAnimation;
|
|
262
|
+
if (selectedAnimationIndex === null || selectedAnimationIndex === undefined) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
return animationGroups.find((_group, index) => {
|
|
266
|
+
return `${index}` === `${selectedAnimationIndex}`;
|
|
267
|
+
}) || null;
|
|
268
|
+
};
|
|
269
|
+
let animationSyncObserver = null;
|
|
270
|
+
let lastAnimationSerializeAt = 0;
|
|
271
|
+
const ANIMATION_SYNC_MS = 50;
|
|
272
|
+
const pushAnimationStateToReact = () => {
|
|
273
|
+
const activeAnimationGroup = getActiveAnimationGroup(scene.animationGroups || []);
|
|
274
|
+
syncSelectedAnimationMeta(activeAnimationGroup);
|
|
275
|
+
const now = performance.now();
|
|
276
|
+
if (props.setSerializedData && now - lastAnimationSerializeAt >= ANIMATION_SYNC_MS) {
|
|
277
|
+
lastAnimationSerializeAt = now;
|
|
278
|
+
props.setSerializedData(serializeScene());
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
const ensureAnimationStateSync = () => {
|
|
282
|
+
if (animationSyncObserver || !scene?.onBeforeRenderObservable) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
animationSyncObserver = scene.onBeforeRenderObservable.add(() => {
|
|
286
|
+
const activeAnimationGroup = getActiveAnimationGroup(scene.animationGroups || []);
|
|
287
|
+
if (!activeAnimationGroup) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
pushAnimationStateToReact();
|
|
291
|
+
});
|
|
292
|
+
};
|
|
293
|
+
const syncSelectedAnimationMeta = animationGroup => {
|
|
294
|
+
if (!scene.metadata) return;
|
|
295
|
+
if (!animationGroup) {
|
|
296
|
+
scene.metadata.selectedAnimationTime = 0;
|
|
297
|
+
scene.metadata.selectedAnimationProgress = 0;
|
|
298
|
+
scene.metadata.selectedAnimationDuration = 0;
|
|
299
|
+
scene.metadata.selectedAnimationIsPlaying = false;
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const runtimeAnimation = animationGroup.animatables?.[0]?.getAnimations?.()?.[0];
|
|
303
|
+
const currentFrame = runtimeAnimation?.currentFrame ?? animationGroup.from ?? 0;
|
|
304
|
+
const from = animationGroup.from ?? 0;
|
|
305
|
+
const to = animationGroup.to ?? 0;
|
|
306
|
+
const totalFrames = Math.max(to - from, 1);
|
|
307
|
+
const progress = BABYLON.Scalar.Clamp((currentFrame - from) / totalFrames, 0, 1);
|
|
308
|
+
const duration = animationGroup.getLength?.() ?? 0;
|
|
309
|
+
scene.metadata.selectedAnimationProgress = progress;
|
|
310
|
+
scene.metadata.selectedAnimationTime = progress * duration;
|
|
311
|
+
scene.metadata.selectedAnimationDuration = duration;
|
|
312
|
+
scene.metadata.selectedAnimationIsPlaying = Boolean(animationGroup.isPlaying);
|
|
313
|
+
};
|
|
260
314
|
export const updateMaterial = inboundData => {
|
|
261
315
|
const {
|
|
262
316
|
payload
|
|
@@ -599,6 +653,10 @@ export const updateMesh = inboundData => {
|
|
|
599
653
|
animationId,
|
|
600
654
|
resetAnimation,
|
|
601
655
|
loopAnimation = true,
|
|
656
|
+
playAnimation,
|
|
657
|
+
pauseAnimation,
|
|
658
|
+
seekAnimation,
|
|
659
|
+
animationProgress,
|
|
602
660
|
sourceUnit,
|
|
603
661
|
displayUnit
|
|
604
662
|
} = payload;
|
|
@@ -741,6 +799,8 @@ export const updateMesh = inboundData => {
|
|
|
741
799
|
if (resetAnimation) {
|
|
742
800
|
stopAllAnimationGroups();
|
|
743
801
|
newMetaDataEntry('selectedAnimation', null);
|
|
802
|
+
syncSelectedAnimationMeta(null);
|
|
803
|
+
props.setSerializedData?.(serializeScene());
|
|
744
804
|
}
|
|
745
805
|
|
|
746
806
|
// Change active animation
|
|
@@ -750,8 +810,39 @@ export const updateMesh = inboundData => {
|
|
|
750
810
|
if (animationGroup) {
|
|
751
811
|
animationGroup.start(Boolean(loopAnimation));
|
|
752
812
|
newMetaDataEntry('selectedAnimation', `${animationId}`);
|
|
813
|
+
syncSelectedAnimationMeta(animationGroup);
|
|
814
|
+
ensureAnimationStateSync();
|
|
815
|
+
props.setSerializedData?.(serializeScene());
|
|
753
816
|
}
|
|
754
817
|
}
|
|
818
|
+
const activeAnimationGroup = getActiveAnimationGroup(animationGroups);
|
|
819
|
+
|
|
820
|
+
// Play current animation
|
|
821
|
+
if (playAnimation && activeAnimationGroup) {
|
|
822
|
+
activeAnimationGroup.play(Boolean(loopAnimation));
|
|
823
|
+
syncSelectedAnimationMeta(activeAnimationGroup);
|
|
824
|
+
ensureAnimationStateSync();
|
|
825
|
+
props.setSerializedData?.(serializeScene());
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// Pause current animation
|
|
829
|
+
if (pauseAnimation && activeAnimationGroup) {
|
|
830
|
+
activeAnimationGroup.pause();
|
|
831
|
+
syncSelectedAnimationMeta(activeAnimationGroup);
|
|
832
|
+
props.setSerializedData?.(serializeScene());
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// Seek current animation to a progress position (0–1)
|
|
836
|
+
if (seekAnimation && activeAnimationGroup && animationProgress !== undefined) {
|
|
837
|
+
const {
|
|
838
|
+
from,
|
|
839
|
+
to
|
|
840
|
+
} = activeAnimationGroup;
|
|
841
|
+
const frame = from + animationProgress * (to - from);
|
|
842
|
+
activeAnimationGroup.goToFrame(frame);
|
|
843
|
+
syncSelectedAnimationMeta(activeAnimationGroup);
|
|
844
|
+
props.setSerializedData?.(serializeScene());
|
|
845
|
+
}
|
|
755
846
|
|
|
756
847
|
// Bounding Box Toggle
|
|
757
848
|
if (boundingBoxEnabled !== undefined) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@archvisioninc/canvas",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.9",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "dist/Canvas.js",
|
|
6
6
|
"module": "dist/Canvas.js",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
]
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
+
"@archvisioninc/canvas": "^3.3.8",
|
|
31
32
|
"d3-array": "^3.2.2",
|
|
32
33
|
"lodash": "^4.17.21",
|
|
33
34
|
"styled-components": "^5.3.6"
|
|
@@ -317,6 +317,85 @@ const dataUrlToBlob = dataURI => {
|
|
|
317
317
|
return blob;
|
|
318
318
|
};
|
|
319
319
|
|
|
320
|
+
const getActiveAnimationGroup = animationGroups => {
|
|
321
|
+
const selectedAnimationIndex = scene.metadata?.selectedAnimation;
|
|
322
|
+
|
|
323
|
+
if (selectedAnimationIndex === null || selectedAnimationIndex === undefined) {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return animationGroups.find((_group, index) => {
|
|
328
|
+
return `${index}` === `${selectedAnimationIndex}`;
|
|
329
|
+
}) || null;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
let animationSyncObserver = null;
|
|
333
|
+
let lastAnimationSerializeAt = 0;
|
|
334
|
+
const ANIMATION_SYNC_MS = 50;
|
|
335
|
+
|
|
336
|
+
const pushAnimationStateToReact = () => {
|
|
337
|
+
const activeAnimationGroup = getActiveAnimationGroup(scene.animationGroups || []);
|
|
338
|
+
|
|
339
|
+
syncSelectedAnimationMeta(activeAnimationGroup);
|
|
340
|
+
|
|
341
|
+
const now = performance.now();
|
|
342
|
+
if (
|
|
343
|
+
props.setSerializedData
|
|
344
|
+
&& now - lastAnimationSerializeAt >= ANIMATION_SYNC_MS
|
|
345
|
+
) {
|
|
346
|
+
lastAnimationSerializeAt = now;
|
|
347
|
+
props.setSerializedData(serializeScene());
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
const ensureAnimationStateSync = () => {
|
|
352
|
+
if (animationSyncObserver || !scene?.onBeforeRenderObservable) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
animationSyncObserver = scene.onBeforeRenderObservable.add(() => {
|
|
357
|
+
const activeAnimationGroup = getActiveAnimationGroup(scene.animationGroups || []);
|
|
358
|
+
|
|
359
|
+
if (!activeAnimationGroup) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
pushAnimationStateToReact();
|
|
364
|
+
});
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
const syncSelectedAnimationMeta = animationGroup => {
|
|
368
|
+
if (!scene.metadata) return;
|
|
369
|
+
|
|
370
|
+
if (!animationGroup) {
|
|
371
|
+
scene.metadata.selectedAnimationTime = 0;
|
|
372
|
+
scene.metadata.selectedAnimationProgress = 0;
|
|
373
|
+
scene.metadata.selectedAnimationDuration = 0;
|
|
374
|
+
scene.metadata.selectedAnimationIsPlaying = false;
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const runtimeAnimation = animationGroup.animatables?.[0]?.getAnimations?.()?.[0];
|
|
379
|
+
const currentFrame = runtimeAnimation?.currentFrame ?? animationGroup.from ?? 0;
|
|
380
|
+
const from = animationGroup.from ?? 0;
|
|
381
|
+
const to = animationGroup.to ?? 0;
|
|
382
|
+
const totalFrames = Math.max(to - from, 1);
|
|
383
|
+
|
|
384
|
+
const progress = BABYLON.Scalar.Clamp(
|
|
385
|
+
(currentFrame - from) / totalFrames,
|
|
386
|
+
0,
|
|
387
|
+
1
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
const duration = animationGroup.getLength?.() ?? 0;
|
|
391
|
+
|
|
392
|
+
scene.metadata.selectedAnimationProgress = progress;
|
|
393
|
+
scene.metadata.selectedAnimationTime = progress * duration;
|
|
394
|
+
scene.metadata.selectedAnimationDuration = duration;
|
|
395
|
+
scene.metadata.selectedAnimationIsPlaying = Boolean(animationGroup.isPlaying);
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
|
|
320
399
|
export const updateMaterial = inboundData => {
|
|
321
400
|
const { payload } = inboundData;
|
|
322
401
|
const {
|
|
@@ -669,6 +748,10 @@ export const updateMesh = inboundData => {
|
|
|
669
748
|
animationId,
|
|
670
749
|
resetAnimation,
|
|
671
750
|
loopAnimation = true,
|
|
751
|
+
playAnimation,
|
|
752
|
+
pauseAnimation,
|
|
753
|
+
seekAnimation,
|
|
754
|
+
animationProgress,
|
|
672
755
|
sourceUnit,
|
|
673
756
|
displayUnit,
|
|
674
757
|
} = payload;
|
|
@@ -790,6 +873,8 @@ export const updateMesh = inboundData => {
|
|
|
790
873
|
if (resetAnimation) {
|
|
791
874
|
stopAllAnimationGroups();
|
|
792
875
|
newMetaDataEntry('selectedAnimation', null);
|
|
876
|
+
syncSelectedAnimationMeta(null);
|
|
877
|
+
props.setSerializedData?.(serializeScene());
|
|
793
878
|
}
|
|
794
879
|
|
|
795
880
|
// Change active animation
|
|
@@ -801,9 +886,38 @@ export const updateMesh = inboundData => {
|
|
|
801
886
|
if (animationGroup) {
|
|
802
887
|
animationGroup.start(Boolean(loopAnimation));
|
|
803
888
|
newMetaDataEntry('selectedAnimation', `${animationId}`);
|
|
889
|
+
syncSelectedAnimationMeta(animationGroup);
|
|
890
|
+
ensureAnimationStateSync();
|
|
891
|
+
props.setSerializedData?.(serializeScene());
|
|
804
892
|
}
|
|
805
893
|
}
|
|
806
894
|
|
|
895
|
+
const activeAnimationGroup = getActiveAnimationGroup(animationGroups);
|
|
896
|
+
|
|
897
|
+
// Play current animation
|
|
898
|
+
if (playAnimation && activeAnimationGroup) {
|
|
899
|
+
activeAnimationGroup.play(Boolean(loopAnimation));
|
|
900
|
+
syncSelectedAnimationMeta(activeAnimationGroup);
|
|
901
|
+
ensureAnimationStateSync();
|
|
902
|
+
props.setSerializedData?.(serializeScene());
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Pause current animation
|
|
906
|
+
if (pauseAnimation && activeAnimationGroup) {
|
|
907
|
+
activeAnimationGroup.pause();
|
|
908
|
+
syncSelectedAnimationMeta(activeAnimationGroup);
|
|
909
|
+
props.setSerializedData?.(serializeScene());
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// Seek current animation to a progress position (0–1)
|
|
913
|
+
if (seekAnimation && activeAnimationGroup && animationProgress !== undefined) {
|
|
914
|
+
const { from, to } = activeAnimationGroup;
|
|
915
|
+
const frame = from + animationProgress * (to - from);
|
|
916
|
+
activeAnimationGroup.goToFrame(frame);
|
|
917
|
+
syncSelectedAnimationMeta(activeAnimationGroup);
|
|
918
|
+
props.setSerializedData?.(serializeScene());
|
|
919
|
+
}
|
|
920
|
+
|
|
807
921
|
// Bounding Box Toggle
|
|
808
922
|
if (boundingBoxEnabled !== undefined) {
|
|
809
923
|
toggleBoundingBoxWidget();
|