@inweb/viewer-three 26.4.1 → 26.5.1

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 (60) hide show
  1. package/dist/plugins/components/AxesHelperComponent.js +65 -0
  2. package/dist/plugins/components/AxesHelperComponent.js.map +1 -0
  3. package/dist/plugins/components/AxesHelperComponent.min.js +1 -0
  4. package/dist/plugins/components/AxesHelperComponent.module.js +39 -0
  5. package/dist/plugins/components/AxesHelperComponent.module.js.map +1 -0
  6. package/dist/plugins/components/ExtentsHelperComponent.js +55 -0
  7. package/dist/plugins/components/ExtentsHelperComponent.js.map +1 -0
  8. package/dist/plugins/components/ExtentsHelperComponent.min.js +1 -0
  9. package/dist/plugins/components/ExtentsHelperComponent.module.js +29 -0
  10. package/dist/plugins/components/ExtentsHelperComponent.module.js.map +1 -0
  11. package/dist/plugins/components/LightHelperComponent.js +65 -0
  12. package/dist/plugins/components/LightHelperComponent.js.map +1 -0
  13. package/dist/plugins/components/LightHelperComponent.min.js +1 -0
  14. package/dist/plugins/components/LightHelperComponent.module.js +40 -0
  15. package/dist/plugins/components/LightHelperComponent.module.js.map +1 -0
  16. package/dist/plugins/loaders/IFCXLoader.js +887 -0
  17. package/dist/plugins/loaders/IFCXLoader.js.map +1 -0
  18. package/dist/plugins/loaders/IFCXLoader.min.js +1 -0
  19. package/dist/plugins/loaders/IFCXLoader.module.js +726 -0
  20. package/dist/plugins/loaders/IFCXLoader.module.js.map +1 -0
  21. package/dist/viewer-three.js +61151 -44369
  22. package/dist/viewer-three.js.map +1 -1
  23. package/dist/viewer-three.min.js +2 -7
  24. package/dist/viewer-three.module.js +209 -92
  25. package/dist/viewer-three.module.js.map +1 -1
  26. package/lib/Viewer/Viewer.d.ts +51 -68
  27. package/lib/Viewer/commands/index.d.ts +1 -1
  28. package/lib/Viewer/components/{ExtentsHelperComponent.d.ts → RoomEnvironmentComponent.d.ts} +2 -4
  29. package/lib/Viewer/loaders/GLTFFileLoader.d.ts +9 -0
  30. package/lib/Viewer/loaders/GLTFLoadingManager.d.ts +9 -3
  31. package/lib/Viewer/loaders/GLTFModelLoader.d.ts +8 -0
  32. package/lib/Viewer/loaders/index.d.ts +67 -0
  33. package/lib/index-umd.d.ts +1 -0
  34. package/lib/index.d.ts +6 -4
  35. package/package.json +10 -7
  36. package/{src/Viewer → plugins}/components/AxesHelperComponent.ts +4 -4
  37. package/{src/Viewer → plugins}/components/ExtentsHelperComponent.ts +4 -4
  38. package/{src/Viewer → plugins}/components/LightHelperComponent.ts +4 -4
  39. package/plugins/loaders/IFCX/IFCXLoader.ts +71 -0
  40. package/plugins/loaders/IFCX/render.js +701 -0
  41. package/plugins/loaders/IFCXFileLoader.ts +76 -0
  42. package/plugins/loaders/IFCXLoader.ts +30 -0
  43. package/plugins/loaders/IFCXModelLoader.ts +75 -0
  44. package/src/Viewer/Viewer.ts +101 -148
  45. package/src/Viewer/commands/Explode.ts +2 -2
  46. package/src/Viewer/commands/index.ts +1 -1
  47. package/src/Viewer/components/BackgroundComponent.ts +1 -9
  48. package/src/Viewer/components/CameraComponent.ts +5 -1
  49. package/src/Viewer/components/ExtentsComponent.ts +1 -2
  50. package/src/Viewer/components/LightComponent.ts +6 -4
  51. package/src/Viewer/components/RoomEnvironmentComponent.ts +47 -0
  52. package/src/Viewer/components/index.ts +4 -8
  53. package/src/Viewer/loaders/GLTFFileLoader.ts +73 -0
  54. package/src/Viewer/loaders/GLTFLoadingManager.ts +16 -8
  55. package/src/Viewer/loaders/GLTFModelLoader.ts +74 -0
  56. package/src/Viewer/loaders/index.ts +99 -0
  57. package/src/index-umd.ts +30 -0
  58. package/src/index.ts +9 -5
  59. package/lib/Viewer/components/AxesHelperComponent.d.ts +0 -10
  60. package/lib/Viewer/components/LightHelperComponent.d.ts +0 -9
