@inweb/viewer-three 27.5.0 → 27.6.0

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.
Files changed (53) hide show
  1. package/dist/extensions/components/LightHelperComponent.js +1 -1
  2. package/dist/extensions/components/LightHelperComponent.js.map +1 -1
  3. package/dist/extensions/components/LightHelperComponent.min.js +1 -1
  4. package/dist/extensions/components/LightHelperComponent.module.js +1 -1
  5. package/dist/extensions/components/LightHelperComponent.module.js.map +1 -1
  6. package/dist/extensions/components/StatsPanelComponent.js +0 -1
  7. package/dist/extensions/components/StatsPanelComponent.js.map +1 -1
  8. package/dist/extensions/components/StatsPanelComponent.min.js +1 -1
  9. package/dist/extensions/components/StatsPanelComponent.module.js +0 -1
  10. package/dist/extensions/components/StatsPanelComponent.module.js.map +1 -1
  11. package/dist/extensions/loaders/GLTFCloudLoader.js +7 -2
  12. package/dist/extensions/loaders/GLTFCloudLoader.js.map +1 -1
  13. package/dist/extensions/loaders/GLTFCloudLoader.min.js +1 -1
  14. package/dist/extensions/loaders/GLTFCloudLoader.module.js +7 -2
  15. package/dist/extensions/loaders/GLTFCloudLoader.module.js.map +1 -1
  16. package/dist/extensions/loaders/GLTFFileLoader.js +2 -1
  17. package/dist/extensions/loaders/GLTFFileLoader.js.map +1 -1
  18. package/dist/extensions/loaders/GLTFFileLoader.min.js +1 -1
  19. package/dist/extensions/loaders/GLTFFileLoader.module.js +2 -1
  20. package/dist/extensions/loaders/GLTFFileLoader.module.js.map +1 -1
  21. package/dist/extensions/loaders/IFCXLoader.js +10 -5
  22. package/dist/extensions/loaders/IFCXLoader.js.map +1 -1
  23. package/dist/extensions/loaders/IFCXLoader.min.js +1 -1
  24. package/dist/extensions/loaders/IFCXLoader.module.js +10 -5
  25. package/dist/extensions/loaders/IFCXLoader.module.js.map +1 -1
  26. package/dist/viewer-three.js +161 -157
  27. package/dist/viewer-three.js.map +1 -1
  28. package/dist/viewer-three.min.js +3 -3
  29. package/dist/viewer-three.module.js +68 -53
  30. package/dist/viewer-three.module.js.map +1 -1
  31. package/extensions/components/LightHelperComponent.ts +1 -1
  32. package/extensions/components/StatsPanelComponent.ts +0 -1
  33. package/extensions/loaders/GLTFCloudLoader.ts +8 -2
  34. package/extensions/loaders/GLTFFileLoader.ts +3 -2
  35. package/extensions/loaders/IFCX/IFCXFileLoader.ts +11 -5
  36. package/lib/Viewer/Viewer.d.ts +1 -1
  37. package/lib/Viewer/measurement/Snapper.d.ts +1 -1
  38. package/package.json +5 -5
  39. package/src/Viewer/Viewer.ts +14 -16
  40. package/src/Viewer/commands/GetSelected2.ts +1 -1
  41. package/src/Viewer/commands/SetSelected.ts +1 -1
  42. package/src/Viewer/components/BackgroundComponent.ts +1 -1
  43. package/src/Viewer/components/CameraComponent.ts +1 -1
  44. package/src/Viewer/components/CanvasRemoveComponent.ts +0 -1
  45. package/src/Viewer/components/HighlighterUtils.ts +2 -2
  46. package/src/Viewer/components/SelectionComponent.ts +4 -2
  47. package/src/Viewer/helpers/SectionsHelper.js +4 -8
  48. package/src/Viewer/helpers/WCSHelper.ts +7 -5
  49. package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +19 -14
  50. package/src/Viewer/loaders/GLTFBinaryParser.ts +2 -2
  51. package/src/Viewer/loaders/GLTFFileDynamicLoader.ts +2 -2
  52. package/src/Viewer/measurement/Snapper.ts +2 -2
  53. package/src/Viewer/models/ModelImpl.ts +38 -25
