@inweb/viewer-three 26.9.6 → 26.9.8
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/viewer-three.js +372 -126
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +3 -3
- package/dist/viewer-three.module.js +357 -111
- package/dist/viewer-three.module.js.map +1 -1
- package/lib/Viewer/components/ResetComponent.d.ts +10 -0
- package/package.json +5 -5
- package/src/Viewer/commands/ResetView.ts +5 -1
- package/src/Viewer/commands/ZoomTo.ts +1 -1
- package/src/Viewer/components/ResetComponent.ts +64 -0
- package/src/Viewer/components/SelectionComponent.ts +4 -4
- package/src/Viewer/components/index.ts +2 -0
- package/src/Viewer/draggers/MeasureLineDragger.ts +175 -17
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +272 -105
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IComponent } from "@inweb/viewer-core";
|
|
2
|
+
import type { Viewer } from "../Viewer";
|
|
3
|
+
export declare class ResetComponent implements IComponent {
|
|
4
|
+
private viewer;
|
|
5
|
+
private savedCameraPosition;
|
|
6
|
+
constructor(viewer: Viewer);
|
|
7
|
+
dispose(): void;
|
|
8
|
+
onDatabaseChunk: () => void;
|
|
9
|
+
resetCameraPosition(): void;
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inweb/viewer-three",
|
|
3
|
-
"version": "26.9.
|
|
3
|
+
"version": "26.9.8",
|
|
4
4
|
"description": "JavaScript library for rendering CAD and BIM files in a browser using Three.js",
|
|
5
5
|
"homepage": "https://cloud.opendesign.com/docs/index.html",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"docs": "typedoc"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@inweb/client": "~26.9.
|
|
39
|
-
"@inweb/eventemitter2": "~26.9.
|
|
40
|
-
"@inweb/markup": "~26.9.
|
|
41
|
-
"@inweb/viewer-core": "~26.9.
|
|
38
|
+
"@inweb/client": "~26.9.8",
|
|
39
|
+
"@inweb/eventemitter2": "~26.9.8",
|
|
40
|
+
"@inweb/markup": "~26.9.8",
|
|
41
|
+
"@inweb/viewer-core": "~26.9.8"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/three": "^0.179.0",
|
|
@@ -22,8 +22,11 @@
|
|
|
22
22
|
///////////////////////////////////////////////////////////////////////////////
|
|
23
23
|
|
|
24
24
|
import type { Viewer } from "../Viewer";
|
|
25
|
+
import type { ResetComponent } from "../components/ResetComponent";
|
|
25
26
|
|
|
26
27
|
export function resetView(viewer: Viewer): void {
|
|
28
|
+
const reset = viewer.getComponent("ResetComponent") as ResetComponent;
|
|
29
|
+
|
|
27
30
|
viewer.executeCommand("setActiveDragger");
|
|
28
31
|
viewer.executeCommand("clearSlices");
|
|
29
32
|
viewer.executeCommand("clearOverlay");
|
|
@@ -32,7 +35,8 @@ export function resetView(viewer: Viewer): void {
|
|
|
32
35
|
viewer.executeCommand("showAll");
|
|
33
36
|
viewer.executeCommand("explode", 0);
|
|
34
37
|
viewer.executeCommand("zoomToExtents", true);
|
|
35
|
-
|
|
38
|
+
|
|
39
|
+
reset.resetCameraPosition();
|
|
36
40
|
|
|
37
41
|
viewer.emit({ type: "resetview" });
|
|
38
42
|
}
|
|
@@ -38,7 +38,7 @@ export function zoomTo(viewer: Viewer, box: Box3): void {
|
|
|
38
38
|
if (camera.isPerspectiveCamera) {
|
|
39
39
|
const offset = new Vector3(0, 0, 1)
|
|
40
40
|
.applyQuaternion(camera.quaternion)
|
|
41
|
-
.multiplyScalar(boxSize / Math.tan(MathUtils.
|
|
41
|
+
.multiplyScalar(boxSize / Math.tan(MathUtils.degToRad(camera.fov * 0.5)));
|
|
42
42
|
|
|
43
43
|
camera.position.copy(offset).add(boxCenter);
|
|
44
44
|
camera.updateMatrixWorld();
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
// ===================== AI-CODE-FILE ======================
|
|
25
|
+
// Source: Claude Sonnet 4
|
|
26
|
+
// Date: 2025-09-10
|
|
27
|
+
// Reviewer: vitaly.ivanov@opendesign.com
|
|
28
|
+
// Issue: CLOUD-5835
|
|
29
|
+
// Notes: Originally AI-generated, modified manually 2025-09-11
|
|
30
|
+
// =========================================================
|
|
31
|
+
|
|
32
|
+
import { IComponent } from "@inweb/viewer-core";
|
|
33
|
+
import type { Viewer } from "../Viewer";
|
|
34
|
+
import { Vector3 } from "three";
|
|
35
|
+
|
|
36
|
+
export class ResetComponent implements IComponent {
|
|
37
|
+
private viewer: Viewer;
|
|
38
|
+
private savedCameraPosition: any = null;
|
|
39
|
+
|
|
40
|
+
constructor(viewer: Viewer) {
|
|
41
|
+
this.viewer = viewer;
|
|
42
|
+
this.viewer.addEventListener("databasechunk", this.onDatabaseChunk);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
dispose() {
|
|
46
|
+
this.viewer.removeEventListener("databasechunk", this.onDatabaseChunk);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
onDatabaseChunk = () => {
|
|
50
|
+
this.savedCameraPosition = {
|
|
51
|
+
position: this.viewer.camera.position.clone(),
|
|
52
|
+
up: this.viewer.camera.up.clone(),
|
|
53
|
+
direction: this.viewer.camera.getWorldDirection(new Vector3()),
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
resetCameraPosition() {
|
|
58
|
+
if (this.savedCameraPosition) {
|
|
59
|
+
this.viewer.camera.position.copy(this.savedCameraPosition.position);
|
|
60
|
+
this.viewer.camera.up.copy(this.savedCameraPosition.up);
|
|
61
|
+
this.viewer.camera.lookAt(this.savedCameraPosition.position.clone().add(this.savedCameraPosition.direction));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -105,12 +105,12 @@ export class SelectionComponent implements IComponent {
|
|
|
105
105
|
const coords = new Vector2(x, y);
|
|
106
106
|
this.raycaster.setFromCamera(coords, this.viewer.camera);
|
|
107
107
|
|
|
108
|
-
this.raycaster.params =
|
|
108
|
+
this.raycaster.params = {
|
|
109
109
|
Mesh: {},
|
|
110
|
-
Line: { threshold: 0.
|
|
111
|
-
Line2: { threshold: 0.
|
|
110
|
+
Line: { threshold: 0.05 },
|
|
111
|
+
Line2: { threshold: 0.05 },
|
|
112
112
|
LOD: {},
|
|
113
|
-
Points: { threshold: 0.
|
|
113
|
+
Points: { threshold: 0.01 },
|
|
114
114
|
Sprite: {},
|
|
115
115
|
};
|
|
116
116
|
|
|
@@ -32,6 +32,7 @@ import { ResizeCanvasComponent } from "./ResizeCanvasComponent";
|
|
|
32
32
|
import { HighlighterComponent } from "./HighlighterComponent";
|
|
33
33
|
import { SelectionComponent } from "./SelectionComponent";
|
|
34
34
|
import { WCSHelperComponent } from "./WCSHelperComponent";
|
|
35
|
+
import { ResetComponent } from "./ResetComponent";
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* Viewer components registry. Use this registry to register custom components.
|
|
@@ -84,3 +85,4 @@ components.registerComponent("RenderLoopComponent", (viewer) => new RenderLoopCo
|
|
|
84
85
|
components.registerComponent("HighlighterComponent", (viewer) => new HighlighterComponent(viewer));
|
|
85
86
|
components.registerComponent("SelectionComponent", (viewer) => new SelectionComponent(viewer));
|
|
86
87
|
components.registerComponent("WCSHelperComponent", (viewer) => new WCSHelperComponent(viewer));
|
|
88
|
+
components.registerComponent("ResetComponent", (viewer) => new ResetComponent(viewer));
|
|
@@ -21,12 +21,26 @@
|
|
|
21
21
|
// acknowledge and accept the above terms.
|
|
22
22
|
///////////////////////////////////////////////////////////////////////////////
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
Camera,
|
|
26
|
+
EdgesGeometry,
|
|
27
|
+
Intersection,
|
|
28
|
+
Line3,
|
|
29
|
+
MathUtils,
|
|
30
|
+
Matrix4,
|
|
31
|
+
Object3D,
|
|
32
|
+
Raycaster,
|
|
33
|
+
Vector2,
|
|
34
|
+
Vector3,
|
|
35
|
+
Vector4,
|
|
36
|
+
} from "three";
|
|
25
37
|
|
|
26
38
|
import type { Viewer } from "../Viewer";
|
|
27
39
|
import { OrbitDragger } from "./OrbitDragger";
|
|
28
40
|
|
|
29
41
|
const PRECISION = 0.01;
|
|
42
|
+
const DESKTOP_SNAP_DISTANCE = 10;
|
|
43
|
+
const MOBILE_SNAP_DISTANCE = 50;
|
|
30
44
|
|
|
31
45
|
export class MeasureLineDragger extends OrbitDragger {
|
|
32
46
|
private overlay: MeasureOverlay;
|
|
@@ -43,7 +57,7 @@ export class MeasureLineDragger extends OrbitDragger {
|
|
|
43
57
|
this.overlay.addLine(this.line);
|
|
44
58
|
|
|
45
59
|
this.snapper = new MeasureSnapper(viewer.camera, viewer.canvas);
|
|
46
|
-
this.
|
|
60
|
+
this.updateSnapper();
|
|
47
61
|
|
|
48
62
|
this.viewer.canvas.addEventListener("pointerdown", this.onPointerDown);
|
|
49
63
|
this.viewer.canvas.addEventListener("pointermove", this.onPointerMove);
|
|
@@ -71,6 +85,8 @@ export class MeasureLineDragger extends OrbitDragger {
|
|
|
71
85
|
this.viewer.removeEventListener("show", this.updateSnapper);
|
|
72
86
|
this.viewer.removeEventListener("showall", this.updateSnapper);
|
|
73
87
|
|
|
88
|
+
this.snapper.dispose();
|
|
89
|
+
|
|
74
90
|
this.overlay.detach();
|
|
75
91
|
this.overlay.dispose();
|
|
76
92
|
|
|
@@ -90,7 +106,10 @@ export class MeasureLineDragger extends OrbitDragger {
|
|
|
90
106
|
onPointerMove = (event: PointerEvent) => {
|
|
91
107
|
if (this.orbit.enabled && this.orbit.state !== -1) return;
|
|
92
108
|
|
|
93
|
-
|
|
109
|
+
const snapPoint = this.snapper.getSnapPoint(event);
|
|
110
|
+
if (snapPoint && this.line.endPoint && snapPoint.equals(this.line.endPoint)) return;
|
|
111
|
+
|
|
112
|
+
this.line.endPoint = snapPoint;
|
|
94
113
|
this.line.render();
|
|
95
114
|
|
|
96
115
|
if (this.line.startPoint) this.changed = true; // <- to prevent context menu
|
|
@@ -124,25 +143,57 @@ export class MeasureLineDragger extends OrbitDragger {
|
|
|
124
143
|
};
|
|
125
144
|
|
|
126
145
|
updateSnapper = () => {
|
|
127
|
-
this.snapper.update(this.viewer
|
|
146
|
+
this.snapper.update(this.viewer);
|
|
128
147
|
};
|
|
129
148
|
}
|
|
130
149
|
|
|
150
|
+
const _vertex = new Vector3();
|
|
151
|
+
const _start = new Vector3();
|
|
152
|
+
const _end = new Vector3();
|
|
153
|
+
const _line = new Line3();
|
|
154
|
+
const _center = new Vector3();
|
|
155
|
+
const _projection = new Vector3();
|
|
156
|
+
|
|
131
157
|
class MeasureSnapper {
|
|
132
158
|
private camera: Camera;
|
|
133
159
|
private canvas: HTMLCanvasElement;
|
|
134
|
-
private objects: Object3D[]
|
|
160
|
+
private objects: Object3D[];
|
|
135
161
|
private raycaster: Raycaster;
|
|
162
|
+
private detectRadiusInPixels: number;
|
|
163
|
+
private edgesCache: WeakMap<any, EdgesGeometry>;
|
|
136
164
|
|
|
137
165
|
constructor(camera: Camera, canvas: HTMLCanvasElement) {
|
|
138
166
|
this.camera = camera;
|
|
139
167
|
this.canvas = canvas;
|
|
168
|
+
this.objects = [];
|
|
140
169
|
this.raycaster = new Raycaster();
|
|
170
|
+
this.detectRadiusInPixels = this.isMobile() ? MOBILE_SNAP_DISTANCE : DESKTOP_SNAP_DISTANCE;
|
|
171
|
+
this.edgesCache = new WeakMap();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
dispose() {
|
|
175
|
+
this.objects = [];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
isMobile(): boolean {
|
|
179
|
+
if (typeof navigator === "undefined") return false;
|
|
180
|
+
|
|
181
|
+
// ===================== AI-CODE-START ======================
|
|
182
|
+
// Source: Claude Sonnet 4
|
|
183
|
+
// Date: 2025-09-09
|
|
184
|
+
// Reviewer: roman.mochalov@opendesign.com
|
|
185
|
+
// Issue: CLOUD-5799
|
|
186
|
+
|
|
187
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
|
|
188
|
+
|
|
189
|
+
// ===================== AI-CODE-END ======================
|
|
141
190
|
}
|
|
142
191
|
|
|
143
|
-
|
|
144
|
-
|
|
192
|
+
getMousePosition(event: MouseEvent, target: Vector2): Vector2 {
|
|
193
|
+
return target.set(event.clientX, event.clientY);
|
|
194
|
+
}
|
|
145
195
|
|
|
196
|
+
getPointerIntersects(mouse: Vector2, objects: Object3D[]): Array<Intersection<Object3D>> {
|
|
146
197
|
const rect = this.canvas.getBoundingClientRect();
|
|
147
198
|
const x = ((mouse.x - rect.left) / rect.width) * 2 - 1;
|
|
148
199
|
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
@@ -152,22 +203,122 @@ class MeasureSnapper {
|
|
|
152
203
|
|
|
153
204
|
this.raycaster.params = {
|
|
154
205
|
Mesh: {},
|
|
155
|
-
Line: { threshold: 0.
|
|
156
|
-
Line2: { threshold: 0.
|
|
206
|
+
Line: { threshold: 0.05 },
|
|
207
|
+
Line2: { threshold: 0.05 },
|
|
157
208
|
LOD: {},
|
|
158
|
-
Points: { threshold: 0.
|
|
209
|
+
Points: { threshold: 0.01 },
|
|
159
210
|
Sprite: {},
|
|
160
211
|
};
|
|
161
212
|
|
|
162
|
-
|
|
163
|
-
|
|
213
|
+
return this.raycaster.intersectObjects(objects, false);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
getDetectRadius(point: Vector3): number {
|
|
217
|
+
const camera: any = this.camera;
|
|
218
|
+
|
|
219
|
+
// ===================== AI-CODE-START ======================
|
|
220
|
+
// Source: Gemini 2.5 Pro
|
|
221
|
+
// Date: 2025-08-27
|
|
222
|
+
// Reviewer: roman.mochalov@opendesign.com
|
|
223
|
+
// Issue: CLOUD-5799
|
|
224
|
+
// Notes: Originally AI-generated, modified manually
|
|
225
|
+
|
|
226
|
+
if (camera.isOrthographicCamera) {
|
|
227
|
+
const worldHeight = camera.top - camera.bottom;
|
|
228
|
+
|
|
229
|
+
const canvasHeight = this.canvas.height;
|
|
230
|
+
const worldUnitsPerPixel = worldHeight / canvasHeight;
|
|
231
|
+
|
|
232
|
+
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (camera.isPerspectiveCamera) {
|
|
236
|
+
const distance = camera.position.distanceTo(point);
|
|
237
|
+
const worldHeight = 2 * Math.tan(MathUtils.degToRad(camera.fov * 0.5)) * distance;
|
|
238
|
+
|
|
239
|
+
const canvasHeight = this.canvas.height;
|
|
240
|
+
const worldUnitsPerPixel = worldHeight / canvasHeight;
|
|
241
|
+
|
|
242
|
+
return this.detectRadiusInPixels * worldUnitsPerPixel;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ===================== AI-CODE-END ======================
|
|
164
246
|
|
|
165
|
-
return
|
|
247
|
+
return 0.1;
|
|
166
248
|
}
|
|
167
249
|
|
|
168
|
-
|
|
169
|
-
this.
|
|
170
|
-
|
|
250
|
+
getSnapPoint(event: PointerEvent): Vector3 {
|
|
251
|
+
const mouse = this.getMousePosition(event, new Vector2());
|
|
252
|
+
|
|
253
|
+
const intersections = this.getPointerIntersects(mouse, this.objects);
|
|
254
|
+
if (intersections.length === 0) return undefined;
|
|
255
|
+
|
|
256
|
+
// ===================== AI-CODE-START ======================
|
|
257
|
+
// Source: Gemini 2.5 Pro
|
|
258
|
+
// Date: 2025-08-20
|
|
259
|
+
// Reviewer: roman.mochalov@opendesign.com
|
|
260
|
+
// Issue: CLOUD-5799
|
|
261
|
+
// Notes: Originally AI-generated, modified manually
|
|
262
|
+
|
|
263
|
+
const object: any = intersections[0].object;
|
|
264
|
+
const intersectionPoint = intersections[0].point;
|
|
265
|
+
const localPoint = object.worldToLocal(intersectionPoint.clone());
|
|
266
|
+
|
|
267
|
+
let snapPoint: Vector3;
|
|
268
|
+
let snapDistance = this.getDetectRadius(intersectionPoint);
|
|
269
|
+
|
|
270
|
+
const geometry = object.geometry;
|
|
271
|
+
|
|
272
|
+
const positions = geometry.attributes.position.array;
|
|
273
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
274
|
+
_vertex.set(positions[i], positions[i + 1], positions[i + 2]);
|
|
275
|
+
const distance = _vertex.distanceTo(localPoint);
|
|
276
|
+
if (distance < snapDistance) {
|
|
277
|
+
snapDistance = distance;
|
|
278
|
+
snapPoint = _vertex.clone();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (snapPoint) return object.localToWorld(snapPoint);
|
|
282
|
+
|
|
283
|
+
let edges = this.edgesCache.get(geometry);
|
|
284
|
+
if (!edges) {
|
|
285
|
+
edges = new EdgesGeometry(geometry);
|
|
286
|
+
this.edgesCache.set(geometry, edges);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const edgePositions = edges.attributes.position.array;
|
|
290
|
+
for (let i = 0; i < edgePositions.length; i += 6) {
|
|
291
|
+
_start.set(edgePositions[i], edgePositions[i + 1], edgePositions[i + 2]);
|
|
292
|
+
_end.set(edgePositions[i + 3], edgePositions[i + 4], edgePositions[i + 5]);
|
|
293
|
+
_line.set(_start, _end);
|
|
294
|
+
|
|
295
|
+
_line.getCenter(_center);
|
|
296
|
+
const centerDistance = _center.distanceTo(localPoint);
|
|
297
|
+
if (centerDistance < snapDistance) {
|
|
298
|
+
snapDistance = centerDistance;
|
|
299
|
+
snapPoint = _center.clone();
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
_line.closestPointToPoint(localPoint, true, _projection);
|
|
304
|
+
const lineDistance = _projection.distanceTo(localPoint);
|
|
305
|
+
if (lineDistance < snapDistance) {
|
|
306
|
+
snapDistance = lineDistance;
|
|
307
|
+
snapPoint = _projection.clone();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
if (snapPoint) return object.localToWorld(snapPoint);
|
|
311
|
+
|
|
312
|
+
// ===================== AI-CODE-END ======================
|
|
313
|
+
|
|
314
|
+
return intersectionPoint.clone();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
update(viewer: Viewer) {
|
|
318
|
+
this.objects.length = 0;
|
|
319
|
+
viewer.models.forEach((model) => {
|
|
320
|
+
model.getVisibleObjects().forEach((object) => this.objects.push(object));
|
|
321
|
+
});
|
|
171
322
|
}
|
|
172
323
|
}
|
|
173
324
|
|
|
@@ -197,6 +348,8 @@ class MeasureOverlay {
|
|
|
197
348
|
this.container.style.pointerEvents = "none";
|
|
198
349
|
this.container.style.overflow = "hidden";
|
|
199
350
|
|
|
351
|
+
if (!this.canvas.parentElement) return;
|
|
352
|
+
|
|
200
353
|
this.canvas.parentElement.appendChild(this.container);
|
|
201
354
|
}
|
|
202
355
|
|
|
@@ -245,7 +398,7 @@ class MeasureLine {
|
|
|
245
398
|
public startPoint: Vector3;
|
|
246
399
|
public endPoint: Vector3;
|
|
247
400
|
|
|
248
|
-
public id =
|
|
401
|
+
public id = MathUtils.generateUUID();
|
|
249
402
|
public unit = "";
|
|
250
403
|
public scale = 1.0;
|
|
251
404
|
public size = 10.0;
|
|
@@ -275,6 +428,11 @@ class MeasureLine {
|
|
|
275
428
|
this.elementEndPoint.remove();
|
|
276
429
|
this.elementLine.remove();
|
|
277
430
|
this.elementLabel.remove();
|
|
431
|
+
|
|
432
|
+
this.elementStartPoint = undefined;
|
|
433
|
+
this.elementEndPoint = undefined;
|
|
434
|
+
this.elementLine = undefined;
|
|
435
|
+
this.elementLabel = undefined;
|
|
278
436
|
}
|
|
279
437
|
|
|
280
438
|
render() {
|