@inweb/viewer-three 27.1.0 → 27.1.2

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 (85) hide show
  1. package/dist/extensions/components/AxesHelperComponent.js +12 -11
  2. package/dist/extensions/components/AxesHelperComponent.js.map +1 -1
  3. package/dist/extensions/components/AxesHelperComponent.min.js +1 -1
  4. package/dist/extensions/components/AxesHelperComponent.module.js +12 -11
  5. package/dist/extensions/components/AxesHelperComponent.module.js.map +1 -1
  6. package/dist/extensions/components/GridHelperComponent.js +4 -6
  7. package/dist/extensions/components/GridHelperComponent.js.map +1 -1
  8. package/dist/extensions/components/GridHelperComponent.min.js +1 -1
  9. package/dist/extensions/components/GridHelperComponent.module.js +4 -6
  10. package/dist/extensions/components/GridHelperComponent.module.js.map +1 -1
  11. package/dist/extensions/components/InfoPanelComponent.js +7 -9
  12. package/dist/extensions/components/InfoPanelComponent.js.map +1 -1
  13. package/dist/extensions/components/InfoPanelComponent.min.js +1 -1
  14. package/dist/extensions/components/InfoPanelComponent.module.js +7 -9
  15. package/dist/extensions/components/InfoPanelComponent.module.js.map +1 -1
  16. package/dist/extensions/components/LightHelperComponent.js +5 -5
  17. package/dist/extensions/components/LightHelperComponent.js.map +1 -1
  18. package/dist/extensions/components/LightHelperComponent.min.js +1 -1
  19. package/dist/extensions/components/LightHelperComponent.module.js +6 -6
  20. package/dist/extensions/components/LightHelperComponent.module.js.map +1 -1
  21. package/dist/extensions/loaders/GLTFCloudLoader.js +1 -1
  22. package/dist/extensions/loaders/GLTFCloudLoader.js.map +1 -1
  23. package/dist/extensions/loaders/GLTFCloudLoader.min.js +1 -1
  24. package/dist/extensions/loaders/GLTFCloudLoader.module.js +1 -1
  25. package/dist/extensions/loaders/GLTFCloudLoader.module.js.map +1 -1
  26. package/dist/extensions/loaders/GLTFFileLoader.js +1 -1
  27. package/dist/extensions/loaders/GLTFFileLoader.js.map +1 -1
  28. package/dist/extensions/loaders/GLTFFileLoader.min.js +1 -1
  29. package/dist/extensions/loaders/GLTFFileLoader.module.js +1 -1
  30. package/dist/extensions/loaders/GLTFFileLoader.module.js.map +1 -1
  31. package/dist/extensions/loaders/IFCXLoader.js +2 -2
  32. package/dist/extensions/loaders/IFCXLoader.js.map +1 -1
  33. package/dist/extensions/loaders/IFCXLoader.min.js +1 -1
  34. package/dist/extensions/loaders/IFCXLoader.module.js +2 -2
  35. package/dist/extensions/loaders/IFCXLoader.module.js.map +1 -1
  36. package/dist/extensions/loaders/PotreeLoader.js +1 -1
  37. package/dist/extensions/loaders/PotreeLoader.js.map +1 -1
  38. package/dist/extensions/loaders/PotreeLoader.min.js +1 -1
  39. package/dist/extensions/loaders/PotreeLoader.module.js +1 -1
  40. package/dist/extensions/loaders/PotreeLoader.module.js.map +1 -1
  41. package/dist/viewer-three.js +1379 -104
  42. package/dist/viewer-three.js.map +1 -1
  43. package/dist/viewer-three.min.js +4 -4
  44. package/dist/viewer-three.module.js +133 -105
  45. package/dist/viewer-three.module.js.map +1 -1
  46. package/extensions/components/AxesHelperComponent.ts +13 -12
  47. package/extensions/components/GridHelperComponent.ts +4 -6
  48. package/extensions/components/InfoPanelComponent.ts +8 -11
  49. package/extensions/components/LightHelperComponent.ts +6 -6
  50. package/extensions/loaders/GLTFCloudLoader.ts +1 -1
  51. package/extensions/loaders/GLTFFileLoader.ts +1 -1
  52. package/extensions/loaders/IFCX/IFCXCloudLoader.ts +1 -1
  53. package/extensions/loaders/IFCX/IFCXFileLoader.ts +1 -1
  54. package/extensions/loaders/Potree/PotreeFileLoader.ts +1 -1
  55. package/lib/Viewer/Viewer.d.ts +1 -1
  56. package/lib/Viewer/commands/CreatePreview.d.ts +1 -1
  57. package/lib/Viewer/commands/SetDefaultViewPosition.d.ts +1 -1
  58. package/lib/Viewer/components/RenderLoopComponent.d.ts +1 -1
  59. package/lib/Viewer/draggers/FlyDragger.d.ts +1 -0
  60. package/lib/Viewer/draggers/WalkDragger.d.ts +1 -0
  61. package/lib/Viewer/loaders/GLTFBinaryParser.d.ts +11 -0
  62. package/lib/Viewer/loaders/GLTFFileDynamicLoader.d.ts +0 -1
  63. package/lib/Viewer/loaders/JSONStreamParser.d.ts +5 -0
  64. package/lib/Viewer/loaders/index.d.ts +2 -1
  65. package/package.json +7 -5
  66. package/src/Viewer/Viewer.ts +32 -32
  67. package/src/Viewer/commands/CreatePreview.ts +2 -2
  68. package/src/Viewer/commands/SetDefaultViewPosition.ts +3 -3
  69. package/src/Viewer/commands/ZoomTo.ts +6 -6
  70. package/src/Viewer/components/CameraComponent.ts +3 -3
  71. package/src/Viewer/components/InfoComponent.ts +4 -4
  72. package/src/Viewer/components/LightComponent.ts +5 -8
  73. package/src/Viewer/components/RenderLoopComponent.ts +2 -2
  74. package/src/Viewer/components/SelectionComponent.ts +3 -1
  75. package/src/Viewer/draggers/CuttingPlaneDragger.ts +6 -6
  76. package/src/Viewer/draggers/FlyDragger.ts +9 -2
  77. package/src/Viewer/draggers/MeasureLineDragger.ts +10 -7
  78. package/src/Viewer/draggers/WalkDragger.ts +9 -2
  79. package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +7 -1
  80. package/src/Viewer/loaders/{GLTFBinaryExtension.ts → GLTFBinaryParser.ts} +34 -29
  81. package/src/Viewer/loaders/GLTFCloudDynamicLoader.ts +12 -11
  82. package/src/Viewer/loaders/GLTFFileDynamicLoader.ts +11 -10
  83. package/src/Viewer/loaders/JSONStreamParser.ts +38 -0
  84. package/src/Viewer/loaders/index.ts +2 -1
  85. package/lib/Viewer/loaders/GLTFBinaryExtension.d.ts +0 -5