@@ -57,7 +57,7 @@ class LightHelperComponent implements IComponent {
57
57
  const helperSize = extentsSize / 20;
58
58
 
59
59
  this.viewer.scene.traverse((object: any) => {
60
- let helper: DirectionalLightHelper | HemisphereLightHelper | PointLightHelper;
60
+ let helper: DirectionalLightHelper | HemisphereLightHelper | PointLightHelper | null = null;
61
61
 
62
62
  if (object.isDirectionalLight) helper = new DirectionalLightHelper(object, helperSize, "#aa0000");
63
63
  else if (object.isHemisphereLight) helper = new HemisphereLightHelper(object, helperSize, "#ff9800");
@@ -45,7 +45,6 @@ class StatsPanelComponent implements IComponent {
45
45
  this.viewer.removeEventListener("animate", this.updateViewer);
46
46
 
47
47
  this.stats.dom.remove();
48
- this.stats = undefined;
49
48
  }
50
49
 
51
50
  updateStats = () => {
@@ -26,10 +26,16 @@ import { GLTFLoadingManager, Loader, loaders, ModelImpl, Viewer } from "@inweb/v
26
26
 
27
27
  class GLTFCloudLoader extends Loader {
28
28
  public viewer: Viewer;
29
+ private manager: GLTFLoadingManager | null;
29
30
 
30
31
  constructor(viewer: Viewer) {
31
32
  super();
32
33
  this.viewer = viewer;
34
+ this.manager = null;
35
+ }
36
+
37
+ override dispose() {
38
+ if (this.manager) this.manager.dispose();
33
39
  }
34
40
 
35
41
  override isSupport(file: any): boolean {
@@ -43,9 +49,9 @@ class GLTFCloudLoader extends Loader {
43
49
 
44
50
  override async load(model: any): Promise<this> {
45
51
  const url = `${model.httpClient.serverUrl}${model.path}/${model.database}`;
46
- const manager = new GLTFLoadingManager(url);
52
+ this.manager = new GLTFLoadingManager(url);
47
53
 
48
- const loader = new GLTFLoader(manager);
54
+ const loader = new GLTFLoader(this.manager);
49
55
  loader.setRequestHeader(model.httpClient.headers);
50
56
 
51
57
  const progress = (event: ProgressEvent) => {
@@ -26,18 +26,19 @@ import { GLTFLoadingManager, GLTFLoadParams, Loader, loaders, ModelImpl, Viewer
26
26
 
27
27
  export class GLTFFileLoader extends Loader {
28
28
  public viewer: Viewer;
29
- private manager: GLTFLoadingManager;
29
+ private manager: GLTFLoadingManager | null;
30
30
 
31
31
  constructor(viewer: Viewer) {
32
32
  super();
33
33
  this.viewer = viewer;
34
+ this.manager = null;
34
35
  }
35
36
 
36
37
  override dispose() {
37
38
  if (this.manager) this.manager.dispose();
38
39
  }
39
40
 
40
- override isSupport(file: any, format?: string): boolean {
41
+ override isSupport(file: any, format = ""): boolean {
41
42
  return (
42
43
  (typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
43
44
  /(gltf|glb)$/i.test(format)
@@ -26,13 +26,19 @@ import { IFCXLoader } from "./IFCXLoader";
26
26
 
27
27
  export class IFCXFileLoader extends Loader {
28
28
  public viewer: Viewer;
29
+ private manager: GLTFLoadingManager | null;
29
30
 
30
31
  constructor(viewer: Viewer) {
31
32
  super();
32
33
  this.viewer = viewer;
34
+ this.manager = null;
33
35
  }
34
36
 
35
- override isSupport(file: any, format?: string): boolean {
37
+ override dispose() {
38
+ if (this.manager) this.manager.dispose();
39
+ }
40
+
41
+ override isSupport(file: any, format = ""): boolean {
36
42
  return (
37
43
  (typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
38
44
  /(ifcx)$/i.test(format)
@@ -40,10 +46,10 @@ export class IFCXFileLoader extends Loader {
40
46
  }
41
47
 
42
48
  override async load(file: any, format?: string, params: GLTFLoadParams = {}): Promise<this> {
43
- const manager = new GLTFLoadingManager(file, params);
49
+ this.manager = new GLTFLoadingManager(file, params);
44
50
 
45
- const loader = new IFCXLoader(manager);
46
- loader.setPath(manager.path);
51
+ const loader = new IFCXLoader(this.manager);
52
+ loader.setPath(this.manager.path);
47
53
  loader.setCrossOrigin(params.crossOrigin || loader.crossOrigin);
48
54
  loader.setWithCredentials(params.withCredentials || loader.withCredentials);
49
55
 
@@ -53,7 +59,7 @@ export class IFCXFileLoader extends Loader {
53
59
  this.viewer.emitEvent({ type: "geometryprogress", data: progress, file });
54
60
  };
55
61
 
56
- const scene = await loader.loadAsync(manager.fileURL, progress);
62
+ const scene = await loader.loadAsync(this.manager.fileURL, progress);
57
63
  if (!this.viewer.scene) return this;
58
64
 
59
65
  let handle = 1;
@@ -161,7 +161,7 @@ export declare class Viewer extends EventEmitter2<ViewerEventMap & CanvasEventMa
161
161
  activeDragger(): IDragger | null;
162
162
  setActiveDragger(name?: string): IDragger | null;
163
163
  resetActiveDragger(): void;
164
- getComponent(name: string): IComponent;
164
+ getComponent(name: string): IComponent | null;
165
165
  drawViewpoint(viewpoint: IViewpoint): void;
166
166
  createViewpoint(): IViewpoint;
167
167
  getSnapshot(type?: string, quality?: number): string;
@@ -12,5 +12,5 @@ export declare class Snapper {
12
12
  getMousePosition(event: MouseEvent, target: Vector2): Vector2;
13
13
  getPointerIntersects(mouse: Vector2, objects: Object3D[], recursive?: boolean, clip?: boolean): Array<Intersection<Object3D>>;
14
14
  getDetectRadius(point: Vector3): number;
15
- getSnapPoint(mouse: Vector2, objects: Object3D[]): Vector3;
15
+ getSnapPoint(mouse: Vector2, objects: Object3D[]): Vector3 | undefined;
16
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inweb/viewer-three",
3
- "version": "27.5.0",
3
+ "version": "27.6.0",
4
4
  "description": "JavaScript library for rendering CAD and BIM files in a browser using Three.js",
5
5
  "homepage": "https://cloud.opendesign.com/docs/index.html",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -35,10 +35,10 @@
35
35
  "docs": "typedoc"
36
36
  },
37
37
  "dependencies": {
38
- "@inweb/client": "~27.5.0",
39
- "@inweb/eventemitter2": "~27.5.0",
40
- "@inweb/markup": "~27.5.0",
41
- "@inweb/viewer-core": "~27.5.0"
38
+ "@inweb/client": "~27.6.0",
39
+ "@inweb/eventemitter2": "~27.6.0",
40
+ "@inweb/markup": "~27.6.0",
41
+ "@inweb/viewer-core": "~27.6.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@streamparser/json": "^0.0.22",
@@ -226,7 +226,8 @@ export class Viewer
226
226
  this._markup.initialize(this.canvas, this.canvasEvents, this, this);
227
227
 
228
228
  for (const name of components.getComponents().keys()) {
229
- this._components.push(components.createComponent(name, this));
229
+ const component = components.createComponent(name, this);
230
+ if (component) this._components.push(component);
230
231
  }
231
232
 
232
233
  this.syncOptions();
@@ -258,10 +259,7 @@ export class Viewer
258
259
  this._components.forEach((component: IComponent) => component.dispose());
259
260
  this._components.length = 0;
260
261
 
261
- if (this._markup) {
262
- this._markup.dispose();
263
- this._markup = undefined;
264
- }
262
+ this._markup.dispose();
265
263
 
266
264
  if (this.canvas) {
267
265
  this.canvasEvents.forEach((x) => this.canvas.removeEventListener(x, this.canvaseventlistener));
@@ -461,7 +459,7 @@ export class Viewer
461
459
  if (!format && typeof file === "string") format = file.split(".").pop();
462
460
  if (!format && file instanceof globalThis.File) format = file.name.split(".").pop();
463
461
 
464
- const loader: ILoader = loaders.createLoader(this, model, format);
462
+ const loader: ILoader | null = loaders.createLoader(this, model, format);
465
463
  if (!loader) throw new Error(`Format not supported (${format})`);
466
464
  this.loaders.push(loader);
467
465
 
@@ -615,8 +613,8 @@ export class Viewer
615
613
 
616
614
  setActiveDragger(name = ""): IDragger | null {
617
615
  if (!this._activeDragger || this._activeDragger.name !== name) {
618
- const oldDragger = this._activeDragger;
619
- let newDragger = null;
616
+ const oldDragger: IDragger | null = this._activeDragger;
617
+ let newDragger: IDragger | null = null;
620
618
 
621
619
  if (this._activeDragger) {
622
620
  this._activeDragger.dispose();
@@ -647,8 +645,8 @@ export class Viewer
647
645
  }
648
646
  }
649
647
 
650
- getComponent(name: string): IComponent {
651
- return this._components.find((component) => component.name === name);
648
+ getComponent(name: string): IComponent | null {
649
+ return this._components.find((component) => component.name === name) || null;
652
650
  }
653
651
 
654
652
  drawViewpoint(viewpoint: IViewpoint): void {
@@ -656,7 +654,7 @@ export class Viewer
656
654
 
657
655
  const getVector3FromPoint3d = ({ x, y, z }): Vector3 => new Vector3(x, y, z);
658
656
 
659
- const setOrthogonalCamera = (orthogonal_camera: IOrthogonalCamera) => {
657
+ const setOrthogonalCamera = (orthogonal_camera?: IOrthogonalCamera) => {
660
658
  if (orthogonal_camera) {
661
659
  const extentsSize = this.extents.getSize(new Vector3()).length() || 1;
662
660
  const rendererSize = this.renderer.getSize(new Vector2());
@@ -686,7 +684,7 @@ export class Viewer
686
684
  }
687
685
  };
688
686
 
689
- const setPerspectiveCamera = (perspective_camera: IPerspectiveCamera) => {
687
+ const setPerspectiveCamera = (perspective_camera?: IPerspectiveCamera) => {
690
688
  if (perspective_camera) {
691
689
  const extentsSize = this.extents.getSize(new Vector3()).length() || 1;
692
690
  const rendererSize = this.renderer.getSize(new Vector2());
@@ -713,7 +711,7 @@ export class Viewer
713
711
  }
714
712
  };
715
713
 
716
- const setClippingPlanes = (clipping_planes: IClippingPlane[]) => {
714
+ const setClippingPlanes = (clipping_planes?: IClippingPlane[]) => {
717
715
  if (clipping_planes) {
718
716
  clipping_planes.forEach((clipping_plane) => {
719
717
  const plane = new Plane();
@@ -764,7 +762,7 @@ export class Viewer
764
762
 
765
763
  const getPoint3dFromVector3 = ({ x, y, z }): IPoint => ({ x, y, z });
766
764
 
767
- const getOrthogonalCamera = (): IOrthogonalCamera => {
765
+ const getOrthogonalCamera = (): IOrthogonalCamera | undefined => {
768
766
  if (this.camera["isOrthographicCamera"])
769
767
  return {
770
768
  view_point: getPoint3dFromVector3(this.camera.position),
@@ -777,7 +775,7 @@ export class Viewer
777
775
  else return undefined;
778
776
  };
779
777
 
780
- const getPerspectiveCamera = (): IPerspectiveCamera => {
778
+ const getPerspectiveCamera = (): IPerspectiveCamera | undefined => {
781
779
  if (this.camera["isPerspectiveCamera"])
782
780
  return {
783
781
  view_point: getPoint3dFromVector3(this.camera.position),
@@ -789,7 +787,7 @@ export class Viewer
789
787
  };
790
788
 
791
789
  const getClippingPlanes = (): IClippingPlane[] => {
792
- const clipping_planes = [];
790
+ const clipping_planes: IClippingPlane[] = [];
793
791
  this.clippingPlanes.forEach((plane: Plane) => {
794
792
  const clipping_plane = {
795
793
  location: getPoint3dFromVector3(plane.coplanarPoint(new Vector3())),
@@ -24,7 +24,7 @@
24
24
  import type { Viewer } from "../Viewer";
25
25
 
26
26
  export function getSelected2(viewer: Viewer): string[] {
27
- const handles2 = [];
27
+ const handles2: string[][] = [];
28
28
 
29
29
  viewer.models.forEach((model) => {
30
30
  handles2.push(model.getHandlesByObjects(viewer.selected));
@@ -24,7 +24,7 @@
24
24
  import type { Viewer } from "../Viewer";
25
25
 
26
26
  export function setSelected(viewer: Viewer, handles: string[] = []): void {
27
- const handles2 = [];
27
+ const handles2: string[] = [];
28
28
 
29
29
  handles.forEach((handle) => {
30
30
  if (handle.includes(":")) {
@@ -42,7 +42,7 @@ export class BackgroundComponent implements IComponent {
42
42
 
43
43
  dispose() {
44
44
  this.viewer.removeEventListener("optionschange", this.syncOptions);
45
- this.viewer.scene.background = undefined;
45
+ this.viewer.scene.background = null;
46
46
  }
47
47
 
48
48
  syncOptions = () => {
@@ -80,7 +80,7 @@ export class CameraComponent implements IComponent {
80
80
 
81
81
  const target = this.viewer.target.clone();
82
82
 
83
- let camera: PerspectiveCamera | OrthographicCamera;
83
+ let camera: PerspectiveCamera | OrthographicCamera | null = null;
84
84
 
85
85
  if (currentCamera.isOrthographicCamera) {
86
86
  const fov = currentCamera.userData.fov || 45;
@@ -36,7 +36,6 @@ export class CanvasRemoveComponent implements IComponent {
36
36
 
37
37
  dispose() {
38
38
  this.mutationObserver.disconnect();
39
- this.mutationObserver = undefined;
40
39
  }
41
40
 
42
41
  cleanupViewer = (mutations: MutationRecord[]) => {
@@ -40,7 +40,7 @@ export class HighlighterUtils {
40
40
 
41
41
  static fromIndexedLine(positions: Float32Array, indices: number[]) {
42
42
  const lineGeometry = new LineSegmentsGeometry();
43
- const segments = [];
43
+ const segments: number[] = [];
44
44
 
45
45
  for (let i = 0; i < indices.length; i += 2) {
46
46
  const idx1 = indices[i] * 3;
@@ -68,7 +68,7 @@ export class HighlighterUtils {
68
68
 
69
69
  static fromNonIndexedLine(positions: Float32Array, isLineSegments: boolean) {
70
70
  const lineGeometry = new LineSegmentsGeometry();
71
- const segments = [];
71
+ const segments: number[] = [];
72
72
 
73
73
  if (isLineSegments) {
74
74
  for (let i = 0; i < positions.length; i += 6) {
@@ -21,7 +21,7 @@
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Object3D, Vector2, Vector3 } from "three";
24
+ import { Intersection, Object3D, Vector2, Vector3 } from "three";
25
25
 
26
26
  import type { IComponent } from "@inweb/viewer-core";
27
27
  import type { Viewer } from "../Viewer";
@@ -68,7 +68,9 @@ export class SelectionComponent implements IComponent {
68
68
  const snapper = new Snapper(this.viewer.camera, this.viewer.clippingPlanes, this.viewer.canvas);
69
69
  snapper.threshold = extentsSize / 10000;
70
70
 
71
- let intersections = [];
71
+ type Intersection2 = Intersection<Object3D> & { model: IModelImpl };
72
+
73
+ let intersections: Intersection2[] = [];
72
74
  this.viewer.models.forEach((model) => {
73
75
  const objects = model.getVisibleObjects();
74
76
  const intersects = snapper.getPointerIntersects(upPosition, objects);
@@ -41,10 +41,6 @@ import { LineSegmentsGeometry } from "three/examples/jsm/lines/LineSegmentsGeome
41
41
  import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
42
42
  import { LineSegments2 } from "three/examples/jsm/lines/LineSegments2.js";
43
43
 
44
- // ============================================================================
45
- // MATH UTILITY CLASS
46
- // ============================================================================
47
-
48
44
  /**
49
45
  * Spatial Hash Grid class. Used for merging vertices that are practically at the same coordinate (within
50
46
  * the given tolerance). This is critical for eliminating gaps caused by floating-point precision
@@ -115,10 +111,10 @@ class PointHashGrid {
115
111
  }
116
112
  }
117
113
 
118
- // ---------------------------------------------------------------------
119
- // Sections Helper Class
120
- // Manages all meshes related to clipping planes: Fill (Caps), Outlines, and Debug Points
121
- // ---------------------------------------------------------------------
114
+ /**
115
+ * Sections Helper Class Manages all meshes related to clipping planes: Fill (Caps), Outlines, and Debug
116
+ * Points
117
+ */
122
118
  class SectionsHelper extends Object3D {
123
119
  constructor() {
124
120
  super();
@@ -113,11 +113,13 @@ export class WCSHelper extends Object3D {
113
113
  canvas.height = 64;
114
114
 
115
115
  const context = canvas.getContext("2d");
116
- context.clearRect(0, 0, 64, 64);
117
- context.font = "24px Arial";
118
- context.textAlign = "center";
119
- context.fillStyle = color.getStyle();
120
- context.fillText(text, 32, 41);
116
+ if (context) {
117
+ context.clearRect(0, 0, 64, 64);
118
+ context.font = "24px Arial";
119
+ context.textAlign = "center";
120
+ context.fillStyle = color.getStyle();
121
+ context.fillText(text, 32, 41);
122
+ }
121
123
 
122
124
  const texture = new CanvasTexture(canvas);
123
125
  texture.colorSpace = SRGBColorSpace;
@@ -62,7 +62,7 @@ export class DynamicModelImpl extends ModelImpl {
62
62
  }
63
63
 
64
64
  override getObjects(): Object3D[] {
65
- const objects = [];
65
+ const objects: Object3D[] = [];
66
66
  this.gltfLoader.originalObjects.forEach((object: Object3D) => {
67
67
  objects.push(object);
68
68
  });
@@ -78,7 +78,7 @@ export class DynamicModelImpl extends ModelImpl {
78
78
 
79
79
  const handlesSet = new Set(handles);
80
80
 
81
- const objects = [];
81
+ const objects: Object3D[] = [];
82
82
  handlesSet.forEach((handle) => {
83
83
  objects.push(this.gltfLoader.getObjectsByHandle(handle));
84
84
  });
@@ -153,6 +153,13 @@ export class DynamicModelImpl extends ModelImpl {
153
153
  return target;
154
154
  };
155
155
 
156
+ const calcObjectOffset = (object: Object3D, target: Vector3): Vector3 => {
157
+ const parent = object.parent;
158
+ if (!parent || parent.userData.originalCenter === undefined) return target;
159
+
160
+ return target.subVectors(object.userData.originalCenter, parent.userData.originalCenter);
161
+ };
162
+
156
163
  const calcObjectDepth = (object: Object3D): number => {
157
164
  if (object.userData.depth !== undefined) return object.userData.depth;
158
165
 
@@ -162,17 +169,19 @@ export class DynamicModelImpl extends ModelImpl {
162
169
  object.userData.depth = depth;
163
170
  object.userData.originalPosition = object.position.clone();
164
171
  object.userData.originalCenter = calcObjectCenter(object, new Vector3());
172
+ object.userData.originalOffset = calcObjectOffset(object, new Vector3());
165
173
 
166
174
  return depth;
167
175
  };
168
176
 
169
177
  const explodeScale = scale / 100;
170
178
  const explodeRoot = this.scene.children[0];
179
+ const explodeObjects = this.getObjects();
171
180
 
172
- if (!explodeRoot.userData.explodeDepth) {
181
+ if (explodeRoot.userData.explodeDepth === undefined) {
173
182
  let maxDepth = 0;
174
183
 
175
- this.gltfLoader.originalObjects.forEach((object: Object3D) => {
184
+ explodeObjects.forEach((object: Object3D) => {
176
185
  const depth = calcObjectDepth(object);
177
186
  if (depth > maxDepth) maxDepth = depth;
178
187
  });
@@ -187,11 +196,11 @@ export class DynamicModelImpl extends ModelImpl {
187
196
 
188
197
  const offsetCache = new Map();
189
198
 
190
- const calcObjectOffset = (object: Object3D, target: Vector3): Vector3 => {
199
+ const calcExplodeOffset = (object: Object3D, target: Vector3): Vector3 => {
191
200
  if (offsetCache.has(object)) return target.copy(offsetCache.get(object));
192
201
 
193
202
  const parent = object.parent;
194
- if (parent && object !== explodeRoot) calcObjectOffset(parent, target);
203
+ if (parent && object !== explodeRoot) calcExplodeOffset(parent, target);
195
204
 
196
205
  const depth = object.userData.depth;
197
206
 
@@ -199,11 +208,7 @@ export class DynamicModelImpl extends ModelImpl {
199
208
  let objectScale = explodeScale * coeff;
200
209
  if (depth === explodeDepth) objectScale *= currentSegmentFraction;
201
210
 
202
- const parentCenter = parent.userData.originalCenter;
203
- const objectCenter = object.userData.originalCenter;
204
- const localOffset = objectCenter.clone().sub(parentCenter).multiplyScalar(objectScale);
205
-
206
- target.add(localOffset);
211
+ target.addScaledVector(object.userData.originalOffset, objectScale);
207
212
  }
208
213
 
209
214
  offsetCache.set(object, target.clone());
@@ -213,9 +218,9 @@ export class DynamicModelImpl extends ModelImpl {
213
218
 
214
219
  const transformMap = new Map();
215
220
 
216
- this.gltfLoader.originalObjects.forEach((object: Object3D) => {
217
- const globalOffset = calcObjectOffset(object, new Vector3());
218
- transformMap.set(object, new Matrix4().makeTranslation(globalOffset));
221
+ explodeObjects.forEach((object: Object3D) => {
222
+ const offset = calcExplodeOffset(object, new Vector3());
223
+ transformMap.set(object, new Matrix4().makeTranslation(offset));
219
224
  });
220
225
 
221
226
  this.gltfLoader.applyObjectTransforms(transformMap);
@@ -86,10 +86,10 @@ export class GLTFBinaryParser {
86
86
  offset += chunkLength;
87
87
  }
88
88
 
89
- if (typeof this.content === "undefined") {
89
+ if (this.content === undefined) {
90
90
  throw new Error("GLTFBinaryParser: JSON content not found.");
91
91
  }
92
- if (typeof this.body === "undefined") {
92
+ if (this.body === undefined) {
93
93
  throw new Error("GLTFBinaryParser: Binary buffer chunk not found or type not supported.");
94
94
  }
95
95
  }
@@ -49,14 +49,14 @@ export class GLTFFileDynamicLoader extends Loader {
49
49
  if (this.manager) this.manager.dispose();
50
50
  }
51
51
 
52
- override isSupport(file: any, format?: string): boolean {
52
+ override isSupport(file: any, format = ""): boolean {
53
53
  return (
54
54
  (typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
55
55
  /(gltf|glb)$/i.test(format)
56
56
  );
57
57
  }
58
58
 
59
- override async load(file: any, format?: string, params?: GLTFLoadParams): Promise<this> {
59
+ override async load(file: any, format?: string, params: GLTFLoadParams = {}): Promise<this> {
60
60
  this.manager = new GLTFLoadingManager(file, params);
61
61
 
62
62
  const scene = new Group();
@@ -151,7 +151,7 @@ export class Snapper {
151
151
  return 0.1;
152
152
  }
153
153
 
154
- getSnapPoint(mouse: Vector2, objects: Object3D[]): Vector3 {
154
+ getSnapPoint(mouse: Vector2, objects: Object3D[]): Vector3 | undefined {
155
155
  const intersections = this.getPointerIntersects(mouse, objects);
156
156
  if (intersections.length === 0) return undefined;
157
157
 
@@ -166,7 +166,7 @@ export class Snapper {
166
166
  const intersectionPoint = intersections[0].point;
167
167
  const localPoint = object.worldToLocal(intersectionPoint.clone());
168
168
 
169
- let snapPoint: Vector3;
169
+ let snapPoint: Vector3 | undefined = undefined;
170
170
  let snapDistance = this.getDetectRadius(intersectionPoint);
171
171
 
172
172
  const geometry = object.geometry;