@xeokit/xeokit-sdk 2.6.54 → 2.6.57

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 (37) hide show
  1. package/dist/xeokit-sdk.cjs.js +1414 -1786
  2. package/dist/xeokit-sdk.es.js +1412 -1787
  3. package/dist/xeokit-sdk.es5.js +732 -725
  4. package/dist/xeokit-sdk.min.cjs.js +5 -5
  5. package/dist/xeokit-sdk.min.es.js +5 -5
  6. package/dist/xeokit-sdk.min.es5.js +4 -4
  7. package/package.json +1 -1
  8. package/src/plugins/AngleMeasurementsPlugin/AngleMeasurement.js +155 -415
  9. package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsMouseControl.js +1 -1
  10. package/src/plugins/AnnotationsPlugin/Annotation.js +7 -5
  11. package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +236 -750
  12. package/src/plugins/StoreyViewsPlugin/StoreyViewsPlugin.js +51 -0
  13. package/src/plugins/TreeViewPlugin/RenderService.js +2 -1
  14. package/src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js +5 -1
  15. package/src/plugins/ZonesPlugin/ZonesPlugin.js +15 -79
  16. package/src/plugins/lib/html/Dot.js +14 -41
  17. package/src/plugins/lib/html/Label.js +10 -37
  18. package/src/plugins/lib/html/MenuEvent.js +74 -0
  19. package/src/plugins/lib/html/Wire.js +20 -47
  20. package/src/plugins/lib/ui/index.js +370 -12
  21. package/src/viewer/Viewer.js +9 -0
  22. package/src/viewer/index.js +1 -0
  23. package/src/viewer/scene/CameraControl/CameraControl.js +38 -0
  24. package/src/viewer/scene/CameraControl/lib/CameraUpdater.js +5 -4
  25. package/src/viewer/scene/CameraControl/lib/handlers/KeyboardPanRotateDollyHandler.js +0 -8
  26. package/src/viewer/scene/CameraControl/lib/handlers/MousePanRotateDollyHandler.js +1 -2
  27. package/src/viewer/scene/CameraControl/lib/handlers/TouchPanRotateAndDollyHandler.js +2 -1
  28. package/src/viewer/scene/marker/Marker.js +20 -23
  29. package/src/viewer/scene/model/SceneModelEntity.js +5 -0
  30. package/src/viewer/scene/model/vbo/instancing/triangles/VBOInstancingTrianglesLayer.js +1 -1
  31. package/src/viewer/utils/index.js +1 -0
  32. package/src/viewer/utils/os.js +8 -1
  33. package/types/viewer/scene/CameraControl/CameraControl.d.ts +23 -0
  34. package/types/viewer/scene/models/PerformanceModel/index.d.ts +0 -1
  35. package/types/viewer/scene/models/SceneModel.d.ts +0 -3
  36. package/types/viewer/scene/models/SceneModelEntity.d.ts +6 -0
  37. package/types/viewer/scene/nodes/Node.d.ts +1 -1
@@ -1,7 +1,20 @@
1
1
  import {Dot} from "../html/Dot.js";
2
+ import {Label} from "../html/Label.js";
3
+ import {Wire} from "../html/Wire.js";
2
4
  import {math} from "../../../viewer/scene/math/math.js";
3
5
  import {Marker} from "../../../viewer/scene/marker/Marker.js";
4
6
 
7
+ const tmpVec2a = math.vec2();
8
+ const tmpVec2b = math.vec2();
9
+ const tmpVec2c = math.vec2();
10
+ const tmpVec2d = math.vec2();
11
+ const tmpVec3a = math.vec3();
12
+ const tmpVec3b = math.vec3();
13
+ const tmpVec4a = math.vec4();
14
+ const tmpVec4b = math.vec4();
15
+ const tmpVec4c = math.vec4();
16
+ const tmpVec4d = math.vec4();
17
+
5
18
  const nop = () => { };
6
19
 