@@ -23,12 +23,13 @@
23
23
 
24
24
  import { draggersRegistry, commandsRegistry, Options, componentsRegistry, Info, Loader, loadersRegistry, CANVAS_EVENTS } from '@inweb/viewer-core';
25
25
  export * from '@inweb/viewer-core';
26
- import { Line, Vector3, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Line3, Raycaster, MathUtils, EdgesGeometry, Matrix4, Vector4, Controls, Clock, Sphere, Box3, Color, PerspectiveCamera, OrthographicCamera, AmbientLight, DirectionalLight, HemisphereLight, REVISION, MeshPhongMaterial, WebGLRenderTarget, UnsignedByteType, RGBAFormat, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, TextureLoader, BufferAttribute, PointsMaterial, Points, TriangleStripDrawMode, TriangleFanDrawMode, LineSegments, LineLoop, Group, NormalBlending, LoadingManager, LoaderUtils, FileLoader, UniformsUtils, ShaderMaterial, AdditiveBlending, HalfFloatType, Scene, WebGLRenderer, LinearSRGBColorSpace } from 'three';
26
+ import { Line, Vector3, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Line3, Raycaster, MathUtils, EdgesGeometry, Matrix4, Vector4, Controls, Clock, Box3, Color, PerspectiveCamera, OrthographicCamera, AmbientLight, DirectionalLight, HemisphereLight, REVISION, MeshPhongMaterial, WebGLRenderTarget, UnsignedByteType, RGBAFormat, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, TextureLoader, BufferAttribute, PointsMaterial, Points, TriangleStripDrawMode, TriangleFanDrawMode, LineSegments, LineLoop, Group, NormalBlending, LoadingManager, LoaderUtils, FileLoader, UniformsUtils, ShaderMaterial, AdditiveBlending, HalfFloatType, Scene, WebGLRenderer, LinearSRGBColorSpace } from 'three';
27
27
  import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
28
28
  import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry.js';
29
29
  import { Wireframe } from 'three/examples/jsm/lines/Wireframe.js';
30
30
  import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
31
31
  import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
32
+ import { JSONParser } from '@streamparser/json';
32
33
  import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
33
34
  import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
34
35
  import { FXAAPass } from 'three/examples/jsm/postprocessing/FXAAPass.js';
@@ -841,7 +842,7 @@ class CuttingPlaneDragger extends OrbitDragger {
841
842
  this.orbit.enabled = !event.value;
842
843
  };
843
844
  this.updatePlaneSize = () => {
844
- this.planeHelper.size = this.viewer.extents.getSize(new Vector3()).length();
845
+ this.planeHelper.size = this.viewer.extents.getSize(new Vector3()).length() || 1;
845
846
  this.viewer.update();
846
847
  };
