@inweb/viewer-three 26.5.0 → 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.
- package/dist/plugins/components/AxesHelperComponent.js +65 -0
- package/dist/plugins/components/AxesHelperComponent.js.map +1 -0
- package/dist/plugins/components/AxesHelperComponent.min.js +1 -0
- package/dist/plugins/components/AxesHelperComponent.module.js +39 -0
- package/dist/plugins/components/AxesHelperComponent.module.js.map +1 -0
- package/dist/plugins/components/ExtentsHelperComponent.js +55 -0
- package/dist/plugins/components/ExtentsHelperComponent.js.map +1 -0
- package/dist/plugins/components/ExtentsHelperComponent.min.js +1 -0
- package/dist/plugins/components/ExtentsHelperComponent.module.js +29 -0
- package/dist/plugins/components/ExtentsHelperComponent.module.js.map +1 -0
- package/dist/plugins/components/LightHelperComponent.js +65 -0
- package/dist/plugins/components/LightHelperComponent.js.map +1 -0
- package/dist/plugins/components/LightHelperComponent.min.js +1 -0
- package/dist/plugins/components/LightHelperComponent.module.js +40 -0
- package/dist/plugins/components/LightHelperComponent.module.js.map +1 -0
- package/dist/plugins/loaders/IFCXLoader.js +887 -0
- package/dist/plugins/loaders/IFCXLoader.js.map +1 -0
- package/dist/plugins/loaders/IFCXLoader.min.js +1 -0
- package/dist/plugins/loaders/IFCXLoader.module.js +726 -0
- package/dist/plugins/loaders/IFCXLoader.module.js.map +1 -0
- package/dist/viewer-three.js +49075 -32407
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +2 -7
- package/dist/viewer-three.module.js +192 -86
- package/dist/viewer-three.module.js.map +1 -1
- package/lib/Viewer/Viewer.d.ts +51 -68
- package/lib/Viewer/loaders/GLTFFileLoader.d.ts +9 -0
- package/lib/Viewer/loaders/GLTFLoadingManager.d.ts +9 -3
- package/lib/Viewer/loaders/GLTFModelLoader.d.ts +8 -0
- package/lib/Viewer/loaders/index.d.ts +67 -0
- package/lib/index-umd.d.ts +1 -0
- package/lib/index.d.ts +6 -4
- package/package.json +10 -7
- package/{src/Viewer → plugins}/components/AxesHelperComponent.ts +4 -4
- package/{src/Viewer → plugins}/components/ExtentsHelperComponent.ts +4 -4
- package/{src/Viewer → plugins}/components/LightHelperComponent.ts +4 -4
- package/plugins/loaders/IFCX/IFCXLoader.ts +71 -0
- package/plugins/loaders/IFCX/render.js +701 -0
- package/plugins/loaders/IFCXFileLoader.ts +76 -0
- package/plugins/loaders/IFCXLoader.ts +30 -0
- package/plugins/loaders/IFCXModelLoader.ts +75 -0
- package/src/Viewer/Viewer.ts +101 -148
- package/src/Viewer/commands/Explode.ts +2 -2
- package/src/Viewer/components/index.ts +2 -8
- package/src/Viewer/loaders/GLTFFileLoader.ts +73 -0
- package/src/Viewer/loaders/GLTFLoadingManager.ts +16 -8
- package/src/Viewer/loaders/GLTFModelLoader.ts +74 -0
- package/src/Viewer/loaders/index.ts +99 -0
- package/src/index-umd.ts +30 -0
- package/src/index.ts +9 -5
- package/lib/Viewer/components/AxesHelperComponent.d.ts +0 -10
- package/lib/Viewer/components/ExtentsHelperComponent.d.ts +0 -9
- 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
|
+
}
|
package/src/Viewer/Viewer.ts
CHANGED
|
@@ -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<
|
|
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
|
|
265
|
+
* Loads a file into the viewer.
|
|
263
266
|
*
|
|
264
|
-
* The
|
|
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
|
|
267
|
-
*
|
|
268
|
-
*
|
|
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
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
|
|
287
|
-
|
|
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
|
-
*
|
|
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
|
-
* -
|
|
328
|
-
*
|
|
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 -
|
|
342
|
-
*
|
|
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
|
-
|
|
354
|
-
file:
|
|
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
|
|
342
|
+
if (!this.renderer) return this;
|
|
364
343
|
|
|
365
|
-
|
|
366
|
-
|
|
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
|
-
|
|
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
|
|
377
|
+
return this;
|
|
371
378
|
}
|
|
372
379
|
|
|
373
380
|
/**
|
|
374
|
-
*
|
|
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
|
-
* @
|
|
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
|
-
|
|
405
|
-
file
|
|
406
|
-
|
|
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
|
-
|
|
437
|
-
|
|
438
|
-
|
|
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
|
-
|
|
441
|
-
|
|
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((
|
|
477
|
-
this.models.forEach((
|
|
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
|
|
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) =>
|
|
72
|
+
viewer.models.forEach((model) => explodeModel(model, index));
|
|
73
73
|
viewer.scene.updateMatrixWorld();
|
|
74
74
|
|
|
75
75
|
viewer.update();
|
|
@@ -23,14 +23,11 @@
|
|
|
23
23
|
|
|
24
24
|
import { IComponentsRegistry, componentsRegistry } from "@inweb/viewer-core";
|
|
25
25
|
|
|
26
|
-
// import { AxesHelperComponent } from "./AxesHelperComponent";
|
|
27
26
|
import { BackgroundComponent } from "./BackgroundComponent";
|
|
28
27
|
import { RoomEnvironmentComponent } from "./RoomEnvironmentComponent";
|
|
29
28
|
import { CameraComponent } from "./CameraComponent";
|
|
30
29
|
import { ExtentsComponent } from "./ExtentsComponent";
|
|
31
|
-
|
|
32
|
-
// import { LightComponent } from "./LightComponent";
|
|
33
|
-
// import { LightHelperComponent } from "./LightHelperComponent";
|
|
30
|
+
import { LightComponent } from "./LightComponent";
|
|
34
31
|
import { RenderLoopComponent } from "./RenderLoopComponent";
|
|
35
32
|
import { ResizeCanvasComponent } from "./ResizeCanvasComponent";
|
|
36
33
|
import { SelectionComponent } from "./SelectionComponent";
|
|
@@ -82,12 +79,9 @@ components.registerComponent("ExtentsComponent", (viewer) => new ExtentsComponen
|
|
|
82
79
|
components.registerComponent("CameraComponent", (viewer) => new CameraComponent(viewer));
|
|
83
80
|
components.registerComponent("BackgroundComponent", (viewer) => new BackgroundComponent(viewer));
|
|
84
81
|
components.registerComponent("RoomEnvironmentComponent", (viewer) => new RoomEnvironmentComponent(viewer));
|
|
85
|
-
|
|
82
|
+
components.registerComponent("LightComponent", (viewer) => new LightComponent(viewer));
|
|
86
83
|
components.registerComponent("ResizeCanvasComponent", (viewer) => new ResizeCanvasComponent(viewer));
|
|
87
84
|
components.registerComponent("RenderLoopComponent", (viewer) => new RenderLoopComponent(viewer));
|
|
88
85
|
components.registerComponent("SelectionComponent", (viewer) => new SelectionComponent(viewer));
|
|
89
86
|
|
|
90
87
|
components.registerComponent("WCSHelperComponent", (viewer) => new WCSHelperComponent(viewer));
|
|
91
|
-
// components.registerComponent("AxesHelperComponent", (viewer) => new AxesHelperComponent(viewer));
|
|
92
|
-
// components.registerComponent("ExtentsHelperComponent", (viewer) => new ExtentsHelperComponent(viewer));
|
|
93
|
-
// components.registerComponent("LightHelperComponent", (viewer) => new LightHelperComponent(viewer));
|
|
@@ -0,0 +1,73 @@
|
|
|
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 { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
25
|
+
import { Loader } from "@inweb/viewer-core";
|
|
26
|
+
|
|
27
|
+
import { Viewer } from "../Viewer";
|
|
28
|
+
import { GLTFLoadingManager, GLTFLoadParams } from "./GLTFLoadingManager";
|
|
29
|
+
|
|
30
|
+
export class GLTFFileLoader extends Loader {
|
|
31
|
+
public viewer: Viewer;
|
|
32
|
+
|
|
33
|
+
constructor(viewer: Viewer) {
|
|
34
|
+
super();
|
|
35
|
+
this.viewer = viewer;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
override isSupport(file: any, format?: string): boolean {
|
|
39
|
+
return (
|
|
40
|
+
(typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
|
|
41
|
+
/(gltf|glb)$/i.test(format)
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override async load(buffer: any, format?: string, params?: GLTFLoadParams): Promise<this> {
|
|
46
|
+
const manager = new GLTFLoadingManager(buffer, params);
|
|
47
|
+
|
|
48
|
+
const loader = new GLTFLoader(manager);
|
|
49
|
+
loader.setPath(manager.path);
|
|
50
|
+
loader.setCrossOrigin(params.crossOrigin || loader.crossOrigin);
|
|
51
|
+
loader.setWithCredentials(params.withCredentials || loader.withCredentials);
|
|
52
|
+
|
|
53
|
+
const progress = (event: ProgressEvent) => {
|
|
54
|
+
const { lengthComputable, loaded, total } = event;
|
|
55
|
+
const progress = lengthComputable ? loaded / total : 1;
|
|
56
|
+
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: buffer });
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const gltf = await loader.loadAsync(manager.fileURL, progress);
|
|
60
|
+
if (!this.viewer.scene) return this;
|
|
61
|
+
|
|
62
|
+
this.viewer.scene.add(gltf.scene);
|
|
63
|
+
this.viewer.models.push(gltf.scene);
|
|
64
|
+
|
|
65
|
+
this.viewer.syncOptions();
|
|
66
|
+
this.viewer.syncOverlay();
|
|
67
|
+
this.viewer.update();
|
|
68
|
+
|
|
69
|
+
this.viewer.emitEvent({ type: "databasechunk", data: gltf.scene, file: buffer });
|
|
70
|
+
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
}
|