7
20
  export function transformToNode(from, to, vec) {
@@ -11,10 +24,124 @@ export function transformToNode(from, to, vec) {
11
24
  vec[1] += fromRec.top - toRec.top;
12
25
  };
13
26
 
27
+ const toClipSpace = (camera, worldPos, p) => {
28
+ // to homogeneous coords
29
+ p.set(worldPos);
30
+ p[3] = 1;
31
+
32
+ // to clip space
33
+ math.mulMat4v4(camera.viewMatrix, p, p);
34
+ math.mulMat4v4(camera.projMatrix, p, p);
35
+ };
36
+
37
+ const toCanvasSpace = (canvas, parentElement, ndc, p) => {
38
+ p[0] = (1 + ndc[0]) * 0.5 * canvas.offsetWidth;
39
+ p[1] = (1 - ndc[1]) * 0.5 * canvas.offsetHeight;
40
+ transformToNode(canvas, parentElement, p);
41
+ };
42
+
43
+ const clipSegment = (scene, parentElement, start, end, canvasStart, canvasEnd) => {
44
+ const camera = scene.camera;
45
+ const canvas = scene.canvas.canvas;
46
+
47
+ if (math.distVec3(start, end) < 0.001) {
48
+ return false;
49
+ }
50
+
51
+ const delta = math.subVec3(end, start, tmpVec3a);
52
+ let s_min = 0.0;
53
+ let s_max = 1.0;
54
+
55
+ for (let plane of scene._sectionPlanesState.sectionPlanes) {
56
+ const endDot = math.dotVec3(plane.dir, math.subVec3(plane.pos, end, tmpVec3b));
57
+ const startDot = math.dotVec3(plane.dir, math.subVec3(plane.pos, start, tmpVec3b));
58
+
59
+ if ((startDot > 0) && (endDot > 0)) {
60
+ return false;
61
+ } else if ((startDot > 0) || (endDot > 0)) {
62
+ const denom = math.dotVec3(plane.dir, delta);
63
+ if (Math.abs(denom) >= 1e-6) {
64
+ const ratio = math.dotVec3(plane.dir, tmpVec3b) / denom;
65
+ if (startDot > 0) {
66
+ s_min = Math.max(s_min, ratio);
67
+ } else {
68
+ s_max = Math.min(s_max, ratio);
69
+ }
70
+ }
71
+ }
72
+ }
73
+
74
+ const p0 = tmpVec4a;
75
+ const p1 = tmpVec4b;
76
+ toClipSpace(camera, (s_min > 0) ? math.addVec3(start, math.mulVec3Scalar(delta, s_min, tmpVec3b), tmpVec3b) : start, p0);
77
+ toClipSpace(camera, (s_max < 1) ? math.addVec3(start, math.mulVec3Scalar(delta, s_max, tmpVec3b), tmpVec3b) : end, p1);
78
+
79
+ const p0Behind = ((p0[2] / p0[3]) < -1) || (p0[3] < 0);
80
+ const p1Behind = ((p1[2] / p1[3]) < -1) || (p1[3] < 0);
81
+ if (p0Behind && p1Behind) {
82
+ return false;
83
+ }
84
+
85
+ const t = (p0[3] + p0[2]) / ((p0[3] + p0[2]) - (p1[3] + p1[2]));
86
+
87
+ if ((t > 0) && (t < 1)) { //p0Behind || p1Behind) {
88
+ // Find the intersection of a segment with the near plane in clip space, if it exists."""
89
+ // Calculate the interpolation factor t where the line segment crosses the near plane
90
+ const delta = math.subVec4(p1, p0, tmpVec4c);
91
+ math.mulVec4Scalar(delta, t, delta);
92
+ math.addVec4(p0, delta, p0Behind ? p0 : p1);
93
+ }
94
+
95
+ // normalize clip space coords
96
+ math.mulVec4Scalar(p0, 1.0 / p0[3]);
97
+ math.mulVec4Scalar(p1, 1.0 / p1[3]);
98
+
99
+ let t_min = 0.0;
100
+ let t_max = 1.0;
101
+
102
+ // If either point is outside the view frustum, clip the line segment
103
+
104
+ for (let i = 0; i < 2; ++i) {
105
+ const denom = p1[i] - p0[i];
106
+
107
+ const l = (-p0[3] - p0[i]) / denom;
108
+ const r = ( p0[3] - p0[i]) / denom;
109
+
110
+ if (denom > 0) {
111
+ t_min = Math.max(t_min, l);
112
+ t_max = Math.min(t_max, r);
113
+ } else {
114
+ t_min = Math.max(t_min, r);
115
+ t_max = Math.min(t_max, l);
116
+ }
117
+ }
118
+
119
+ if (t_min >= t_max) {
120
+ return false;
121
+ }
122
+
123
+ // Calculate the clipped start and end points
124
+ const ndcDelta = math.subVec4(p1, p0, tmpVec4c);
125
+ math.addVec4(p0, math.mulVec4Scalar(ndcDelta, t_max, tmpVec4d), p1);
126
+ math.addVec4(p0, math.mulVec4Scalar(ndcDelta, t_min, tmpVec4d), p0);
127
+
128
+ math.mulVec4Scalar(p0, 1 / p0[3]);
129
+ math.mulVec4Scalar(p1, 1 / p1[3]);
130
+
131
+ toCanvasSpace(canvas, parentElement, p0, canvasStart);
132
+ toCanvasSpace(canvas, parentElement, p1, canvasEnd);
133
+
134
+ return true;
135
+ };
136
+
14
137
  export class Dot3D extends Marker {
15
138
  constructor(scene, markerCfg, parentElement, cfg = {}) {
139
+ const camera = scene.camera;
140
+
16
141
  super(scene, markerCfg);
17
142
 
143
+ this.__visible = true; // "__" to not interfere with Marker::_visible
144
+
18
145
  const handler = (cfgEvent, componentEvent) => {
19
146
  return event => {
20
147
  if (cfgEvent) {
@@ -24,6 +151,7 @@ export class Dot3D extends Marker {
24
151
  };
25
152
  };
26
153
  this._dot = new Dot(parentElement, {
154
+ borderColor: cfg.borderColor,
27
155
  fillColor: cfg.fillColor,
28
156
  zIndex: cfg.zIndex,
29
157
  onMouseOver: handler(cfg.onMouseOver, "mouseover"),
@@ -38,19 +166,62 @@ export class Dot3D extends Marker {
38
166
  onContextMenu: handler(cfg.onContextMenu, "contextmenu")
39
167
  });
40
168
 
169
+ const toClipSpace = (worldPos, p) => {
170
+ // to homogeneous coords
171
+ p.set(worldPos);
172
+ p[3] = 1;
173
+
174
+ // to clip space
175
+ math.mulMat4v4(camera.viewMatrix, p, p);
176
+ math.mulMat4v4(camera.projMatrix, p, p);
177
+ };
178
+
179
+ const toCanvasSpace = ndc => {
180
+ const canvas = scene.canvas.canvas;
181
+ ndc[0] = (1 + ndc[0]) * 0.5 * canvas.offsetWidth;
182
+ ndc[1] = (1 - ndc[1]) * 0.5 * canvas.offsetHeight;
183
+ transformToNode(canvas, parentElement, ndc);
184
+ };
185
+
41
186
  const updateDotPos = () => {
42
- const pos = this.canvasPos.slice();
43
- transformToNode(scene.canvas.canvas, parentElement, pos);
44
- this._dot.setPos(pos[0], pos[1]);
187
+ if (! this.__visible) {
188
+ return;
189
+ }
190
+ const p0 = tmpVec4c;
191
+ toClipSpace(this.worldPos, p0);
192
+ math.mulVec3Scalar(p0, 1.0 / p0[3]);
193
+
194
+ const outsideFrustum = ((p0[3] < 0)
195
+ ||
196
+ (p0[0] < -1) || (p0[0] > 1)
197
+ ||
198
+ (p0[1] < -1) || (p0[1] > 1)
199
+ ||
200
+ (p0[2] < -1) || (p0[2] > 1));
201
+ const culled = outsideFrustum || scene._sectionPlanesState.sectionPlanes.some(
202
+ plane => (math.dotVec3(plane.dir, math.subVec3(plane.pos, this.worldPos, tmpVec3a)) > 0));
203
+
204
+ this._dot.setCulled(culled);
205
+ if (!culled) {
206
+ toCanvasSpace(p0);
207
+ this._dot.setPos(p0[0], p0[1]);
208
+ }
45
209
  };
46
210
 
47
211
  this.on("worldPos", updateDotPos);
48
212
 
49
- const onViewMatrix = scene.camera.on("viewMatrix", updateDotPos);
50
- const onProjMatrix = scene.camera.on("projMatrix", updateDotPos);
213
+ const onViewMatrix = camera.on("viewMatrix", updateDotPos);
214
+ const onProjMatrix = camera.on("projMatrix", updateDotPos);
215
+ const onCanvasBnd = scene.canvas.on("boundary", updateDotPos);
216
+ const planesUpdate = scene.on("sectionPlaneUpdated", updateDotPos);
217
+
218
+ this._updatePosition = updateDotPos;
219
+
51
220
  this._cleanup = () => {
52
- scene.camera.off(onViewMatrix);
53
- scene.camera.off(onProjMatrix);
221
+ camera.off(onViewMatrix);
222
+ camera.off(onProjMatrix);
223
+ scene.canvas.off(onCanvasBnd);
224
+ scene.off(planesUpdate);
54
225
  this._dot.destroy();
55
226
  };
56
227
  }
@@ -59,14 +230,14 @@ export class Dot3D extends Marker {
59
230
  this._dot.setClickable(value);
60
231
  }
61
232
 
62
- setCulled(value) {
63
- this._dot.setCulled(value);
64
- }
65
-
66
233
  setFillColor(value) {
67
234
  this._dot.setFillColor(value);
68
235
  }
69
236
 
237
+ setBorderColor(value) {
238
+ this._dot.setBorderColor(value);
239
+ }
240
+
70
241
  setHighlighted(value) {
71
242
  this._dot.setHighlighted(value);
72
243
  }
@@ -76,7 +247,11 @@ export class Dot3D extends Marker {
76
247
  }
77
248
 
78
249
  setVisible(value) {
79
- this._dot.setVisible(value);
250
+ if (this.__visible != value) {
251
+ this.__visible = value;
252
+ this._updatePosition();
253
+ this._dot.setVisible(value);
254
+ }
80
255
  }
81
256
 
82
257
  destroy() {
@@ -86,6 +261,189 @@ export class Dot3D extends Marker {
86
261
 
87
262
  }
88
263
 
264
+ export class Label3D {
265
+ constructor(scene, parentElement, cfg) {
266
+ const camera = scene.camera;
267
+
268
+ this._label = new Label(parentElement, cfg);
269
+ this._start = math.vec3();
270
+ this._mid = math.vec3();
271
+ this._end = math.vec3();
272
+ this._yOff = 0;
273
+ this._betweenWires = false;
274
+ this.__visible = true;
275
+
276
+ const setPosOnWire = (p0, p1, yOff) => {
277
+ p0[0] += p1[0];
278
+ p0[1] += p1[1];
279
+ math.mulVec2Scalar(p0, .5);
280
+ this._label.setPos(p0[0], p0[1] + yOff);
281
+ };
282
+
283
+ this._updatePositions = () => {
284
+ if (! this.__visible) {
285
+ return;
286
+ }
287
+ if (this._betweenWires) {
288
+ const visibleA = clipSegment(scene, parentElement, this._start, this._mid, tmpVec2a, tmpVec2b);
289
+ const visibleB = clipSegment(scene, parentElement, this._end, this._mid, tmpVec2c, tmpVec2d);
290
+ this._label.setCulled(! (visibleA || visibleB));
291
+ if (visibleA && visibleB) {
292
+ tmpVec2b[0] += tmpVec2d[0];
293
+ tmpVec2b[1] += tmpVec2d[1];
294
+ math.mulVec2Scalar(tmpVec2b, .5);
295
+
296
+ tmpVec2b[0] += tmpVec2a[0] + tmpVec2c[0];
297
+ tmpVec2b[1] += tmpVec2a[1] + tmpVec2c[1];
298
+ math.mulVec2Scalar(tmpVec2b, 1/3);
299
+ this._label.setPos(tmpVec2b[0], tmpVec2b[1]);
300
+ } else if (visibleA) {
301
+ setPosOnWire(tmpVec2a, tmpVec2b, 0);
302
+ } else if (visibleB) {
303
+ setPosOnWire(tmpVec2c, tmpVec2d, 0);
304
+ }
305
+ } else {
306
+ const visible = (clipSegment(scene, parentElement, this._start, this._end, tmpVec2a, tmpVec2b)
307
+ &&
308
+ (math.distVec2(tmpVec2a, tmpVec2b) >= this._labelMinAxisLength));
309
+ this._label.setCulled(!visible);
310
+ if (visible) {
311
+ setPosOnWire(tmpVec2a, tmpVec2b, this._yOff);
312
+ }
313
+ }
314
+ };
315
+
316
+ const onViewMatrix = camera.on("viewMatrix", this._updatePositions);
317
+ const onProjMatrix = camera.on("projMatrix", this._updatePositions);
318
+ const onCanvasBnd = scene.canvas.on("boundary", this._updatePositions);
319
+ const planesUpdate = scene.on("sectionPlaneUpdated", this._updatePositions);
320
+
321
+ this._cleanup = () => {
322
+ camera.off(onViewMatrix);
323
+ camera.off(onProjMatrix);
324
+ scene.canvas.off(onCanvasBnd);
325
+ scene.off(planesUpdate);
326
+ this._label.destroy();
327
+ };
328
+ }
329
+
330
+ setPosOnWire(p0, p1, yOff, labelMinAxisLength) {
331
+ this._start.set(p0);
332
+ this._end.set(p1);
333
+ this._yOff = yOff;
334
+ this._labelMinAxisLength = labelMinAxisLength;
335
+ this._betweenWires = false;
336
+ this._updatePositions();
337
+ }
338
+
339
+ setPosBetween(p0, p1, p2) {
340
+ this._start.set(p0);
341
+ this._mid.set(p1);
342
+ this._end.set(p2);
343
+ this._betweenWires = true;
344
+ this._updatePositions();
345
+ }
346
+
347
+ setFillColor(value) {
348
+ this._label.setFillColor(value);
349
+ }
350
+
351
+ setHighlighted(value) {
352
+ this._label.setHighlighted(value);
353
+ }
354
+
355
+ setText(value) {
356
+ this._label.setText(value);
357
+ }
358
+
359
+ setClickable(value) {
360
+ this._label.setClickable(value);
361
+ }
362
+
363
+ setVisible(value) {
364
+ if (this.__visible != value) {
365
+ this.__visible = value;
366
+ this._updatePositions();
367
+ this._label.setVisible(value);
368
+ }
369
+ }
370
+
371
+ destroy() {
372
+ this._cleanup();
373
+ }
374
+
375
+ }
376
+
377
+ export class Wire3D {
378
+ constructor(scene, parentElement, cfg) {
379
+ const camera = scene.camera;
380
+
381
+ this._wire = new Wire(parentElement, cfg);
382
+ this._start = math.vec3();
383
+ this._end = math.vec3();
384
+ this.__visible = true;
385
+
386
+ this._updatePositions = () => {
387
+ if (! this.__visible) {
388
+ return;
389
+ }
390
+ const visible = clipSegment(scene, parentElement, this._start, this._end, tmpVec2a, tmpVec2b);
391
+ this._wire.setCulled(! visible);
392
+ if (visible) {
393
+ this._wire.setStartAndEnd(tmpVec2a[0], tmpVec2a[1], tmpVec2b[0], tmpVec2b[1]);
394
+ }
395
+ };
396
+
397
+ const onViewMatrix = camera.on("viewMatrix", this._updatePositions);
398
+ const onProjMatrix = camera.on("projMatrix", this._updatePositions);
399
+ const onCanvasBnd = scene.canvas.on("boundary", this._updatePositions);
400
+ const planesUpdate = scene.on("sectionPlaneUpdated", this._updatePositions);
401
+
402
+ this._cleanup = () => {
403
+ camera.off(onViewMatrix);
404
+ camera.off(onProjMatrix);
405
+ scene.canvas.off(onCanvasBnd);
406
+ scene.off(planesUpdate);
407
+ this._wire.destroy();
408
+ };
409
+ }
410
+
411
+ setEnds(start, end) {
412
+ this._start.set(start);
413
+ this._end.set(end);
414
+ this._updatePositions();
415
+ }
416
+
417
+ setClickable(value) {
418
+ this._wire.setClickable(value);
419
+ }
420
+
421
+ setColor(value) {
422
+ this._wire.setColor(value);
423
+ }
424
+
425
+ setHighlighted(value) {
426
+ this._wire.setHighlighted(value);
427
+ }
428
+
429
+ setOpacity(value) {
430
+ this._wire.setOpacity(value);
431
+ }
432
+
433
+ setVisible(value) {
434
+ if (this.__visible != value) {
435
+ this.__visible = value;
436
+ this._updatePositions();
437
+ this._wire.setVisible(value);
438
+ }
439
+ }
440
+
441
+ destroy() {
442
+ this._cleanup();
443
+ }
444
+
445
+ }
446
+
89
447
  export function activateDraggableDot(dot, cfg) {
90
448
  const extractCFG = function(propName, defaultValue) {
91
449
  if (propName in cfg) {
@@ -491,6 +491,12 @@ class Viewer {
491
491
  }
492
492
  }
493
493
 
494
+ // Added to fix label's text offset in an html2canvas capture (See XEOK-151)
495
+ // based on https://github.com/niklasvh/html2canvas/issues/2775#issuecomment-1316356991
496
+ const style = document.createElement('style');
497
+ document.head.appendChild(style);
498
+ style.sheet?.insertRule('body > div:last-child img { display: inline-block; }');
499
+
494
500
  for (let i = 0, len = pluginContainerElements.length; i < len; i++) {
495
501
  const containerElement = pluginContainerElements[i];
496
502
  await html2canvas(containerElement, {
@@ -503,6 +509,9 @@ class Viewer {
503
509
  // (implemented to compensate XCD-153 issue)
504
510
  snapshotCanvas.getContext("2d").resetTransform();
505
511
  }
512
+
513
+ style.remove();
514
+
506
515
  if (!params.includeGizmos) {
507
516
  this.sendToPlugins("snapshotFinished");
508
517
  }
@@ -1,5 +1,6 @@
1
1
  export * from "./localization/LocaleService.js";
2
2
  export * from "./scene/index.js";
3
+ export * from './utils/index.js';
3
4
  export * from "./Plugin.js";
4
5
  export * from "./Viewer.js";
5
6
  export * from "./Configs.js";
@@ -820,6 +820,13 @@ class CameraControl extends Component {
820
820
  new KeyboardPanRotateDollyHandler(this.scene, this._controllers, this._configs, this._states, this._updates)
821
821
  ];
822
822
 
823
+ this._cursors = {
824
+ dollyForward: "zoom-in",
825
+ dollyBackward: "zoom-out",
826
+ rotate: 'grabbing',
827
+ pan: 'move',
828
+ }
829
+
823
830
  // Applies scheduled updates to the Camera on each Scene "tick" event
824
831
 
825
832
  this._cameraUpdater = new CameraUpdater(this.scene, this._controllers, this._configs, this._states, this._updates);
@@ -1181,6 +1188,37 @@ class CameraControl extends Component {
1181
1188
  this._configs.pointerEnabled = !!value;
1182
1189
  }
1183
1190
 
1191
+ /**
1192
+ * Sets the cursor to be used when a particular action is being performed.
1193
+ *
1194
+ * Accepted actions are:
1195
+ *
1196
+ * * "dollyForward" - when the camera is dollying in the forward direction
1197
+ * * "dollyBackward" - when the camera is dollying in the backward direction
1198
+ * * "pan" - when the camera is being panned
1199
+ * * "rotate" - when the camera is being rotated
1200
+ *
1201
+ * @param {String} action
1202
+ * @param {String} style
1203
+ */
1204
+ setCursorStyle(action, style) {
1205
+ if (Object.prototype.hasOwnProperty.call(this._cursors, action)) {
1206
+ this._cursors = { ...this._cursors, [action]: style };
1207
+ }
1208
+ else
1209
+ console.warn(`Action '${action}' is not valid for cursor styles.`);
1210
+ }
1211
+
1212
+ /**
1213
+ * Gets the current style for a particular action.
1214
+ *
1215
+ * @param {String} action To get the style for
1216
+ * @returns {String} style set on the cursor for action
1217
+ */
1218
+ getCursorStyle(action) {
1219
+ return this._cursors[action] || null;
1220
+ }
1221
+
1184
1222
  _reset() {
1185
1223
  for (let i = 0, len = this._handlers.length; i < len; i++) {
1186
1224
  const handler = this._handlers[i];
@@ -18,6 +18,7 @@ class CameraUpdater {
18
18
  const pickController = controllers.pickController;
19
19
  const pivotController = controllers.pivotController;
20
20
  const panController = controllers.panController;
21
+ const cameraControl = controllers.cameraControl;
21
22
 
22
23
  let countDown = SCALE_DOLLY_EACH_FRAME; // Decrements on each tick
23
24
  let dollyDistFactor = 1.0; // Calculated when countDown is zero
@@ -142,7 +143,7 @@ class CameraUpdater {
142
143
  updates.rotateDeltaX *= configs.rotationInertia;
143
144
  updates.rotateDeltaY *= configs.rotationInertia;
144
145
 
145
- cursorType = "grabbing";
146
+ cursorType = cameraControl._cursors.rotate;
146
147
  }
147
148
 
148
149
  //----------------------------------------------------------------------------------------------------------
@@ -208,7 +209,7 @@ class CameraUpdater {
208
209
  camera.pan(vec);
209
210
  }
210
211
 
211
- cursorType = "grabbing";
212
+ cursorType = cameraControl._cursors.pan;
212
213
  }
213
214
 
214
215
  updates.panDeltaX *= configs.panInertia;
@@ -222,9 +223,9 @@ class CameraUpdater {
222
223
  if (dollyDeltaForDist !== 0) {
223
224
 
224
225
  if (dollyDeltaForDist < 0) {
225
- cursorType = "zoom-in";
226
+ cursorType = cameraControl._cursors.dollyForward;
226
227
  } else {
227
- cursorType = "zoom-out";
228
+ cursorType = cameraControl._cursors.dollyBackward;
228
229
  }
229
230
 
230
231
  if (configs.firstPerson) {
@@ -26,10 +26,6 @@ class KeyboardPanRotateDollyHandler {
26
26
  return;
27
27
  }
28
28
  keyDownMap[keyCode] = true;
29
-
30
- if (keyCode === input.KEY_SHIFT) {
31
- canvas.style.cursor = "move";
32
- }
33
29
  });
34
30
 
35
31
  this._onSceneKeyUp = input.on("keyup", (keyCode) => {
@@ -38,10 +34,6 @@ class KeyboardPanRotateDollyHandler {
38
34
  }
39
35
  keyDownMap[keyCode] = false;
40
36
 
41
- if (keyCode === input.KEY_SHIFT) {
42
- canvas.style.cursor = null;
43
- }
44
-
45
37
  if (controllers.pivotController.getPivoting()) {
46
38
  controllers.pivotController.endPivot()
47
39
  }
@@ -78,7 +78,6 @@ class MousePanRotateDollyHandler {
78
78
  });
79
79
 
80
80
  function setMousedownState(pick = true) {
81
- canvas.style.cursor = "move";
82
81
  setMousedownPositions();
83
82
  if (pick) {
84
83
  setMousedownPick();
@@ -109,7 +108,7 @@ class MousePanRotateDollyHandler {
109
108
  }
110
109
 
111
110
  function isPanning() {
112
- return cameraControl._isKeyDownForAction(cameraControl.MOUSE_PAN, keyDown);
111
+ return configs.planView || cameraControl._isKeyDownForAction(cameraControl.MOUSE_PAN, keyDown);
113
112
  }
114
113
 
115
114
  function isRotating() {
@@ -119,7 +119,8 @@ class TouchPanRotateAndDollyHandler {
119
119
 
120
120
  canvas.addEventListener("touchend", this._canvasTouchEndHandler = () => {
121
121
  if (pivotController.getPivoting()) {
122
- pivotController.endPivot()
122
+ pivotController.endPivot();
123
+ pivotController.hidePivot();
123
124
  }
124
125
  firstDragDeltaX = 0;
125
126
  firstDragDeltaY = 0;
@@ -191,28 +191,13 @@ class Marker extends Component {
191
191
  * @type {Entity}
192
192
  */
193
193
  set entity(entity) {
194
- if (this._entity) {
195
- if (this._entity === entity) {
196
- return;
197
- }
198
- if (this._onEntityDestroyed !== null) {
199
- if (this._entity.model) {
200
- this._entity.model.off(this._onEntityDestroyed);
201
- } else {
202
- this._entity.off(this._onEntityDestroyed);
203
- }
204
- this._onEntityDestroyed = null;
205
- }
206
- if (this._onEntityModelDestroyed !== null) {
207
- if (this._entity.model) {
208
- this._entity.model.off(this._onEntityModelDestroyed);
209
- }
210
- this._onEntityModelDestroyed = null;
211
- }
194
+ if (this._entity === entity) {
195
+ return;
212
196
  }
197
+ this._cleanupDestroyedHandlers();
213
198
  this._entity = entity;
214
199
  if (this._entity) {
215
- if (this._entity instanceof SceneModelEntity) {
200
+ if (this._entity.isSceneModelEntity) {
216
201
  this._onEntityModelDestroyed = this._entity.model.on("destroyed", () => { // SceneModelEntity does not fire events, and cannot exist beyond its VBOSceneModel
217
202
  this._entity = null; // Marker now may become visible, if it was synched to invisible Entity
218
203
  this._onEntityModelDestroyed = null;
@@ -374,16 +359,28 @@ class Marker extends Component {
374
359
  this.fire("destroyed", true);
375
360
  this.scene.camera.off(this._onCameraViewMatrix);
376
361
  this.scene.camera.off(this._onCameraProjMatrix);
362
+ this._cleanupDestroyedHandlers();
363
+ this._renderer.removeMarker(this);
364
+ super.destroy();
365
+ }
366
+
367
+ _cleanupDestroyedHandlers() {
377
368
  if (this._entity) {
378
369
  if (this._onEntityDestroyed !== null) {
379
- this._entity.model.off(this._onEntityDestroyed);
370
+ if (this._entity.model) {
371
+ this._entity.model.off(this._onEntityDestroyed);
372
+ } else {
373
+ this._entity.off(this._onEntityDestroyed);
374
+ }
375
+ this._onEntityDestroyed = null;
380
376
  }
381
377
  if (this._onEntityModelDestroyed !== null) {
382
- this._entity.model.off(this._onEntityModelDestroyed);
378
+ if (this._entity.model) {
379
+ this._entity.model.off(this._onEntityModelDestroyed);
380
+ }
381
+ this._onEntityModelDestroyed = null;
383
382
  }
384
383
  }
385
- this._renderer.removeMarker(this);
386
- super.destroy();
387
384
  }
388
385
  }
389
386
 
@@ -34,6 +34,11 @@ export class SceneModelEntity {
34
34
  */
35
35
  this.model = model;
36
36
 
37
+ /**
38
+ * Identifies if it's a SceneModelEntity
39
+ */
40
+ this.isSceneModelEntity = true;
41
+
37
42
  /**
38
43
  * The {@link SceneModelMesh}es belonging to this SceneModelEntity.
39
44
  *