@@ -0,0 +1,76 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
3
+ // All rights reserved.
4
+ //
5
+ // This software and its documentation and related materials are owned by
6
+ // the Alliance. The software may only be incorporated into application
7
+ // programs owned by members of the Alliance, subject to a signed
8
+ // Membership Agreement and Supplemental Software License Agreement with the
9
+ // Alliance. The structure and organization of this software are the valuable
10
+ // trade secrets of the Alliance and its suppliers. The software is also
11
+ // protected by copyright law and international treaty provisions. Application
12
+ // programs incorporating this software must include the following statement
13
+ // with their copyright notices:
14
+ //
15
+ // This application incorporates Open Design Alliance software pursuant to a
16
+ // license agreement with Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
18
+ // All rights reserved.
19
+ //
20
+ // By use of this software, its documentation or related materials, you
21
+ // acknowledge and accept the above terms.
22
+ ///////////////////////////////////////////////////////////////////////////////
23
+
24
+ import { GLTFLoadingManager, GLTFLoadParams, Loader, Viewer } from "@inweb/viewer-three";
25
+ import { IFCXLoader } from "./IFCX/IFCXLoader";
26
+
27
+ export class IFCXFileLoader extends Loader {
28
+ public viewer: Viewer;
29
+
30
+ constructor(viewer: Viewer) {
31
+ super();
32
+ this.viewer = viewer;
33
+ }
34
+
35
+ override isSupport(file: any, format?: string): boolean {
36
+ return (
37
+ (typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
38
+ /(ifcx)$/i.test(format)
39
+ );
40
+ }
41
+
42
+ override async load(file: any, format?: string, params?: GLTFLoadParams): Promise<this> {
43
+ const manager = new GLTFLoadingManager(file, params);
44
+
45
+ const loader = new IFCXLoader(manager);
46
+ loader.setPath(manager.path);
47
+ loader.setCrossOrigin(params.crossOrigin || loader.crossOrigin);
48
+ loader.setWithCredentials(params.withCredentials || loader.withCredentials);
49
+
50
+ const progress = (event: ProgressEvent) => {
51
+ const { lengthComputable, loaded, total } = event;
52
+ const progress = lengthComputable ? loaded / total : 1;
53
+ this.viewer.emitEvent({ type: "geometryprogress", data: progress, file });
54
+ };
55
+
56
+ const scene = await loader.loadAsync(manager.fileURL, progress);
57
+ if (!this.viewer.scene) return this;
58
+
59
+ let handle = 0;
60
+ scene.traverse((object) => {
61
+ object.userData = { handle, ...object.userData };
62
+ handle++;
63
+ });
64
+
65
+ this.viewer.scene.add(scene);
66
+ this.viewer.models.push(scene);
67
+
68
+ this.viewer.syncOptions();
69
+ this.viewer.syncOverlay();
70
+ this.viewer.update();
71
+
72
+ this.viewer.emitEvent({ type: "databasechunk", data: scene, file });
73
+
74
+ return this;
75
+ }
76
+ }
@@ -0,0 +1,30 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
3
+ // All rights reserved.
4
+ //
5
+ // This software and its documentation and related materials are owned by
6
+ // the Alliance. The software may only be incorporated into application
7
+ // programs owned by members of the Alliance, subject to a signed
8
+ // Membership Agreement and Supplemental Software License Agreement with the
9
+ // Alliance. The structure and organization of this software are the valuable
10
+ // trade secrets of the Alliance and its suppliers. The software is also
11
+ // protected by copyright law and international treaty provisions. Application
12
+ // programs incorporating this software must include the following statement
13
+ // with their copyright notices:
14
+ //
15
+ // This application incorporates Open Design Alliance software pursuant to a
16
+ // license agreement with Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
18
+ // All rights reserved.
19
+ //
20
+ // By use of this software, its documentation or related materials, you
21
+ // acknowledge and accept the above terms.
22
+ ///////////////////////////////////////////////////////////////////////////////
23
+
24
+ import { loaders } from "@inweb/viewer-three";
25
+
26
+ import { IFCXModelLoader } from "./IFCXModelLoader";
27
+ import { IFCXFileLoader } from "./IFCXFileLoader";
28
+
29
+ loaders.registerLoader("ifcx", (viewer: any) => new IFCXModelLoader(viewer));
30
+ loaders.registerLoader("ifcx-file", (viewer: any) => new IFCXFileLoader(viewer));
@@ -0,0 +1,75 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
3
+ // All rights reserved.
4
+ //
5
+ // This software and its documentation and related materials are owned by
6
+ // the Alliance. The software may only be incorporated into application
7
+ // programs owned by members of the Alliance, subject to a signed
8
+ // Membership Agreement and Supplemental Software License Agreement with the
9
+ // Alliance. The structure and organization of this software are the valuable
10
+ // trade secrets of the Alliance and its suppliers. The software is also
11
+ // protected by copyright law and international treaty provisions. Application
12
+ // programs incorporating this software must include the following statement
13
+ // with their copyright notices:
14
+ //
15
+ // This application incorporates Open Design Alliance software pursuant to a
16
+ // license agreement with Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
18
+ // All rights reserved.
19
+ //
20
+ // By use of this software, its documentation or related materials, you
21
+ // acknowledge and accept the above terms.
22
+ ///////////////////////////////////////////////////////////////////////////////
23
+
24
+ import { Loader, Viewer } from "@inweb/viewer-three";
25
+ import { parse, clear } from "./IFCX/render.js";
26
+
27
+ export class IFCXModelLoader extends Loader {
28
+ public viewer: Viewer;
29
+
30
+ constructor(viewer: Viewer) {
31
+ super();
32
+ this.viewer = viewer;
33
+ }
34
+
35
+ override isSupport(file: any): boolean {
36
+ return (
37
+ typeof file === "object" &&
38
+ typeof file.type === "string" &&
39
+ typeof file.download === "function" &&
40
+ /.ifcx$/i.test(file.type)
41
+ );
42
+ }
43
+
44
+ override async load(model: any): Promise<this> {
45
+ const progress = (progress: number) => {
46
+ this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model });
47
+ };
48
+
49
+ const arrayBuffer = await model.download(progress, this.abortController.signal);
50
+ if (!this.viewer.scene) return this;
51
+
52
+ const textDecoder = new TextDecoder();
53
+ const json = JSON.parse(textDecoder.decode(arrayBuffer));
54
+
55
+ const scene = parse(json);
56
+ clear();
57
+
58
+ let handle = 0;
59
+ scene.traverse((object) => {
60
+ object.userData = { handle, ...object.userData };
61
+ handle++;
62
+ });
63
+
64
+ this.viewer.scene.add(scene);
65
+ this.viewer.models.push(scene);
66
+
67
+ this.viewer.syncOptions();
68
+ this.viewer.syncOverlay();
69
+ this.viewer.update();
70
+
71
+ this.viewer.emitEvent({ type: "databasechunk", data: scene, file: model });
72
+
73
+ return this;
74
+ }
75
+ }
@@ -34,18 +34,18 @@ import {
34
34
  Vector3,
35
35
  WebGLRenderer,
36
36
  } from "three";
