@xeokit/xeokit-sdk 2.6.71 → 2.6.72

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xeokit/xeokit-sdk",
3
- "version": "2.6.71",
3
+ "version": "2.6.72",
4
4
  "description": "3D BIM IFC Viewer SDK for AEC engineering applications. Open Source JavaScript Toolkit based on pure WebGL for top performance, real-world coordinates and full double precision",
5
5
  "module": "./dist/xeokit-sdk.es.js",
6
6
  "main": "./dist/xeokit-sdk.cjs.js",
@@ -282,6 +282,7 @@ class ContextMenu {
282
282
  * @param {Boolean} [cfg.enabled=true] Whether this ````ContextMenu```` is initially enabled. {@link ContextMenu#show} does nothing while this is ````false````.
283
283
  * @param {Boolean} [cfg.hideOnMouseDown=true] Whether this ````ContextMenu```` automatically hides whenever we mouse-down or tap anywhere in the page.
284
284
  * @param {Boolean} [cfg.hideOnAction=true] Whether this ````ContextMenu```` automatically hides after we select a menu item. Se false if we want the menu to remain shown and show any updates to its item titles, after we've selected an item.
285
+ * @param {Node | undefined} [cfg.parentNode] Optional reference to an existing DOM Node (e.g. ShadowRoot), to which the menu's HTML element will be appended, defaults to ````document.body````.
285
286
  */
286
287
  constructor(cfg = {}) {
287
288
 
@@ -296,6 +297,7 @@ class ContextMenu {
296
297
  this._itemMap = {}; // Items mapped to their IDs
297
298
  this._shown = false; // True when the ContextMenu is visible
298
299
  this._nextId = 0;
300
+ this._parentNode = cfg.parentNode || document.body;
299
301
 
300
302
  /**
301
303
  * Subscriptions to events fired at this ContextMenu.
@@ -304,12 +306,12 @@ class ContextMenu {
304
306
  this._eventSubs = {};
305
307
 
306
308
  if (cfg.hideOnMouseDown !== false) {
307
- document.addEventListener("mousedown", (event) => {
309
+ this._parentNode.addEventListener("mousedown", (event) => {
308
310
  if (!event.target.classList.contains("xeokit-context-menu-item")) {
309
311
  this.hide();
310
312
  }
311
313
  });
312
- document.addEventListener("touchstart", this._canvasTouchStartHandler = (event) => {
314
+ this._parentNode.addEventListener("touchstart", this._canvasTouchStartHandler = (event) => {
313
315
  if (!event.target.classList.contains("xeokit-context-menu-item")) {
314
316
  this.hide();
315
317
  }
@@ -613,7 +615,10 @@ class ContextMenu {
613
615
  const groups = menu.groups;
614
616
  const html = [];
615
617
 
616
- html.push('<div class="xeokit-context-menu ' + menu.id + '" style="z-index:300000; position: absolute;">');
618
+ const menuElement= document.createElement("div");
619
+ menuElement.classList.add("xeokit-context-menu", menu.id);
620
+ menuElement.style.zIndex = 300000;
621
+ menuElement.style.position = "absolute";
617
622
 
618
623
  html.push('<ul>');
619
624
 
@@ -664,13 +669,10 @@ class ContextMenu {
664
669
  }
665
670
 
666
671
  html.push('</ul>');
667
- html.push('</div>');
668
672
 
669
673
  const htmlString = html.join("");
670
-
671
- document.body.insertAdjacentHTML('beforeend', htmlString);
672
-
673
- const menuElement = document.querySelector("." + menu.id);
674
+ menuElement.innerHTML = htmlString;
675
+ this._parentNode.appendChild(menuElement);
674
676
 
675
677
  menu.menuElement = menuElement;
676
678
 
@@ -704,7 +706,7 @@ class ContextMenu {
704
706
  const item = groupItems[j];
705
707
  const itemSubMenu = item.subMenu;
706
708
 
707
- item.itemElement = document.getElementById(item.id);
709
+ item.itemElement = this._parentNode.querySelector(`#${item.id}`);
708
710
 
709
711
  if (!item.itemElement) {
710
712
  console.error("ContextMenu item element not found: " + item.id);
@@ -7,6 +7,8 @@ const tempVec3a = math.vec3();
7
7
  const tempVec3b = math.vec3();
8
8
  const tempVec3c = math.vec3();
9
9
 
10
+ const px = x => x + "px";
11
+
10
12
  /**
11
13
  * A {@link Marker} with an HTML label attached to it, managed by an {@link AnnotationsPlugin}.
12
14
  *
@@ -213,22 +215,29 @@ class Annotation extends Marker {
213
215
  * @private
214
216
  */
215
217
  _updateWithCurWidths() {
216
- const px = x => x + "px";
217
218
  const boundary = this.scene.canvas.boundary;
218
219
  const left = boundary[0] + this.canvasPos[0];
219
220
  const top = boundary[1] + this.canvasPos[1];
220
- const markerWidth = this._curMarkerWidth;
221
- const markerDir = (this._markerAlign === "right") ? -1 : ((this._markerAlign === "center") ? 0 : 1);
222
- const markerCenter = left + markerDir * (markerWidth / 2 - 12);
223
- this._marker.style.left = px(markerCenter - markerWidth / 2);
224
- this._marker.style.top = px(top - 12);
225
- this._marker.style["z-index"] = 90005 + Math.floor(this._viewPos[2]) + 1;
226
-
227
- const labelWidth = this._curLabelWidth;
228
- const labelDir = Math.sign(this._labelPosition);
229
- this._label.style.left = px(markerCenter + labelDir * (markerWidth / 2 + Math.abs(this._labelPosition) + labelWidth / 2) - labelWidth / 2);
221
+ this._marker.style.top = px(top - 12);
230
222
  this._label.style.top = px(top - 17);
231
- this._label.style["z-index"] = 90005 + Math.floor(this._viewPos[2]) + 1;
223
+
224
+ if (this._markerAlign === "legacy") {
225
+ this._marker.style.left = px(left - 12);
226
+ this._label.style.left = px(left + 40);
227
+ } else {
228
+ const markerWidth = this._curMarkerWidth;
229
+ const markerDir = (this._markerAlign === "right") ? -1 : ((this._markerAlign === "center") ? 0 : 1);
230
+ const markerCenter = left + markerDir * (markerWidth / 2 - 12);
231
+ this._marker.style.left = px(markerCenter - markerWidth / 2);
232
+
233
+ const labelWidth = this._curLabelWidth;
234
+ const labelDir = Math.sign(this._labelPosition);
235
+ this._label.style.left = px(markerCenter + labelDir * (markerWidth / 2 + Math.abs(this._labelPosition) + labelWidth / 2) - labelWidth / 2);
236
+ }
237
+
238
+ const zIndex = 90005 + Math.floor(this._viewPos[2]) + 1;
239
+ this._marker.style["z-index"] = zIndex;
240
+ this._label.style["z-index"] = zIndex;
232
241
  }
233
242
 
234
243
  /**
@@ -259,7 +268,8 @@ class Annotation extends Marker {
259
268
  * @private
260
269
  */
261
270
  _updatePosition() {
262
- if (this._curMarkerWidth === undefined) {
271
+ const isLegacy = this._markerAlign === "legacy";
272
+ if ((! isLegacy) && (this._curMarkerWidth === undefined)) {
263
273
  this._updateIfWidthsChanged();
264
274
  } else {
265
275
  // Update position with cached width values
@@ -267,7 +277,9 @@ class Annotation extends Marker {
267
277
  // so they don't interfere with e.g. interactive scene manipulation
268
278
  this._updateWithCurWidths();
269
279
  window.clearTimeout(this._widthTimeout);
270
- this._widthTimeout = window.setTimeout(() => this._updateIfWidthsChanged(), 500);
280
+ if (! isLegacy) {
281
+ this._widthTimeout = window.setTimeout(() => this._updateIfWidthsChanged(), 500);
282
+ }
271
283
  }
272
284
  }
273
285
 
@@ -305,10 +317,10 @@ class Annotation extends Marker {
305
317
  /**
306
318
  * Sets the horizontal alignment of the Annotation's marker HTML.
307
319
  *
308
- * @param {String} align Either "left", "center", "right" (default "left")
320
+ * @param {String} align Either "left", "center", "right", "legacy" (default "left")
309
321
  */
310
322
  setMarkerAlign(align) {
311
- const valid = [ "left", "center", "right" ];
323
+ const valid = [ "left", "center", "right", "legacy" ];
312
324
  if (! valid.includes(align)) {
313
325
  this.error("Param 'align' should be one of: " + JSON.stringify(valid));
314
326
  } else {
@@ -8,6 +8,7 @@ function CubeTextureCanvas(viewer, navCubeScene, cfg = {}) {
8
8
  const cubeColor = "lightgrey";
9
9
  const cubeHighlightColor = cfg.hoverColor || "rgba(0,0,0,0.4)";
10
10
  const textColor = cfg.textColor || "black";
11
+ const parentNode = cfg.canvasElement || document.body;
11
12
 
12
13
  const height = 500;
13
14
  const width = height + (height / 3);
@@ -119,8 +120,7 @@ function CubeTextureCanvas(viewer, navCubeScene, cfg = {}) {
119
120
  this._textureCanvas.style.visibility = "hidden";
120
121
  this._textureCanvas.style["z-index"] = 2000000;
121
122
 
122
- const body = document.getElementsByTagName("body")[0];
123
- body.appendChild(this._textureCanvas);
123
+ parentNode.appendChild(this._textureCanvas);
124
124
 
125
125
  const context = this._textureCanvas.getContext("2d");
126
126
 
@@ -115,7 +115,7 @@ class NavCubePlugin extends Plugin {
115
115
  this._navCubeScene = new Scene(viewer, {
116
116
  canvasId: cfg.canvasId,
117
117
  canvasElement: cfg.canvasElement,
118
- transparent: true
118
+ transparent: true,
119
119
  });
120
120
 
121
121
  this._navCubeCanvas = this._navCubeScene.canvas.canvas;
@@ -361,7 +361,7 @@ class NavCubePlugin extends Plugin {
361
361
  }
362
362
  });
363
363
 
364
- document.addEventListener("mouseup", self._onMouseUp = function (e) {
364
+ self._navCubeCanvas.addEventListener("mouseup", self._onMouseUp = function (e) {
365
365
  if (e.which !== 1) {// Left button
366
366
  return;
367
367
  }
@@ -378,7 +378,7 @@ class NavCubePlugin extends Plugin {
378
378
  if (hit.uv) {
379
379
  var areaId = self._cubeTextureCanvas.getArea(hit.uv);
380
380
  if (areaId >= 0) {
381
- document.body.style.cursor = "pointer";
381
+ self._navCubeCanvas.style.cursor = "pointer";
382
382
  if (lastAreaId >= 0) {
383
383
  self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
384
384
  self._repaint();
@@ -404,7 +404,7 @@ class NavCubePlugin extends Plugin {
404
404
  self._repaint();
405
405
  lastAreaId = -1;
406
406
  }
407
- document.body.style.cursor = "pointer";
407
+ self._navCubeCanvas.style.cursor = "pointer";
408
408
  if (lastAreaId >= 0) {
409
409
  self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
410
410
  self._repaint();
@@ -423,7 +423,7 @@ class NavCubePlugin extends Plugin {
423
423
  }
424
424
  });
425
425
 
426
- document.addEventListener("mousemove", self._onMouseMove = function (e) {
426
+ self._navCubeCanvas.addEventListener("mousemove", self._onMouseMove = function (e) {
427
427
  if (lastAreaId >= 0) {
428
428
  self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
429
429
  self._repaint();
@@ -435,7 +435,7 @@ class NavCubePlugin extends Plugin {
435
435
  if (down) {
436
436
  var posX = e.clientX;
437
437
  var posY = e.clientY;
438
- document.body.style.cursor = "move";
438
+ self._navCubeCanvas.style.cursor = "move";
439
439
  actionMove(posX, posY);
440
440
  return;
441
441
  }
@@ -449,7 +449,7 @@ class NavCubePlugin extends Plugin {
449
449
  });
450
450
  if (hit) {
451
451
  if (hit.uv) {
452
- document.body.style.cursor = "pointer";
452
+ self._navCubeCanvas.style.cursor = "pointer";
453
453
  var areaId = self._cubeTextureCanvas.getArea(hit.uv);
454
454
  if (areaId === lastAreaId) {
455
455
  return;
@@ -464,7 +464,7 @@ class NavCubePlugin extends Plugin {
464
464
  }
465
465
  }
466
466
  } else {
467
- document.body.style.cursor = "default";
467
+ self._navCubeCanvas.style.cursor = "default";
468
468
  if (lastAreaId >= 0) {
469
469
  self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
470
470
  self._repaint();
@@ -727,8 +727,8 @@ class NavCubePlugin extends Plugin {
727
727
  this._navCubeCanvas.removeEventListener("mouseleave", this._onMouseLeave);
728
728
  this._navCubeCanvas.removeEventListener("mousedown", this._onMouseDown);
729
729
 
730
- document.removeEventListener("mousemove", this._onMouseMove);
731
- document.removeEventListener("mouseup", this._onMouseUp);
730
+ this._navCubeCanvas.removeEventListener("mousemove", this._onMouseMove);
731
+ this._navCubeCanvas.removeEventListener("mouseup", this._onMouseUp);
732
732
 
733
733
  this._navCubeCanvas = null;
734
734
  this._cubeTextureCanvas.destroy();
@@ -482,8 +482,8 @@ class Control {
482
482
  const canvasPos = math.vec2();
483
483
 
484
484
  const copyCanvasPos = (event, vec2) => {
485
- vec2[0] = event.clientX;
486
- vec2[1] = event.clientY;
485
+ vec2[0] = event.pageX;
486
+ vec2[1] = event.pageY;
487
487
  transformToNode(canvas.ownerDocument.documentElement, canvas, vec2);
488
488
  };
489
489
 
@@ -5,159 +5,13 @@ import {ReadableGeometry} from "../../viewer/scene/geometry/ReadableGeometry.js"
5
5
  import {PhongMaterial} from "../../viewer/scene/materials/PhongMaterial.js";
6
6
  import {math} from "../../viewer/scene/math/math.js";
7
7
  import {Mesh} from "../../viewer/scene/mesh/Mesh.js";
8
- import {activateDraggableDots, Dot3D, Wire3D, touchPointSelector, transformToNode} from "../../../src/plugins/lib/ui/index.js";
8
+ import {activateDraggableDots, Dot3D, marker3D, wire3D, touchPointSelector, transformToNode, triangulateEarClipping} from "../../../src/plugins/lib/ui/index.js";
9
9
 
10
10
  const hex2rgb = function(color) {
11
11
  const rgb = idx => parseInt(color.substr(idx + 1, 2), 16) / 255;
12
12
  return [ rgb(0), rgb(2), rgb(4) ];
13
13
  };
14
14
 
15
- const triangulateEarClipping = function(planeCoords) {
16
-
17
- const polygonVertices = [ ];
18
- for (let i = 0; i < planeCoords.length; ++i)
19
- polygonVertices.push(i);
20
-
21
- const isCCW = (function() {
22
- const ba = math.vec2();
23
- const bc = math.vec2();
24
-
25
- let anglesSum = 0;
26
- const angles = [ ];
27
-
28
- for (let i = 0; i < polygonVertices.length; ++i)
29
- {
30
- const a = planeCoords[polygonVertices[i]];
31
- const b = planeCoords[polygonVertices[(i + 1) % polygonVertices.length]];
32
- const c = planeCoords[polygonVertices[(i + 2) % polygonVertices.length]];
33
-
34
- math.subVec2(a, b, ba);
35
- math.subVec2(c, b, bc);
36
-
37
- const theta = math.dotVec2(ba, bc) / Math.sqrt(math.sqLenVec2(ba) * math.sqLenVec2(bc));
38
- const angle = Math.acos(Math.max(-1, Math.min(theta, 1)));
39
- const convex = (ba[0] * bc[1] - ba[1] * bc[0]) >= 0;
40
- anglesSum += convex ? angle : (2 * Math.PI - angle);
41
- }
42
-
43
- return anglesSum < (polygonVertices.length * Math.PI);
44
- })();
45
-
46
- const pointInTriangle = (function() {
47
- const sign = (p1, p2, p3) => {
48
- return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
49
- };
50
-
51
- return (pt, v1, v2, v3) => {
52
- const d1 = sign(pt, v1, v2);
53
- const d2 = sign(pt, v2, v3);
54
- const d3 = sign(pt, v3, v1);
55
-
56
- const has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
57
- const has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
58
-
59
- return !(has_neg && has_pos);
60
- };
61
- })();
62
-
63
- const baseTriangles = [ ];
64
-
65
- const vertices = (isCCW ? polygonVertices : polygonVertices.slice(0).reverse()).map(i => ({ idx: i }));
66
- vertices.forEach((v, i) => {
67
- v.prev = vertices[(i - 1 + vertices.length) % vertices.length];
68
- v.next = vertices[(i + 1) % vertices.length];
69
- });
70
-
71
- const ba = math.vec2();
72
- const bc = math.vec2();
73
-
74
- while (vertices.length > 2) {
75
- let earIdx = 0;
76
- while (true) {
77
- if (earIdx >= vertices.length)
78
- {
79
- throw `isCCW = ${isCCW}; earIdx = ${earIdx}; len = ${vertices.length}`;
80
- }
81
- const v = vertices[earIdx];
82
-
83
- const a = planeCoords[v.prev.idx];
84
- const b = planeCoords[v.idx];
85
- const c = planeCoords[v.next.idx];
86
-
87
- math.subVec2(a, b, ba);
88
- math.subVec2(c, b, bc);
89
-
90
- if (((ba[0] * bc[1] - ba[1] * bc[0]) >= 0) // a convex vertex
91
- &&
92
- vertices.every( // no other vertices inside
93
- vv => ((vv === v)
94
- ||
95
- (vv === v.prev)
96
- ||
97
- (vv === v.next)
98
- ||
99
- !pointInTriangle(planeCoords[vv.idx], a, b, c))))
100
- break;
101
- ++earIdx;
102
- }
103
-
104
- const ear = vertices[earIdx];
105
- vertices.splice(earIdx, 1);
106
-
107
- baseTriangles.push([ ear.idx, ear.next.idx, ear.prev.idx ]);
108
-
109
- const prev = ear.prev;
110
- prev.next = ear.next;
111
- const next = ear.next;
112
- next.prev = ear.prev;
113
- }
114
-
115
- return [ planeCoords, baseTriangles, isCCW ];
116
- };
117
-
118
- const marker3D = function(scene, color) {
119
- const marker = new Dot3D(scene, {}, scene.canvas.canvas.parentNode, {
120
- borderColor: "white",
121
- fillColor: color,
122
- zIndex: 100
123
- });
124
-
125
- return {
126
- update: function(worldPos) {
127
- if (worldPos)
128
- {
129
- marker.worldPos = worldPos;
130
- }
131
- marker.setVisible(!!worldPos);
132
- },
133
-
134
- setHighlighted: h => marker.setHighlighted(h),
135
- getCanvasPos: () => marker.canvasPos,
136
- getWorldPos: () => marker.worldPos,
137
- destroy: () => marker.destroy()
138
- };
139
- };
140
-
141
- const wire3D = function(scene, color, startWorldPos) {
142
- const wire = new Wire3D(scene, scene.canvas.canvas.ownerDocument.body, {
143
- color: color,
144
- thickness: 1,
145
- thicknessClickable: 6
146
- });
147
- wire.setVisible(false);
148
- return {
149
- update: endWorldPos => {
150
- if (endWorldPos)
151
- {
152
- wire.setEnds(startWorldPos, endWorldPos);
153
- }
154
- wire.setVisible(!!endWorldPos);
155
- },
156
-
157
- destroy: () => wire.destroy()
158
- };
159
- };
160
-
161
15
  const basePolygon3D = function(scene, color, alpha) {
162
16
  let mesh = null;
163
17
 
@@ -1160,7 +1014,8 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
1160
1014
 
1161
1015
  (function selectNextPoint(markers) {
1162
1016
  const marker = marker3D(scene, zoneColor);
1163
- const wire = (markers.length > 0) && wire3D(scene, zoneColor, markers[markers.length - 1].getWorldPos());
1017
+ const wire = (markers.length > 0) && wire3D(scene, zoneColor);
1018
+ const wireStart = wire && markers[markers.length - 1].getWorldPos();
1164
1019
 
1165
1020
  cleanups.push(() => {
1166
1021
  marker.destroy();
@@ -1220,7 +1075,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
1220
1075
  () => {
1221
1076
  updatePointerLens(null);
1222
1077
  marker.update(null);
1223
- wire && wire.update(null);
1078
+ wire && wire.update(wireStart, null);
1224
1079
  basePolygon.updateBase((markers.length > 2) ? markers.map(m => m.getWorldPos()) : null);
1225
1080
  },
1226
1081
  (canvasPos, worldPos) => {
@@ -1228,7 +1083,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
1228
1083
  firstMarker && firstMarker.setHighlighted(!! snappedFirst);
1229
1084
  updatePointerLens(snappedFirst ? snappedFirst.canvasPos : canvasPos);
1230
1085
  marker.update((! snappedFirst) && worldPos);
1231
- wire && wire.update(snappedFirst ? snappedFirst.worldPos : worldPos);
1086
+ wire && wire.update(wireStart, snappedFirst ? snappedFirst.worldPos : worldPos);
1232
1087
  if ((markers.length >= 2))
1233
1088
  {
1234
1089
  const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
@@ -1272,7 +1127,7 @@ const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, z
1272
1127
  else
1273
1128
  {
1274
1129
  marker.update(worldPos);
1275
- wire && wire.update(worldPos);
1130
+ wire && wire.update(wireStart, worldPos);
1276
1131
  selectNextPoint(markers.concat(marker));
1277
1132
  }
1278
1133
  });