@xeokit/xeokit-sdk 2.6.20 → 2.6.23

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.20",
3
+ "version": "2.6.23",
4
4
  "description": "Web Programming Toolkit for 3D/2D BIM and AEC Graphics",
5
5
  "module": "./dist/xeokit-sdk.es.js",
6
6
  "main": "./dist/xeokit-sdk.cjs.js",
@@ -103,10 +103,10 @@ export class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
103
103
  }
104
104
 
105
105
  _destroyMarkerDiv() {
106
- if (this._markerDiv) {
106
+ if (this.markerDiv) {
107
107
  const element = document.getElementById('myMarkerDiv')
108
108
  element.parentNode.removeChild(element)
109
- this._markerDiv = null
109
+ this.markerDiv = null
110
110
  }
111
111
  }
112
112
 
@@ -1,4 +1,62 @@
1
1
  export * from "./AngleMeasurementsPlugin.js";
2
2
  export * from "./AngleMeasurementsControl.js";
3
3
  export * from "./AngleMeasurementsMouseControl.js";
4
- export * from "./AngleMeasurementsTouchControl.js";
4
+ export * from "./AngleMeasurementsTouchControl.js";
5
+
6
+ import {Component} from "../../viewer/scene/Component.js";
7
+ import {activateDraggableDots} from "../../../src/plugins/lib/ui/index.js";
8
+
9
+ class AngleMeasurementEditControl extends Component {
10
+
11
+ /**
12
+ * Edits {@link AngleMeasurement} with mouse and/or touch input.
13
+ *
14
+ * @param {AngleMeasurement} [measurement] The AngleMeasurement to edit.
15
+ * @param [cfg] Configuration
16
+ * @param {PointerLens} [cfg.pointerLens] A PointerLens to use to provide a magnified view of the cursor.
17
+ * @param {boolean} [cfg.snapping] Whether to enable snap-to-vertex and snap-to-edge.
18
+ * @param {boolean} [handleMouseEvents] Whether to hangle mouse input.
19
+ * @param {boolean} [handleTouchEvents] Whether to hangle touch input.
20
+ */
21
+ constructor(measurement, cfg, handleMouseEvents, handleTouchEvents) {
22
+
23
+ const viewer = measurement.plugin.viewer;
24
+
25
+ super(viewer.scene);
26
+
27
+ const cleanup = activateDraggableDots({
28
+ viewer: viewer,
29
+ handleMouseEvents: handleMouseEvents,
30
+ handleTouchEvents: handleTouchEvents,
31
+ snapping: cfg.snapping,
32
+ pointerLens: cfg.pointerLens,
33
+ color: measurement.color,
34
+ markers: [ measurement.origin, measurement.corner, measurement.target ],
35
+ onEdit: () => this.fire("edited")
36
+ });
37
+
38
+ const destroyCb = measurement.on("destroyed", cleanup);
39
+
40
+ this._deactivate = function() {
41
+ measurement.off("destroyed", destroyCb);
42
+ cleanup();
43
+ };
44
+ }
45
+
46
+ deactivate() {
47
+ this._deactivate();
48
+ super.destroy();
49
+ }
50
+ }
51
+
52
+ export class AngleMeasurementEditMouseControl extends AngleMeasurementEditControl {
53
+ constructor(zone, cfg) {
54
+ super(zone, cfg, true, false);
55
+ }
56
+ }
57
+
58
+ export class AngleMeasurementEditTouchControl extends AngleMeasurementEditControl {
59
+ constructor(zone, cfg) {
60
+ super(zone, cfg, false, true);
61
+ }
62
+ }
@@ -1,4 +1,62 @@
1
1
  export * from "./DistanceMeasurementsPlugin.js";
2
2
  export * from "./DistanceMeasurementsControl.js";
3
3
  export * from "./DistanceMeasurementsMouseControl.js";
4
- export * from "./DistanceMeasurementsTouchControl.js";
4
+ export * from "./DistanceMeasurementsTouchControl.js";
5
+
6
+ import {Component} from "../../viewer/scene/Component.js";
7
+ import {activateDraggableDots} from "../../../src/plugins/lib/ui/index.js";
8
+
9
+ class DistanceMeasurementEditControl extends Component {
10
+
11
+ /**
12
+ * Edits {@link DistanceMeasurement} with mouse and/or touch input.
13
+ *
14
+ * @param {DistanceMeasurement} [measurement] The DistanceMeasurement to edit.
15
+ * @param [cfg] Configuration
16
+ * @param {PointerLens} [cfg.pointerLens] A PointerLens to use to provide a magnified view of the cursor.
17
+ * @param {boolean} [cfg.snapping] Whether to enable snap-to-vertex and snap-to-edge.
18
+ * @param {boolean} [handleMouseEvents] Whether to hangle mouse input.
19
+ * @param {boolean} [handleTouchEvents] Whether to hangle touch input.
20
+ */
21
+ constructor(measurement, cfg, handleMouseEvents, handleTouchEvents) {
22
+
23
+ const viewer = measurement.plugin.viewer;
24
+
25
+ super(viewer.scene);
26
+
27
+ const cleanup = activateDraggableDots({
28
+ viewer: viewer,
29
+ handleMouseEvents: handleMouseEvents,
30
+ handleTouchEvents: handleTouchEvents,
31
+ snapping: cfg.snapping,
32
+ pointerLens: cfg.pointerLens,
33
+ color: measurement.color,
34
+ markers: [ measurement.origin, measurement.target ],
35
+ onEdit: () => this.fire("edited")
36
+ });
37
+
38
+ const destroyCb = measurement.on("destroyed", cleanup);
39
+
40
+ this._deactivate = function() {
41
+ measurement.off("destroyed", destroyCb);
42
+ cleanup();
43
+ };
44
+ }
45
+
46
+ deactivate() {
47
+ this._deactivate();
48
+ super.destroy();
49
+ }
50
+ }
51
+
52
+ export class DistanceMeasurementEditMouseControl extends DistanceMeasurementEditControl {
53
+ constructor(zone, cfg) {
54
+ super(zone, cfg, true, false);
55
+ }
56
+ }
57
+
58
+ export class DistanceMeasurementEditTouchControl extends DistanceMeasurementEditControl {
59
+ constructor(zone, cfg) {
60
+ super(zone, cfg, false, true);
61
+ }
62
+ }
@@ -7,19 +7,13 @@ import {PhongMaterial} from "../../viewer/scene/materials/PhongMaterial.js";
7
7
  import {math} from "../../viewer/scene/math/math.js";
8
8
  import {Mesh} from "../../viewer/scene/mesh/Mesh.js";
9
9
  import {Dot} from "../lib/html/Dot.js";
10
+ import {createDraggableDot3D, transformToNode} from "../../../src/plugins/lib/ui/index.js";
10
11
 
11
12
  const hex2rgb = function(color) {
12
13
  const rgb = idx => parseInt(color.substr(idx + 1, 2), 16) / 255;
13
14
  return [ rgb(0), rgb(2), rgb(4) ];
14
15
  };
15
16
 
16
- const transformToNode = function(from, to, vec) {
17
- const fromRec = from.getBoundingClientRect();
18
- const toRec = to.getBoundingClientRect();
19
- vec[0] += fromRec.left - toRec.left;
20
- vec[1] += fromRec.top - toRec.top;
21
- };
22
-
23
17
  const triangulateEarClipping = function(planeCoords) {
24
18
 
25
19
  const polygonVertices = [ ];
@@ -123,148 +117,6 @@ const triangulateEarClipping = function(planeCoords) {
123
117
  return [ planeCoords, baseTriangles ];
124
118
  };
125
119
 
126
- const draggableDot3D = function(handleMouseEvents, handleTouchEvents, viewer, worldPos, color, ray2WorldPos, onStart, onMove, onEnd) {
127
- const scene = viewer.scene;
128
- const canvas = scene.canvas.canvas;
129
-
130
- const marker = new Marker(scene, {});
131
-
132
- const pickWorldPos = canvasPos => {
133
- const origin = math.vec3();
134
- const direction = math.vec3();
135
- math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
136
- return ray2WorldPos(origin, direction);
137
- };
138
-
139
- const onChange = event => {
140
- const canvasPos = math.vec2([ event.clientX, event.clientY ]);
141
- transformToNode(canvas.ownerDocument.body, canvas, canvasPos);
142
-
143
- const worldPos = pickWorldPos(canvasPos);
144
- marker.worldPos = worldPos;
145
- updateDotPos();
146
- onMove(canvasPos, worldPos);
147
- };
148
-
149
- let currentDrag = null;
150
-
151
- const onDragMove = function(event) {
152
- const e = currentDrag.matchesEvent(event);
153
- if (e)
154
- {
155
- onChange(e);
156
- }
157
- };
158
-
159
- const onDragEnd = function(event) {
160
- const e = currentDrag.matchesEvent(event);
161
- if (e)
162
- {
163
- dot.setOpacity(idleOpacity);
164
- currentDrag.cleanup();
165
- onChange(e);
166
- onEnd();
167
- }
168
- };
169
-
170
- const startDrag = function(matchesEvent, cleanupHandlers) {
171
- if (currentDrag) {
172
- currentDrag.cleanup();
173
- }
174
-
175
- dot.setOpacity(1.0);
176
- dot.setClickable(false);
177
- viewer.cameraControl.active = false;
178
-
179
- currentDrag = {
180
- matchesEvent: matchesEvent,
181
- cleanup: function() {
182
- currentDrag = null;
183
- dot.setClickable(true);
184
- viewer.cameraControl.active = true;
185
- cleanupHandlers();
186
- }
187
- };
188
-
189
- onStart();
190
- };
191
-
192
- const dotCfg = { fillColor: color };
193
-
194
- if (handleMouseEvents)
195
- {
196
- dotCfg.onMouseOver = () => (! currentDrag) && dot.setOpacity(1.0);
197
- dotCfg.onMouseLeave = () => (! currentDrag) && dot.setOpacity(idleOpacity);
198
- dotCfg.onMouseDown = event => {
199
- if (event.which === 1)
200
- {
201
- canvas.addEventListener("mousemove", onDragMove);
202
- canvas.addEventListener("mouseup", onDragEnd);
203
- startDrag(
204
- event => (event.which === 1) && event,
205
- () => {
206
- canvas.removeEventListener("mousemove", onDragMove);
207
- canvas.removeEventListener("mouseup", onDragEnd);
208
- });
209
- }
210
- };
211
- }
212
-
213
- if (handleTouchEvents)
214
- {
215
- let touchStartId;
216
- dotCfg.onTouchstart = event => {
217
- event.preventDefault();
218
- if (event.touches.length === 1)
219
- {
220
- touchStartId = event.touches[0].identifier;
221
- startDrag(
222
- event => [...event.changedTouches].find(e => e.identifier === touchStartId),
223
- () => { touchStartId = null; });
224
- }
225
- };
226
- dotCfg.onTouchmove = event => {
227
- event.preventDefault();
228
- onDragMove(event);
229
- };
230
- dotCfg.onTouchend = event => {
231
- event.preventDefault();
232
- onDragEnd(event);
233
- };
234
- }
235
-
236
- const dotParent = canvas.ownerDocument.body;
237
- const dot = new Dot(dotParent, dotCfg);
238
-
239
- const idleOpacity = 0.5;
240
- dot.setOpacity(idleOpacity);
241
-
242
- const updateDotPos = function() {
243
- const pos = marker.canvasPos.slice();
244
- transformToNode(canvas, dotParent, pos);
245
- dot.setPos(pos[0], pos[1]);
246
- };
247
-
248
- marker.worldPos = worldPos;
249
- updateDotPos();
250
-
251
- const onViewMatrix = scene.camera.on("viewMatrix", updateDotPos);
252
- const onProjMatrix = scene.camera.on("projMatrix", updateDotPos);
253
-
254
- return {
255
- setActive: value => dot.setClickable(value),
256
- getWorldPos: () => marker.worldPos,
257
- setWorldPos: pos => { marker.worldPos = pos; updateDotPos(); },
258
- destroy: function() {
259
- currentDrag && currentDrag.cleanup();
260
- scene.camera.off(onViewMatrix);
261
- scene.camera.off(onProjMatrix);
262
- marker.destroy();
263
- dot.destroy();
264
- }
265
- };
266
- };
267
-
268
120
  const marker3D = function(scene, color) {
269
121
  const canvas = scene.canvas.canvas;
270
122
 
@@ -1790,23 +1642,23 @@ export class ZoneEditControl extends Component {
1790
1642
  }
1791
1643
  };
1792
1644
 
1793
- const dot = draggableDot3D(
1794
- handleMouseEvents,
1795
- handleTouchEvents,
1796
- zone.plugin.viewer,
1797
- math.vec3([ planeCoord[0], altitude, planeCoord[1] ]),
1798
- zone._color,
1799
- (orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir),
1800
- () => {
1645
+ const dot = createDraggableDot3D({
1646
+ handleMouseEvents: handleMouseEvents,
1647
+ handleTouchEvents: handleTouchEvents,
1648
+ viewer: zone.plugin.viewer,
1649
+ worldPos: math.vec3([ planeCoord[0], altitude, planeCoord[1] ]),
1650
+ color: zone._color,
1651
+ ray2WorldPos: (orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir),
1652
+ onStart: () => {
1801
1653
  initWorldPos = dot.getWorldPos().slice();
1802
1654
  initPlaneCoord = planeCoord.slice();
1803
1655
  set_other_dots_active(false, dot);
1804
1656
  },
1805
- (canvasPos, worldPos) => {
1657
+ onMove: (canvasPos, worldPos) => {
1806
1658
  updatePointerLens(canvasPos);
1807
1659
  setPlaneCoord([ worldPos[0], worldPos[2] ]);
1808
1660
  },
1809
- () => {
1661
+ onEnd: () => {
1810
1662
  if (zone._zoneMesh)
1811
1663
  {
1812
1664
  self.fire("edited");
@@ -1818,7 +1670,8 @@ export class ZoneEditControl extends Component {
1818
1670
  }
1819
1671
  updatePointerLens(null);
1820
1672
  set_other_dots_active(true, dot);
1821
- });
1673
+ }
1674
+ });
1822
1675
  return dot;
1823
1676
  });
1824
1677
  const set_other_dots_active = (active, dot) => dots.forEach(d => (d !== dot) && d.setActive(active));
@@ -0,0 +1,264 @@
1
+ import {Dot} from "../html/Dot.js";
2
+ import {math} from "../../../viewer/scene/math/math.js";
3
+ import {Marker} from "../../../viewer/scene/marker/Marker.js";
4
+
5
+ const nop = () => { };
6
+
7
+ export function transformToNode(from, to, vec) {
8
+ const fromRec = from.getBoundingClientRect();
9
+ const toRec = to.getBoundingClientRect();
10
+ vec[0] += fromRec.left - toRec.left;
11
+ vec[1] += fromRec.top - toRec.top;
12
+ };
13
+
14
+ export function createDraggableDot3D(cfg) {
15
+ const extractCFG = function(propName, defaultValue) {
16
+ if (propName in cfg) {
17
+ return cfg[propName];
18
+ } else if (defaultValue !== undefined) {
19
+ return defaultValue;
20
+ } else {
21
+ throw "config missing: " + propName;
22
+ }
23
+ };
24
+
25
+ const viewer = extractCFG("viewer");
26
+ const worldPos = extractCFG("worldPos");
27
+ const color = extractCFG("color");
28
+ const ray2WorldPos = extractCFG("ray2WorldPos");
29
+ const handleMouseEvents = extractCFG("handleMouseEvents", false);
30
+ const handleTouchEvents = extractCFG("handleTouchEvents", false);
31
+ const onStart = extractCFG("onStart", nop);
32
+ const onMove = extractCFG("onMove", nop);
33
+ const onEnd = extractCFG("onEnd", nop);
34
+
35
+ const scene = viewer.scene;
36
+ const canvas = scene.canvas.canvas;
37
+
38
+ const marker = new Marker(scene, {});
39
+
40
+ const pickWorldPos = canvasPos => {
41
+ const origin = math.vec3();
42
+ const direction = math.vec3();
43
+ math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
44
+ return ray2WorldPos(origin, direction, canvasPos);
45
+ };
46
+
47
+ const onChange = event => {
48
+ const canvasPos = math.vec2([ event.clientX, event.clientY ]);
49
+ transformToNode(canvas.ownerDocument.body, canvas, canvasPos);
50
+
51
+ const worldPos = pickWorldPos(canvasPos);
52
+ marker.worldPos = worldPos;
53
+ updateDotPos();
54
+ onMove(canvasPos, worldPos);
55
+ };
56
+
57
+ let currentDrag = null;
58
+
59
+ const onDragMove = function(event) {
60
+ const e = currentDrag.matchesEvent(event);
61
+ if (e)
62
+ {
63
+ onChange(e);
64
+ }
65
+ };
66
+
67
+ const onDragEnd = function(event) {
68
+ const e = currentDrag.matchesEvent(event);
69
+ if (e)
70
+ {
71
+ dot.setOpacity(idleOpacity);
72
+ currentDrag.cleanup();
73
+ onChange(e);
74
+ onEnd();
75
+ }
76
+ };
77
+
78
+ const startDrag = function(matchesEvent, cleanupHandlers) {
79
+ if (currentDrag) {
80
+ currentDrag.cleanup();
81
+ }
82
+
83
+ dot.setOpacity(1.0);
84
+ dot.setClickable(false);
85
+ viewer.cameraControl.active = false;
86
+
87
+ currentDrag = {
88
+ matchesEvent: matchesEvent,
89
+ cleanup: function() {
90
+ currentDrag = null;
91
+ dot.setClickable(true);
92
+ viewer.cameraControl.active = true;
93
+ cleanupHandlers();
94
+ }
95
+ };
96
+
97
+ onStart();
98
+ };
99
+
100
+ const dotCfg = { fillColor: color };
101
+
102
+ if (handleMouseEvents)
103
+ {
104
+ dotCfg.onMouseOver = () => (! currentDrag) && dot.setOpacity(1.0);
105
+ dotCfg.onMouseLeave = () => (! currentDrag) && dot.setOpacity(idleOpacity);
106
+ dotCfg.onMouseDown = event => {
107
+ if (event.which === 1)
108
+ {
109
+ canvas.addEventListener("mousemove", onDragMove);
110
+ canvas.addEventListener("mouseup", onDragEnd);
111
+ startDrag(
112
+ event => (event.which === 1) && event,
113
+ () => {
114
+ canvas.removeEventListener("mousemove", onDragMove);
115
+ canvas.removeEventListener("mouseup", onDragEnd);
116
+ });
117
+ }
118
+ };
119
+ }
120
+
121
+ if (handleTouchEvents)
122
+ {
123
+ let touchStartId;
124
+ dotCfg.onTouchstart = event => {
125
+ event.preventDefault();
126
+ if (event.touches.length === 1)
127
+ {
128
+ touchStartId = event.touches[0].identifier;
129
+ startDrag(
130
+ event => [...event.changedTouches].find(e => e.identifier === touchStartId),
131
+ () => { touchStartId = null; });
132
+ }
133
+ };
134
+ dotCfg.onTouchmove = event => {
135
+ event.preventDefault();
136
+ onDragMove(event);
137
+ };
138
+ dotCfg.onTouchend = event => {
139
+ event.preventDefault();
140
+ onDragEnd(event);
141
+ };
142
+ }
143
+
144
+ const dotParent = canvas.ownerDocument.body;
145
+ const dot = new Dot(dotParent, dotCfg);
146
+
147
+ const idleOpacity = 0.5;
148
+ dot.setOpacity(idleOpacity);
149
+
150
+ const updateDotPos = function() {
151
+ const pos = marker.canvasPos.slice();
152
+ transformToNode(canvas, dotParent, pos);
153
+ dot.setPos(pos[0], pos[1]);
154
+ };
155
+
156
+ marker.worldPos = worldPos;
157
+ updateDotPos();
158
+
159
+ const onViewMatrix = scene.camera.on("viewMatrix", updateDotPos);
160
+ const onProjMatrix = scene.camera.on("projMatrix", updateDotPos);
161
+
162
+ return {
163
+ setActive: value => dot.setClickable(value),
164
+ getWorldPos: () => marker.worldPos,
165
+ setWorldPos: pos => { marker.worldPos = pos; updateDotPos(); },
166
+ destroy: function() {
167
+ currentDrag && currentDrag.cleanup();
168
+ scene.camera.off(onViewMatrix);
169
+ scene.camera.off(onProjMatrix);
170
+ marker.destroy();
171
+ dot.destroy();
172
+ }
173
+ };
174
+ };
175
+
176
+ export function activateDraggableDots(cfg) {
177
+ const extractCFG = function(propName, defaultValue) {
178
+ if (propName in cfg) {
179
+ return cfg[propName];
180
+ } else if (defaultValue !== undefined) {
181
+ return defaultValue;
182
+ } else {
183
+ throw "config missing: " + propName;
184
+ }
185
+ };
186
+
187
+ const viewer = extractCFG("viewer");
188
+ const handleMouseEvents = extractCFG("handleMouseEvents", false);
189
+ const handleTouchEvents = extractCFG("handleTouchEvents", false);
190
+ const snapping = extractCFG("snapping");
191
+ const pointerLens = extractCFG("pointerLens", null);
192
+ const color = extractCFG("color");
193
+ const markers = extractCFG("markers");
194
+ const onEdit = extractCFG("onEdit", nop);
195
+
196
+ const updatePointerLens = (pointerLens
197
+ ? function(canvasPos) {
198
+ pointerLens.visible = !! canvasPos;
199
+ if (canvasPos)
200
+ {
201
+ pointerLens.canvasPos = canvasPos;
202
+ }
203
+ }
204
+ : () => { });
205
+
206
+ const dots = markers.map(marker => {
207
+ let initDotPos, initMarkerPos;
208
+ const setCoord = coord => marker.worldPos = coord;
209
+
210
+ const dot = createDraggableDot3D({
211
+ handleMouseEvents: handleMouseEvents,
212
+ handleTouchEvents: handleTouchEvents,
213
+ viewer: viewer,
214
+ worldPos: marker.worldPos,
215
+ color: color,
216
+ ray2WorldPos: (orig, dir, canvasPos) => {
217
+ const tryPickWorldPos = snap => {
218
+ const pickResult = viewer.scene.pick({
219
+ canvasPos: canvasPos,
220
+ snapToEdge: snap,
221
+ snapToVertex: snap,
222
+ pickSurface: true // <<------ This causes picking to find the intersection point on the entity
223
+ });
224
+
225
+ // If - when snapping - no pick found, then try w/o snapping
226
+ return (pickResult && pickResult.worldPos) ? pickResult.worldPos : (snap && tryPickWorldPos(false));
227
+ };
228
+
229
+ return tryPickWorldPos(!!snapping) || initDotPos;
230
+ },
231
+ onStart: () => {
232
+ initDotPos = dot.getWorldPos().slice();
233
+ initMarkerPos = marker.worldPos.slice();
234
+ setOtherDotsActive(false, dot);
235
+ },
236
+ onMove: (canvasPos, worldPos) => {
237
+ updatePointerLens(canvasPos);
238
+ setCoord(worldPos);
239
+ },
240
+ onEnd: () => {
241
+ if (! math.compareVec3(initMarkerPos, marker.worldPos))
242
+ {
243
+ onEdit();
244
+ }
245
+ else
246
+ {
247
+ dot.setWorldPos(initDotPos);
248
+ setCoord(initMarkerPos);
249
+ }
250
+ updatePointerLens(null);
251
+ setOtherDotsActive(true, dot);
252
+ }
253
+ });
254
+ return dot;
255
+ });
256
+
257
+ const setOtherDotsActive = (active, dot) => dots.forEach(d => (d !== dot) && d.setActive(active));
258
+ setOtherDotsActive(true);
259
+
260
+ return function() {
261
+ dots.forEach(m => m.destroy());
262
+ updatePointerLens(null);
263
+ };
264
+ }