37
- import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
38
- import { GLTFLoadingManager } from "./loaders/GLTFLoadingManager";
39
37
 
40
38
  import { EventEmitter2 } from "@inweb/eventemitter2";
41
39
  import { Assembly, Client, Model, File } from "@inweb/client";
42
40
  import {
43
41
  CANVAS_EVENTS,
44
42
  CanvasEventMap,
43
+ FileSource,
45
44
  IClippingPlane,
46
45
  IComponent,
47
46
  IEntity,
48
47
  IDragger,
48
+ ILoader,
49
49
  IOptions,
50
50
  IOrthogonalCamera,
51
51
  IPerspectiveCamera,
@@ -61,6 +61,7 @@ import { IMarkup, IWorldTransform, Markup } from "@inweb/markup";
61
61
  import { draggers } from "./draggers";
62
62
  import { commands } from "./commands";
63
63
  import { components } from "./components";
64
+ import { loaders } from "./loaders";
64
65
 
65
66
  /**
66
67
  * 3D viewer powered by {@link https://threejs.org/ | Three.js}.
@@ -81,7 +82,8 @@ export class Viewer
81
82
  public helpers: Scene | undefined;
82
83
  public camera: PerspectiveCamera | OrthographicCamera | undefined;
83
84
  public renderer: WebGLRenderer | undefined;
84
- public models: Array<GLTF>;
85
+ public models: Array<Object3D>;
86
+ public loaders: Array<ILoader>;
85
87
  public selected: Array<Object3D>;
86
88
  public extents: Box3;
87
89
  public target: Vector3;
@@ -109,6 +111,7 @@ export class Viewer
109
111
  this.canvaseventlistener = (event: Event) => this.emit(event);
110
112
 
111
113
  this.models = [];
114
+ this.loaders = [];
112
115
  this.selected = [];
113
116
  this.extents = new Box3();
114
117
  this.target = new Vector3();
@@ -259,17 +262,35 @@ export class Viewer
259
262
  }
260
263
 
261
264
  /**
262
- * Loads a file from Open Cloud Server into the viewer.
265
+ * Loads a file into the viewer.
263
266
  *
264
- * The file geometry data on the server must be converted to `glTF` format.
267
+ * The viewer must be {@link initialize | initialized} before opening the file. Otherwise, `open()` does
268
+ * nothing.
265
269
  *
266
- * This method requires a `Client` instance to be specified when creating the viewer to load model
267
- * reference files from the Open Cloud Server. For a standalone viewer instance use
268
- * {@link openGltfFile | openGltfFile()}.
270
+ * This method requires a `Client` instance to be specified to load file from the Open Cloud Server.
271
+ * The file geometry data on the Open Cloud Server must be converted into a format siutable for the
272
+ * viewer, otherwise an exception will be thrown.
273
+ *
274
+ * For files from Open Cloud Server, the default model will be loaded. If there is no default model,
275
+ * first availiable model will be loaded. If no models are found in the file, an exception will be
276
+ * thrown.
277
+ *
278
+ * The file extension is used to determine the file format. For a `ArrayBuffer`, `Blob` and `Data URL`,
279
+ * a file format must be specified using `params.format` parameter (see below). If no appropriate
280
+ * loader is found for the specified format, an exception will be thrown.
269
281
  *
270
282
  * If there was an active dragger before opening the file, it will be deactivated. After opening the
271
283
  * file, you must manually activate the required dragger.
272
284
  *
285
+ * To open a large files, enable {@link IOptions.enablePartialMode | partial streaming} mode before
286
+ * opening. For example:
287
+ *
288
+ * ```javascript
289
+ * viewer.options.enableStreamingMode = true;
290
+ * viewer.options.enablePartialMode = true;
291
+ * await viewer.open(file);
292
+ * ```
293
+ *
273
294
  * Fires:
274
295
  *
275
296
  * - {@link OpenEvent | open}
@@ -280,67 +301,23 @@ export class Viewer
280
301
  * - {@link GeometryEndEvent | geometryend}
281
302
  * - {@link GeometryErrorEvent | geometryerror}
282
303
  *
283
- * @param file - File, assembly or specific model to load. If a `File` instance with multiple models is
284
- * specified, the default model will be loaded. If there is no default model, first availiable model
285
- * will be loaded.
286
- */
287
- async open(file: Model | File | Assembly): Promise<this> {
288
- if (!this.renderer) return this;
289
-
290
- this.cancel();
291
- this.clear();
292
-
293
- this.emitEvent({ type: "open", file, model: file });
294
-
295
- let model: Model | undefined = undefined;
296
- if (file) {
297
- const models = (await file.getModels()) || [];
298
- model = models.find((model: Model) => model.default) || models[0];
299
- }
300
- if (!model) throw new Error("No default model found");
301
-
302
- const geometryType = model.database.split(".").pop();
303
- if (geometryType !== "gltf") throw new Error(`Unknown geometry type: ${geometryType}`);
304
-
305
- const url = `${model.httpClient.serverUrl}${model.path}/${model.database}`;
306
- const params = { requestHeader: model.httpClient.headers };
307
-
308
- await this.loadReferences(model);
309
- await this.loadGltfFile(url, undefined, params);
310
-
311
- return this;
312
- }
313
-
314
- cancel(): this {
315
- this.emitEvent({ type: "cancel" });
316
- return this;
317
- }
318
-
319
- /**
320
- * Loads a `glTF` file into the viewer.
321
- *
322
- * If there was an active dragger before opening the file, it will be deactivated. After opening the
323
- * file, you must manually activate the required dragger.
304
+ * @param file - File to load.
305
+ * @param params - Loading parameters.
306
+ * @param params.format - File format string. Required when loading a file as `ArrayBuffer`, `Blob` or
307
+ * `Data URL`.
308
+ * @param params.mode - File opening mode. Can be one of:
324
309
  *
325
- * Fires:
310
+ * - `open` - Unloads an open file and opens a new one. This is default mode.
311
+ * - `append` - Appends a file to an already open file.
326
312
  *
327
- * - {@link OpenEvent | open}
328
- * - {@link GeometryStartEvent | geometrystart}
329
- * - {@link GeometryProgressEvent | geometryprogress}
330
- * - {@link DatabaseChunkEvent | databasechunk}
331
- * - {@link GeometryEndEvent | geometryend}
332
- * - {@link GeometryErrorEvent | geometryerror}
333
- *
334
- * @param file - File URL or binary data buffer to load.
335
- * @param externalData - External resource map such as binary data buffers or images. Each resource
336
- * should be represented by a `uri` and a corresponding resource URL, or
313
+ * @param params.externalFiles - External resource map such as binary data buffers or textures. Each
314
+ * resource should be represented by a `uri` and a corresponding resource URL, or
337
315
  * {@link https://developer.mozilla.org/docs/Web/API/File | Web API File} object, or
338
- * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer | ArrayBuffer}
316
+ * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer | ArrayBuffer},
339
317
  * or {@link https://developer.mozilla.org/docs/Web/API/Blob/Blob | Blob}, or
340
318
  * {@link https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs | Data URL} string,
341
- * @param params - Loader parameters.
342
- * @param params.path - The base path from which to find subsequent glTF resources such as textures and
343
- * .bin data files. If not defined, the base path of the file URL will be used.
319
+ * @param params.path - The base path from which additional resources will be loaded. If not defined,
320
+ * the base path of the file URL will be used.
344
321
  * @param params.requestHeader - The
345
322
  * {@link https://developer.mozilla.org/docs/Glossary/Request_header | request header} used in HTTP
346
323
  * request.
@@ -350,102 +327,78 @@ export class Viewer
350
327
  * authorization headers or TLS client certificates. See
351
328
  * {@link https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/withCredentials | XMLHttpRequest.withCredentials}.
352
329
  */
353
- openGltfFile(
354
- file: string | globalThis.File | ArrayBuffer | Blob,
355
- externalData: Map<string, string | globalThis.File | ArrayBuffer | Blob> = new Map(),
330
+ async open(
331
+ file: FileSource,
356
332
  params: {
333
+ format?: string;
334
+ mode?: string;
357
335
  path?: string;
336
+ externalFiles?: Map<string, string | globalThis.File | ArrayBuffer | Blob>;
358
337
  requestHeader?: HeadersInit;
359
338
  crossOrigin?: string;
360
339
  withCredentials?: boolean;
361
340
  } = {}
362
341
  ): Promise<this> {
363
- if (!this.renderer) return Promise.resolve(this);
342
+ if (!this.renderer) return this;
364
343
 
365
- this.cancel();
366
- this.clear();
344
+ if (params.mode !== "a" && params.mode !== "append") {
345
+ this.cancel();
346
+ this.clear();
347
+ }
348
+
349
+ this.emitEvent({ type: "open", file });
367
350
 
368
- this.emitEvent({ type: "open" });
351
+ let model: any = file;
352
+ if (model && typeof model.getModels === "function") {
353
+ const models = await model.getModels();
354
+ model = models.find((model: Model) => model.default) || models[0] || file;
355
+ }
356
+ if (!model) throw new Error(`Format not supported`);
357
+
358
+ let format = params.format;
359
+ if (!format && typeof model.type === "string") format = model.type.split(".").pop();
360
+ if (!format && typeof file === "string") format = file.split(".").pop();
361
+ if (!format && file instanceof globalThis.File) format = file.name.split(".").pop();
362
+
363
+ const loader = loaders.createLoader(this, model, format);
364
+ if (!loader) throw new Error(`Format not supported`);
365
+ this.loaders.push(loader);
366
+
367
+ this.emitEvent({ type: "geometrystart", file, model });
368
+ try {
369
+ await this.loadReferences(model);
370
+ await loader.load(model, format, params);
371
+ } catch (error: any) {
372
+ this.emitEvent({ type: "geometryerror", data: error, file, model });
373
+ throw error;
374
+ }
375
+ this.emitEvent({ type: "geometryend", file, model });
369
376
 
370
- return this.loadGltfFile(file, externalData, params);
377
+ return this;
371
378
  }
372
379
 
373
380
  /**
374
- * Appends a `glTF` file to the existing opened file.
375
- *
376
- * Fires:
377
- *
378
- * - {@link OpenEvent | open}
379
- * - {@link GeometryStartEvent | geometrystart}
380
- * - {@link GeometryProgressEvent | geometryprogress}
381
- * - {@link DatabaseChunkEvent | databasechunk}
382
- * - {@link GeometryEndEvent | geometryend}
383
- * - {@link GeometryErrorEvent | geometryerror}
381
+ * Deprecated since `26.4`. Use {@link open | open()} instead.
384
382
  *
385
- * @param file - File URL or binary data buffer to load.
386
- * @param externalData - External resource map such as binary data buffers or images. Each resource
387
- * should be represented by a `uri` and a corresponding resource URL, or
388
- * {@link https://developer.mozilla.org/docs/Web/API/File | Web API File} object, or
389
- * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer | ArrayBuffer}
390
- * or {@link https://developer.mozilla.org/docs/Web/API/Blob/Blob | Blob}, or
391
- * {@link https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs | Data URL} string,
392
- * @param params - Loader parameters.
393
- * @param params.path - The base path from which to find subsequent glTF resources such as textures and
394
- * .bin data files.
395
- * @param params.requestHeader - The
396
- * {@link https://developer.mozilla.org/docs/Glossary/Request_header | request header} used in HTTP
397
- * request.
398
- * @param params.crossOrigin - The crossOrigin string to implement CORS for loading the url from a
399
- * different domain that allows CORS. Default is `anonymous`.
400
- * @param params.withCredentials - Whether the XMLHttpRequest uses credentials such as cookies,
401
- * authorization headers or TLS client certificates. See
402
- * {@link https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/withCredentials | XMLHttpRequest.withCredentials}.
383
+ * @deprecated
403
384
  */
404
- async loadGltfFile(
405
- file: string | globalThis.File | ArrayBuffer | Blob,
406
- externalData: Map<string, string | globalThis.File | ArrayBuffer | Blob> = new Map(),
407
- params: {
408
- path?: string;
409
- requestHeader?: HeadersInit;
410
- crossOrigin?: string;
411
- withCredentials?: boolean;
412
- } = {}
413
- ): Promise<this> {
414
- const manager = new GLTFLoadingManager(file, externalData, params);
415
- try {
416
- this.emitEvent({ type: "geometrystart" });
417
-
418
- const loader = new GLTFLoader(manager);
419
- loader.setPath(manager.path);
420
- loader.setRequestHeader(params.requestHeader as any);
421
- loader.setCrossOrigin(params.crossOrigin || loader.crossOrigin);
422
- loader.setWithCredentials(params.withCredentials || loader.withCredentials);
423
-
424
- const gltf = await loader.loadAsync(manager.fileURL, (event: ProgressEvent) => {
425
- const { lengthComputable, loaded, total } = event;
426
- const progress = lengthComputable ? loaded / total : 1;
427
- this.emitEvent({ type: "geometryprogress", data: progress });
428
- });
429
-
430
- if (!this.scene) return this;
431
- if (!gltf.scene) throw new Error("No glTF scene found");
432
-
433
- this.models.push(gltf);
434
- this.scene.add(gltf.scene);
385
+ openGltfFile(file, externalFiles, params: any = {}): Promise<this> {
386
+ return this.open(file, { ...params, format: "gltf", externalFiles });
387
+ }
435
388
 
436
- this.syncOptions();
437
- this.syncOverlay();
438
- this.update();
389
+ /**
390
+ * Deprecated since `26.4`. Use {@link open | open()} instead.
391
+ *
392
+ * @deprecated
393
+ */
394
+ loadGltfFile(file, externalFiles, params: any = {}): Promise<this> {
395
+ return this.open(file, { ...params, format: "gltf", externalFiles, mode: "append" });
396
+ }
439
397
 
440
- this.emitEvent({ type: "databasechunk" });
441
- this.emitEvent({ type: "geometryend", data: gltf.scene });
442
- } catch (error) {
443
- this.emitEvent({ type: "geometryerror", data: error });
444
- throw error;
445
- } finally {
446
- manager.dispose();
447
- }
398
+ cancel(): this {
399
+ this.loaders.forEach((loader) => loader.cancel());
448
400
 
401
+ this.emitEvent({ type: "cancel" });
449
402
  return this;
450
403
  }
451
404
 
@@ -454,10 +407,7 @@ export class Viewer
454
407
 
455
408
  function disposeMaterial(material: any) {
456
409
  const materials = Array.isArray(material) ? material : [material];
457
- materials.forEach((material: any) => {
458
- // Object.keys(material).forEach((key) => material[key]?.dispose?.());
459
- material.dispose();
460
- });
410
+ materials.forEach((material: any) => material.dispose());
461
411
  }
462
412
 
463
413
  function disposeObject(object: any) {
@@ -473,12 +423,15 @@ export class Viewer
473
423
  this.helpers.traverse(disposeObject);
474
424
  this.helpers.clear();
475
425
 
476
- this.models.forEach((gltf) => gltf.scene.traverse(disposeObject));
477
- this.models.forEach((gltf) => gltf.scene.removeFromParent());
426
+ this.models.forEach((model) => model.traverse(disposeObject));
427
+ this.models.forEach((model) => model.removeFromParent());
478
428
  this.models = [];
479
429
 
480
430
  this.scene.clear();
481
431
 
432
+ this.loaders.forEach((loader) => loader.dispose());
433
+ this.loaders = [];
434
+
482
435
  this.syncOptions();
483
436
  this.syncOverlay();
484
437
  this.update(true);
@@ -38,7 +38,7 @@ function calcExplodeDepth(object, depth: number): number {
38
38
  return res;
39
39
  }
40
40
 
41
- function explodeScene(scene, scale = 0, coeff = 4) {
41
+ function explodeModel(scene, scale = 0, coeff = 4) {
42
42
  scale /= 100;
43
43
 
44
44
  if (!scene.explodeDepth) scene.explodeDepth = calcExplodeDepth(scene, 1);
@@ -69,7 +69,7 @@ function explodeScene(scene, scale = 0, coeff = 4) {
69
69
  }
70
70
 
71
71
  export function explode(viewer: Viewer, index = 0): void {
72
- viewer.models.forEach((model) => explodeScene(model.scene, index));
72
+ viewer.models.forEach((model) => explodeModel(model, index));
73
73
  viewer.scene.updateMatrixWorld();
74
74
 
75
75
  viewer.update();
@@ -47,7 +47,7 @@ import { zoomToObjects } from "./ZoomToObjects";
47
47
  import { zoomToSelected } from "./ZoomToSelected";
48
48
 
49
49
  /**
50
- * A commands registry. Use this registry to register custom commands.
50
+ * Viewer commands registry. Use this registry to register custom commands.
51
51
  *
52
52
  * To implement custom command:
53
53
  *
@@ -21,8 +21,7 @@
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Color, PMREMGenerator } from "three";
25
- import { RoomEnvironment } from "three/examples/jsm/environments/RoomEnvironment.js";
24
+ import { Color } from "three";
26
25
 
27
26
  import { IComponent } from "@inweb/viewer-core";
28
27
  import type { Viewer } from "../Viewer";
@@ -36,20 +35,13 @@ export class BackgroundComponent implements IComponent {
36
35
 
37
36
  this.backgroundColor = new Color(0xffffff);
38
37
 
39
- const environment = new RoomEnvironment();
40
- const pmremGenerator = new PMREMGenerator(this.viewer.renderer);
41
-
42
38
  this.viewer.renderer.setClearColor(this.backgroundColor);
43
39
  this.viewer.scene.background = this.backgroundColor;
44
- this.viewer.scene.environment = pmremGenerator.fromScene(environment).texture;
45
40
  this.viewer.addEventListener("optionschange", this.syncOptions);
46
-
47
- environment.dispose();
48
41
  }
49
42
 
50
43
  dispose() {
51
44
  this.viewer.removeEventListener("optionschange", this.syncOptions);
52
- this.viewer.scene.environment = undefined;
53
45
  this.viewer.scene.background = undefined;
54
46
  }
55
47
 
@@ -21,7 +21,7 @@
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Sphere, Vector2 } from "three";
24
+ import { Sphere, Vector2, Vector3 } from "three";
25
25
 
26
26
  import { IComponent } from "@inweb/viewer-core";
27
27
  import type { Viewer } from "../Viewer";
@@ -39,10 +39,12 @@ export class CameraComponent implements IComponent {
39
39
  }
40
40
 
41
41
  geometryEnd = () => {
42
+ const extentsCenter = this.viewer.extents.getCenter(new Vector3());
42
43
  const extentsSize = this.viewer.extents.getBoundingSphere(new Sphere()).radius * 2;
43
44
  const rendererSize = this.viewer.renderer.getSize(new Vector2());
44
45
  const aspect = rendererSize.x / rendererSize.y;
45
46
 
47
+ // TODO: do not change the camera and target after opening the second model in "append" mode
46
48
  let sceneCamera: any;
47
49
  this.viewer.scene.traverse((object: any) => {
48
50
  if (object.isCamera)
@@ -71,6 +73,8 @@ export class CameraComponent implements IComponent {
71
73
  camera.updateProjectionMatrix();
72
74
  }
73
75
 
76
+ this.viewer.target.copy(extentsCenter);
77
+
74
78
  if (!sceneCamera) {
75
79
  this.viewer.executeCommand("setDefaultViewPosition");
76
80
  }
@@ -21,7 +21,7 @@
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Box3, Vector3 } from "three";
24
+ import { Box3 } from "three";
25
25
 
26
26
  import { IComponent } from "@inweb/viewer-core";
27
27
  import type { Viewer } from "../Viewer";
@@ -53,6 +53,5 @@ export class ExtentsComponent implements IComponent {
53
53
  this.viewer.scene.traverseVisible((object) => !object.children.length && extents.expandByObject(object));
54
54
 
55
55
  this.viewer.extents.copy(extents);
56
- this.viewer.target.copy(extents.getCenter(new Vector3()));
57
56
  };
58
57
  }