847
848
  this.updateTransformCamera = () => {
@@ -852,17 +853,17 @@ class CuttingPlaneDragger extends OrbitDragger {
852
853
  this.plane.negate();
853
854
  this.viewer.update();
854
855
  };
855
- const size = viewer.extents.getSize(new Vector3()).length();
856
- const center = viewer.extents.getCenter(new Vector3());
857
- const constant = -center.dot(normal);
856
+ const extentsSize = viewer.extents.getSize(new Vector3()).length() || 1;
857
+ const extentsCenter = viewer.extents.getCenter(new Vector3());
858
+ const constant = -extentsCenter.dot(normal);
858
859
  this.plane = new Plane(normal, constant);
859
860
  if (!viewer.renderer.clippingPlanes)
860
861
  viewer.renderer.clippingPlanes = [];
861
862
  viewer.renderer.clippingPlanes.push(this.plane);
862
- this.planeHelper = new PlaneHelper(this.plane, size, color, center);
863
+ this.planeHelper = new PlaneHelper(this.plane, extentsSize, color, extentsCenter);
863
864
  this.viewer.helpers.add(this.planeHelper);
864
865
  this.planeCenter = new Object3D();
865
- this.planeCenter.position.copy(viewer.extents.getCenter(new Vector3()));
866
+ this.planeCenter.position.copy(extentsCenter);
866
867
  this.viewer.helpers.add(this.planeCenter);
867
868
  this.transform = new TransformControls(viewer.camera, viewer.canvas);
868
869
  this.transform.showX = !!normal.x;
@@ -1173,7 +1174,11 @@ class MeasureLineDragger extends OrbitDragger {
1173
1174
  const model = this.viewer.models[0];
1174
1175
  const units = (_a = this.viewer.options.rulerUnit) !== null && _a !== void 0 ? _a : "Default";
1175
1176
  const precision = (_b = this.viewer.options.rulerPrecision) !== null && _b !== void 0 ? _b : "Default";
1176
- if (units === "Default") {
1177
+ if (!model) {
1178
+ this.scale = 1;
1179
+ this.units = "";
1180
+ }
1181
+ else if (units === "Default") {
1177
1182
  this.scale = model.getUnitScale();
1178
1183
  this.units = model.getUnitString();
1179
1184
  }
@@ -1181,20 +1186,21 @@ class MeasureLineDragger extends OrbitDragger {
1181
1186
  this.scale = convertUnits(model.getUnits(), units, 1);
1182
1187
  this.units = units;
1183
1188
  }
1184
- if (precision === "Default") {
1189
+ if (!model)
1190
+ this.precision = 2;
1191
+ else if (precision === "Default")
1185
1192
  this.precision = model.getPrecision();
1186
- }
1187
- else {
1193
+ else
1188
1194
  this.precision = precision;
1189
- }
1190
1195
  this.overlay.updateLineUnits(this.scale, this.units, this.precision);
1191
1196
  };
1192
1197
  this.overlay = new MeasureOverlay(viewer.camera, viewer.canvas);
1193
1198
  this.overlay.attach();
1194
1199
  this.line = new MeasureLine(this.overlay, this.scale, this.units, this.precision);
1195
1200
  this.overlay.addLine(this.line);
1201
+ const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
1196
1202
  this.snapper = new Snapper(viewer.camera, viewer.renderer, viewer.canvas);
1197
- this.snapper.threshold = viewer.extents.getSize(new Vector3()).length() / 10000;
1203
+ this.snapper.threshold = extentsSize / 10000;
1198
1204
  this.objects = [];
1199
1205
  this.updateObjects();
1200
1206
  this.updateUnits();
@@ -1893,7 +1899,7 @@ class WalkDragger {
1893
1899
  constructor(viewer) {
1894
1900
  this.updateControls = () => {
1895
1901
  const size = this.viewer.extents.getSize(new Vector3());
1896
- this.controls.movementSpeed = Math.min(size.x, size.y, size.z) / 2;
1902
+ this.controls.movementSpeed = Math.min(size.x, size.y, size.z) / 2 || 1;
1897
1903
  this.joyStickControls.movementSpeed = this.controls.movementSpeed;
1898
1904
  this.joyStickControls.multiplier = this.controls.multiplier;
1899
1905
  };
@@ -1910,11 +1916,13 @@ class WalkDragger {
1910
1916
  };
1911
1917
  this.viewerRender = () => {
1912
1918
  this.joyStickControls.update();
1913
- this.controls.update();
1914
1919
  };
1915
1920
  this.viewerZoom = () => {
1916
1921
  this.controls.rotateDelta.set(0, 0);
1917
1922
  };
1923
+ this.animate = () => {
1924
+ this.controls.update();
1925
+ };
1918
1926
  const meshOnlyGround = [];
1919
1927
  viewer.models.forEach((model) => model.getVisibleObjects().forEach((obj) => {
1920
1928
  if (obj instanceof Mesh) {
@@ -1927,12 +1935,14 @@ class WalkDragger {
1927
1935
  this.joyStickControls = new JoyStickControls(viewer.camera, viewer.canvas, viewer.canvas, meshOnlyGround);
1928
1936
  this.joyStickControls.addEventListener("change", this.controlsChange);
1929
1937
  this.viewer = viewer;
1938
+ this.viewer.addEventListener("animate", this.animate);
1930
1939
  this.viewer.addEventListener("render", this.viewerRender);
1931
1940
  this.viewer.addEventListener("zoom", this.viewerZoom);
1932
1941
  this.viewer.addEventListener("changecameramode", this.updateControlsCamera);
1933
1942
  this.updateControls();
1934
1943
  }
1935
1944
  dispose() {
1945
+ this.viewer.removeEventListener("animate", this.animate);
1936
1946
  this.viewer.removeEventListener("render", this.viewerRender);
1937
1947
  this.viewer.removeEventListener("zoom", this.viewerZoom);
1938
1948
  this.viewer.removeEventListener("changecameramode", this.updateControlsCamera);
@@ -2095,7 +2105,7 @@ class FlyDragger {
2095
2105
  constructor(viewer) {
2096
2106
  this.updateControls = () => {
2097
2107
  const size = this.viewer.extents.getSize(new Vector3());
2098
- this.controls.movementSpeed = Math.min(size.x, size.y, size.z) / 2;
2108
+ this.controls.movementSpeed = Math.min(size.x, size.y, size.z) / 2 || 1;
2099
2109
  this.joyStickControls.movementSpeed = this.controls.movementSpeed;
2100
2110
  this.joyStickControls.multiplier = this.controls.multiplier;
2101
2111
  };
@@ -2112,23 +2122,27 @@ class FlyDragger {
2112
2122
  };
2113
2123
  this.viewerRender = () => {
2114
2124
  this.joyStickControls.update();
2115
- this.controls.update();
2116
2125
  };
2117
2126
  this.viewerZoom = () => {
2118
2127
  this.controls.rotateDelta.set(0, 0);
2119
2128
  };
2129
+ this.animate = () => {
2130
+ this.controls.update();
2131
+ };
2120
2132
  this.controls = new FlyControls(viewer.camera, viewer.canvas);
2121
2133
  this.controls.addEventListener("change", this.controlsChange);
2122
2134
  this.controls.addEventListener("flyspeedchange", this.flyspeedChange);
2123
2135
  this.joyStickControls = new JoyStickControls(viewer.camera, viewer.canvas, viewer.canvas, []);
2124
2136
  this.joyStickControls.addEventListener("change", this.controlsChange);
2125
2137
  this.viewer = viewer;
2138
+ this.viewer.addEventListener("animate", this.animate);
2126
2139
  this.viewer.addEventListener("render", this.viewerRender);
2127
2140
  this.viewer.addEventListener("zoom", this.viewerZoom);
2128
2141
  this.viewer.addEventListener("changecameramode", this.updateControlsCamera);
2129
2142
  this.updateControls();
2130
2143
  }
2131
2144
  dispose() {
2145
+ this.viewer.removeEventListener("animate", this.animate);
2132
2146
  this.viewer.removeEventListener("render", this.viewerRender);
2133
2147
  this.viewer.removeEventListener("zoom", this.viewerZoom);
2134
2148
  this.viewer.removeEventListener("changecameramode", this.updateControlsCamera);
@@ -2178,9 +2192,9 @@ function clearSlices(viewer) {
2178
2192
  viewer.clearSlices();
2179
2193
  }
2180
2194
 
2181
- function createPreview(viewer, type = "image/jpeg", encoderOptions = 0.25) {
2195
+ function createPreview(viewer, type = "image/jpeg", quality = 0.25) {
2182
2196
  viewer.update(true);
2183
- return viewer.canvas.toDataURL(type, encoderOptions);
2197
+ return viewer.canvas.toDataURL(type, quality);
2184
2198
  }
2185
2199
 
2186
2200
  function explode(viewer, index = 0) {
@@ -2196,27 +2210,27 @@ function zoomTo(viewer, box) {
2196
2210
  if (box.isEmpty())
2197
2211
  return;
2198
2212
  const boxCenter = box.getCenter(new Vector3());
2199
- const boxSize = box.getBoundingSphere(new Sphere()).radius;
2213
+ const boxSize = box.getSize(new Vector3()).length() || 1;
2200
2214
  const rendererSize = viewer.renderer.getSize(new Vector2());
2201
2215
  const aspectRatio = rendererSize.x / rendererSize.y;
2202
2216
  const camera = viewer.camera;
2203
2217
  if (camera.isPerspectiveCamera) {
2204
2218
  const offset = new Vector3(0, 0, 1)
2205
2219
  .applyQuaternion(camera.quaternion)
2206
- .multiplyScalar(boxSize / Math.tan(MathUtils.degToRad(camera.fov * 0.5)));
2220
+ .multiplyScalar(boxSize / (2 * Math.tan(MathUtils.degToRad(camera.fov * 0.5))));
2207
2221
  camera.position.copy(offset).add(boxCenter);
2208
2222
  camera.updateMatrixWorld();
2209
2223
  }
2210
2224
  if (camera.isOrthographicCamera) {
2211
- camera.top = boxSize;
2212
- camera.bottom = -boxSize;
2225
+ camera.top = boxSize / 2;
2226
+ camera.bottom = -boxSize / 2;
2213
2227
  camera.left = camera.bottom * aspectRatio;
2214
2228
  camera.right = camera.top * aspectRatio;
2215
2229
  camera.zoom = 1;
2216
2230
  camera.updateProjectionMatrix();
2217
2231
  const offset = new Vector3(0, 0, 1)
2218
2232
  .applyQuaternion(camera.quaternion)
2219
- .multiplyScalar(viewer.extents.getBoundingSphere(new Sphere()).radius * 3);
2233
+ .multiplyScalar(viewer.extents.getSize(new Vector3()).length() || 1);
2220
2234
  camera.position.copy(offset).add(boxCenter);
2221
2235
  camera.updateMatrixWorld();
2222
2236
  }
@@ -2237,9 +2251,9 @@ const defaultViewPositions = {
2237
2251
  ne: new Vector3(-1, 1, 1).normalize(),
2238
2252
  nw: new Vector3(1, 1, 1).normalize(),
2239
2253
  };
2240
- function setDefaultViewPosition(viewer, position) {
2254
+ function setDefaultViewPosition(viewer, position = "sw") {
2241
2255
  const extentsCenter = viewer.extents.getCenter(new Vector3());
2242
- const extentsSize = viewer.extents.getBoundingSphere(new Sphere()).radius * 2;
2256
+ const extentsSize = viewer.extents.getSize(new Vector3()).length() || 1;
2243
2257
  const upY = new Vector3(0, 1, 0);
2244
2258
  const offsetY = defaultViewPositions[position] || defaultViewPositions["sw"];
2245
2259
  const up = new Vector3().copy(viewer.camera.up);
@@ -2496,7 +2510,7 @@ class CameraComponent {
2496
2510
  return camera.isOrthographicCamera ? "orthographic" : "perspective";
2497
2511
  }
2498
2512
  switchCamera(camera) {
2499
- const extentsSize = this.viewer.extents.getBoundingSphere(new Sphere()).radius * 2 || 1;
2513
+ const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
2500
2514
  const rendererSize = this.viewer.renderer.getSize(new Vector2());
2501
2515
  const aspectRatio = rendererSize.x / rendererSize.y;
2502
2516
  if (camera.isPerspectiveCamera) {
@@ -2536,7 +2550,7 @@ class CameraComponent {
2536
2550
  if (currentCamera.isPerspectiveCamera) {
2537
2551
  const fov = currentCamera.fov;
2538
2552
  const distance = currentCamera.position.distanceTo(target);
2539
- const fieldHeight = 2 * Math.tan(MathUtils.degToRad(fov) / 2) * distance;
2553
+ const fieldHeight = 2 * Math.tan(MathUtils.degToRad(fov * 0.5)) * distance;
2540
2554
  camera = new OrthographicCamera();
2541
2555
  camera.top = fieldHeight / 2;
2542
2556
  camera.bottom = -fieldHeight / 2;
@@ -2594,7 +2608,7 @@ class LightComponent {
2594
2608
  if (this.viewer.extents.isEmpty())
2595
2609
  return;
2596
2610
  const extentsCenter = this.viewer.extents.getCenter(new Vector3());
2597
- const extentsSize = this.viewer.extents.getBoundingSphere(new Sphere()).radius;
2611
+ const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
2598
2612
  const upY = new Vector3(0, 1, 0);
2599
2613
  const frontY = new Vector3(0, 0, -1);
2600
2614
  const up = new Vector3().copy(this.viewer.camera.up);
@@ -2603,17 +2617,14 @@ class LightComponent {
2603
2617
  this.directionalLight.position
2604
2618
  .copy(up)
2605
2619
  .applyAxisAngle(front, (-Math.PI * 30) / 180)
2606
- .multiplyScalar(extentsSize * 2)
2620
+ .multiplyScalar(extentsSize)
2607
2621
  .add(extentsCenter);
2608
2622
  this.directionalLight.target.position.copy(extentsCenter);
2609
- this.frontLight.position
2610
- .copy(front)
2611
- .multiplyScalar(extentsSize * 2)
2612
- .add(extentsCenter);
2623
+ this.frontLight.position.copy(front).multiplyScalar(extentsSize).add(extentsCenter);
2613
2624
  this.frontLight.target.position.copy(extentsCenter);
2614
2625
  this.hemisphereLight.position
2615
2626
  .copy(front)
2616
- .multiplyScalar(extentsSize * 3)
2627
+ .multiplyScalar(extentsSize * 1.5)
2617
2628
  .add(extentsCenter);
2618
2629
  this.viewer.scene.add(this.ambientLight);
2619
2630
  this.viewer.scene.add(this.directionalLight);
@@ -2727,9 +2738,9 @@ class InfoComponent {
2727
2738
  console.log("File load time:", this.viewer.info.performance.loadTime, "ms");
2728
2739
  };
2729
2740
  this.resize = () => {
2730
- const rendererSize = this.viewer.renderer.getSize(new Vector2());
2731
- this.viewer.info.render.viewport.width = rendererSize.x;
2732
- this.viewer.info.render.viewport.height = rendererSize.y;
2741
+ const { width, height } = this.viewer.canvas;
2742
+ this.viewer.info.render.viewport.width = width;
2743
+ this.viewer.info.render.viewport.height = height;
2733
2744
  };
2734
2745
  this.render = () => {
2735
2746
  this.viewer.info.render.drawCalls = this.viewer.renderer.info.render.calls;
@@ -2778,13 +2789,13 @@ class InfoComponent {
2778
2789
 
2779
2790
  class RenderLoopComponent {
2780
2791
  constructor(viewer) {
2781
- this.animate = (time = 0) => {
2792
+ this.animate = (time) => {
2782
2793
  this.requestId = requestAnimationFrame(this.animate);
2783
2794
  this.viewer.render(time);
2784
2795
  this.viewer.emitEvent({ type: "animate", time });
2785
2796
  };
2786
2797
  this.viewer = viewer;
2787
- this.animate();
2798
+ this.requestId = requestAnimationFrame(this.animate);
2788
2799
  }
2789
2800
  dispose() {
2790
2801
  cancelAnimationFrame(this.requestId);
@@ -3019,8 +3030,9 @@ class SelectionComponent {
3019
3030
  const upPosition = this.getMousePosition(event, new Vector2());
3020
3031
  if (upPosition.distanceTo(this.downPosition) !== 0)
3021
3032
  return;
3033
+ const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
3022
3034
  const snapper = new Snapper(this.viewer.camera, this.viewer.renderer, this.viewer.canvas);
3023
- snapper.threshold = this.viewer.extents.getSize(new Vector3()).length() / 10000;
3035
+ snapper.threshold = extentsSize / 10000;
3024
3036
  let intersections = [];
3025
3037
  this.viewer.models.forEach((model) => {
3026
3038
  const objects = model.getVisibleObjects();
@@ -3789,7 +3801,11 @@ class GltfStructure {
3789
3801
  this.criticalError = null;
3790
3802
  }
3791
3803
  async initialize(loader) {
3792
- this.json = await this.loadController.loadJson();
3804
+ const json = await this.loadController.loadJson();
3805
+ if (json.asset === undefined || json.asset.version[0] < 2) {
3806
+ throw new Error("GltfStructure: Unsupported asset. glTF versions >=2.0 are supported.");
3807
+ }
3808
+ this.json = json;
3793
3809
  this.loader = loader;
3794
3810
  this.uri = this.json.buffers[0].uri || "";
3795
3811
  }
@@ -6285,51 +6301,62 @@ class GLTFLoadingManager extends LoadingManager {
6285
6301
 
6286
6302
  const BINARY_EXTENSION_HEADER_MAGIC = "glTF";
6287
6303
  const BINARY_EXTENSION_HEADER_LENGTH = 12;
6288
- const BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4e4f534a, BIN: 0x004e4042 };
6289
- class GLTFBinaryExtension {
6304
+ const BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4e4f534a, BIN: 0x004e4942 };
6305
+ class GLTFBinaryParser {
6290
6306
  constructor(data) {
6291
- const headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH);
6307
+ const dataView = new DataView(data, 0);
6292
6308
  const textDecoder = new TextDecoder();
6293
- const magic = textDecoder.decode(new Uint8Array(data.slice(0, 4)));
6309
+ const magic = textDecoder.decode(new Uint8Array(data, 0, Math.min(4, data.byteLength)));
6294
6310
  if (magic !== BINARY_EXTENSION_HEADER_MAGIC) {
6295
- this.content = textDecoder.decode(data);
6311
+ this.content = new Uint8Array(data);
6296
6312
  return;
6297
6313
  }
6298
- const header = {
6314
+ this.header = {
6299
6315
  magic,
6300
- version: headerView.getUint32(4, true),
6301
- length: headerView.getUint32(8, true),
6316
+ version: dataView.getUint32(4, true),
6317
+ length: dataView.getUint32(8, true),
6302
6318
  };
6303
- if (header.magic !== BINARY_EXTENSION_HEADER_MAGIC) {
6304
- throw new Error("Unsupported glTF-Binary header.");
6305
- }
6306
- if (header.version < 2.0) {
6307
- throw new Error("Legacy binary file detected.");
6308
- }
6309
- const chunkContentsLength = header.length - BINARY_EXTENSION_HEADER_LENGTH;
6310
- const chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH);
6311
- let chunkIndex = 0;
6312
- while (chunkIndex < chunkContentsLength) {
6313
- const chunkLength = chunkView.getUint32(chunkIndex, true);
6314
- chunkIndex += 4;
6315
- const chunkType = chunkView.getUint32(chunkIndex, true);
6316
- chunkIndex += 4;
6319
+ if (this.header.length !== data.byteLength) {
6320
+ throw new Error("GLTFBinaryParser: Invalid binary file header.");
6321
+ }
6322
+ if (this.header.version < 2.0) {
6323
+ throw new Error("GLTFBinaryParser: Legacy binary file detected.");
6324
+ }
6325
+ let offset = BINARY_EXTENSION_HEADER_LENGTH;
6326
+ while (offset < this.header.length) {
6327
+ const chunkLength = dataView.getUint32(offset, true);
6328
+ offset += 4;
6329
+ const chunkType = dataView.getUint32(offset, true);
6330
+ offset += 4;
6317
6331
  if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) {
6318
- const contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength);
6319
- this.content = textDecoder.decode(contentArray);
6332
+ this.content = new Uint8Array(data, offset, chunkLength);
6320
6333
  }
6321
6334
  else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) {
6322
- const byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
6323
- this.body = data.slice(byteOffset, byteOffset + chunkLength);
6335
+ this.body = data.slice(offset, offset + chunkLength);
6324
6336
  }
6325
- chunkIndex += chunkLength;
6337
+ offset += chunkLength;
6326
6338
  }
6327
6339
  if (typeof this.content === "undefined") {
6328
- throw new Error("JSON content not found.");
6340
+ throw new Error("GLTFBinaryParser: JSON content not found.");
6341
+ }
6342
+ if (typeof this.body === "undefined") {
6343
+ throw new Error("GLTFBinaryParser: Binary buffer chunk not found or type not supported.");
6329
6344
  }
6330
6345
  }
6331
6346
  }
6332
6347
 
6348
+ class JSONStreamParser extends JSONParser {
6349
+ constructor(data) {
6350
+ super();
6351
+ this.onValue = ({ value, stack }) => {
6352
+ if (stack.length === 0)
6353
+ this.json = value;
6354
+ };
6355
+ if (data)
6356
+ this.write(data);
6357
+ }
6358
+ }
6359
+
6333
6360
  class FetchError extends Error {
6334
6361
  constructor(status, message) {
6335
6362
  super(message);
@@ -6413,13 +6440,13 @@ class GLTFFileDynamicLoader extends Loader {
6413
6440
  this.viewer.models.push(modelImpl);
6414
6441
  this.viewer.syncOptions();
6415
6442
  this.viewer.syncOverlay();
6416
- this.viewer.update();
6417
6443
  this.viewer.emitEvent({ type: "databasechunk", data: scene, file });
6444
+ this.viewer.update(true);
6418
6445
  });
6419
6446
  this.gltfLoader.addEventListener("geometryerror", (data) => {
6420
6447
  this.viewer.emitEvent({ type: "geometryerror", data, file });
6421
6448
  });
6422
- this.gltfLoader.addEventListener("update", (data) => {
6449
+ this.gltfLoader.addEventListener("update", () => {
6423
6450
  this.viewer.update();
6424
6451
  });
6425
6452
  const loadController = {
@@ -6435,13 +6462,13 @@ class GLTFFileDynamicLoader extends Loader {
6435
6462
  this.viewer.emitEvent({ type: "geometryprogress", data: progress, file });
6436
6463
  };
6437
6464
  const data = await loader.loadAsync(this.manager.fileURL, progress);
6438
- const extension = new GLTFBinaryExtension(data);
6439
- this.gltf = JSON.parse(extension.content);
6440
- this.glb = extension.body;
6441
- if (/\.glb$/i.test(this.manager.fileURL) && !this.glb) {
6442
- throw new Error("GLTFFileDynamicLoader: Binary buffer chunk not found or type not supported.");
6465
+ const binaryParser = new GLTFBinaryParser(data);
6466
+ const jsonParser = new JSONStreamParser(binaryParser.content);
6467
+ if (!jsonParser.json) {
6468
+ throw new Error("GLTFFileDynamicLoader: JSON content not found or invalid.");
6443
6469
  }
6444
- return this.gltf;
6470
+ this.glb = binaryParser.body;
6471
+ return jsonParser.json;
6445
6472
  },
6446
6473
  loadBinaryData: (ranges, uri = "") => {
6447
6474
  const loader = new RangesLoader();
@@ -6501,24 +6528,27 @@ class GLTFCloudDynamicLoader extends Loader {
6501
6528
  this.viewer.models.push(modelImpl);
6502
6529
  this.viewer.syncOptions();
6503
6530
  this.viewer.syncOverlay();
6504
- this.viewer.update();
6505
6531
  this.viewer.emitEvent({ type: "databasechunk", data: scene, file: model.file, model });
6532
+ this.viewer.update(true);
6506
6533
  });
6507
6534
  this.gltfLoader.addEventListener("geometryerror", (data) => {
6508
6535
  this.viewer.emitEvent({ type: "geometryerror", data, file: model.file, model });
6509
6536
  });
6510
- this.gltfLoader.addEventListener("update", (data) => {
6537
+ this.gltfLoader.addEventListener("update", () => {
6511
6538
  this.viewer.update();
6512
6539
  });
6513
6540
  const loadController = {
6514
6541
  loadJson: async () => {
6515
- const progress = (progress) => {
6542
+ const jsonParser = new JSONStreamParser();
6543
+ const progress = (progress, chunk) => {
6544
+ jsonParser.write(chunk);
6516
6545
  this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model.file, model });
6517
6546
  };
6518
- const arrayBuffer = await model.downloadResource(model.database, progress, this.gltfLoader.getAbortController().signal);
6519
- const text = new TextDecoder().decode(arrayBuffer);
6520
- const json = JSON.parse(text);
6521
- return json;
6547
+ await model.downloadResource(model.database, progress, this.gltfLoader.getAbortController().signal);
6548
+ if (!jsonParser.json) {
6549
+ throw new Error("GLTFCloudDynamicLoader: JSON content not found or invalid.");
6550
+ }
6551
+ return jsonParser.json;
6522
6552
  },
6523
6553
  loadBinaryData: (requests) => {
6524
6554
  const ranges = requests.map((request) => ({
@@ -6831,11 +6861,13 @@ class Viewer extends EventEmitter2 {
6831
6861
  this.syncOptions();
6832
6862
  this.syncOverlay();
6833
6863
  this._renderTime = performance.now();
6834
- this.render(this._renderTime);
6835
- if (typeof onProgress === "function")
6836
- onProgress(new ProgressEvent("progress", { lengthComputable: true, loaded: 1, total: 1 }));
6864
+ if (typeof onProgress === "function") {
6865
+ const event = new ProgressEvent("progress", { lengthComputable: true, loaded: 1, total: 1 });
6866
+ onProgress(event);
6867
+ }
6837
6868
  this.emitEvent({ type: "initializeprogress", data: 1, loaded: 1, total: 1 });
6838
6869
  this.emitEvent({ type: "initialize" });
6870
+ this.update(true);
6839
6871
  return Promise.resolve(this);
6840
6872
  }
6841
6873
  dispose() {
@@ -6899,8 +6931,8 @@ class Viewer extends EventEmitter2 {
6899
6931
  }
6900
6932
  this.renderer.setSize(width, height, updateStyle);
6901
6933
  this.composer.setSize(width, height);
6902
- this.update(true);
6903
6934
  this.emitEvent({ type: "resize", width, height });
6935
+ this.update(true);
6904
6936
  }
6905
6937
  update(force = false) {
6906
6938
  const time = performance.now();
@@ -6910,11 +6942,11 @@ class Viewer extends EventEmitter2 {
6910
6942
  this.render(time);
6911
6943
  this.emitEvent({ type: "update", force });
6912
6944
  }
6913
- render(time) {
6945
+ render(time, force = false) {
6914
6946
  var _a, _b;
6915
6947
  if (!this.renderer)
6916
6948
  return;
6917
- if (!this._renderNeeded)
6949
+ if (!this._renderNeeded && !force)
6918
6950
  return;
6919
6951
  if (!time)
6920
6952
  time = performance.now();
@@ -6953,10 +6985,8 @@ class Viewer extends EventEmitter2 {
6953
6985
  if (model && typeof model.database === "string") {
6954
6986
  file = model.file;
6955
6987
  }
6956
- if (!model)
6957
- throw new Error(`Format not supported`);
6958
6988
  let format = params.format;
6959
- if (!format && typeof file["type"] === "string")
6989
+ if (!format && file && typeof file["type"] === "string")
6960
6990
  format = file["type"].split(".").pop();
6961
6991
  if (!format && typeof file === "string")
6962
6992
  format = file.split(".").pop();
@@ -6964,7 +6994,7 @@ class Viewer extends EventEmitter2 {
6964
6994
  format = file.name.split(".").pop();
6965
6995
  const loader = loaders.createLoader(this, model, format);
6966
6996
  if (!loader)
6967
- throw new Error(`Format not supported`);
6997
+ throw new Error(`Format not supported (${format})`);
6968
6998
  this.loaders.push(loader);
6969
6999
  this.emitEvent({ type: "geometrystart", file, model });
6970
7000
  try {
@@ -6976,6 +7006,7 @@ class Viewer extends EventEmitter2 {
6976
7006
  throw error;
6977
7007
  }
6978
7008
  this.emitEvent({ type: "geometryend", file, model });
7009
+ this.update(true);
6979
7010
  return this;
6980
7011
  }
6981
7012
  openGltfFile(file, externalFiles, params = {}) {
@@ -7005,11 +7036,10 @@ class Viewer extends EventEmitter2 {
7005
7036
  this.scene.clear();
7006
7037
  this.helpers.clear();
7007
7038
  this.extents.makeEmpty();
7008
- this.target.set(0, 0, 0);
7009
7039
  this.syncOptions();
7010
7040
  this.syncOverlay();
7011
- this.update(true);
7012
7041
  this.emitEvent({ type: "clear" });
7042
+ this.update(true);
7013
7043
  return this;
7014
7044
  }
7015
7045
  is3D() {
@@ -7121,7 +7151,7 @@ class Viewer extends EventEmitter2 {
7121
7151
  const getVector3FromPoint3d = ({ x, y, z }) => new Vector3(x, y, z);
7122
7152
  const setOrthogonalCamera = (orthogonal_camera) => {
7123
7153
  if (orthogonal_camera) {
7124
- const extentsSize = this.extents.getBoundingSphere(new Sphere()).radius * 2;
7154
+ const extentsSize = this.extents.getSize(new Vector3()).length() || 1;
7125
7155
  const rendererSize = this.renderer.getSize(new Vector2());
7126
7156
  const aspectRatio = rendererSize.x / rendererSize.y;
7127
7157
  const camera = new OrthographicCamera();
@@ -7147,7 +7177,7 @@ class Viewer extends EventEmitter2 {
7147
7177
  };
7148
7178
  const setPerspectiveCamera = (perspective_camera) => {
7149
7179
  if (perspective_camera) {
7150
- const extentsSize = this.extents.getBoundingSphere(new Sphere()).radius * 2;
7180
+ const extentsSize = this.extents.getSize(new Vector3()).length() || 1;
7151
7181
  const rendererSize = this.renderer.getSize(new Vector2());
7152
7182
  const aspectRatio = rendererSize.x / rendererSize.y;
7153
7183
  const camera = new PerspectiveCamera();
@@ -7197,7 +7227,7 @@ class Viewer extends EventEmitter2 {
7197
7227
  this.syncOverlay();
7198
7228
  this.setActiveDragger(draggerName);
7199
7229
  this.emitEvent({ type: "drawviewpoint", data: viewpoint });
7200
- this.update();
7230
+ this.update(true);
7201
7231
  }
7202
7232
  createViewpoint() {
7203
7233
  if (!this.renderer)
@@ -7278,11 +7308,9 @@ class Viewer extends EventEmitter2 {
7278
7308
  }
7279
7309
  return { x: intersectionPoint.x, y: intersectionPoint.y, z: intersectionPoint.z };
7280
7310
  }
7281
- else {
7282
- const point = new Vector3(x, y, -1);
7283
- point.unproject(this.camera);
7284
- return { x: point.x, y: point.y, z: point.z };
7285
- }
7311
+ const point = new Vector3(x, y, -1);
7312
+ point.unproject(this.camera);
7313
+ return { x: point.x, y: point.y, z: point.z };
7286
7314
  }
7287
7315
  worldToScreen(position) {
7288
7316
  if (!this.renderer)