@xeokit/xeokit-sdk 2.6.0-beta-11 → 2.6.0-beta-13

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.
@@ -0,0 +1,916 @@
1
+ import {math} from "../../viewer/scene/math/math.js";
2
+ import {PointerCircle} from "../../extras/PointerCircle/PointerCircle.js";
3
+ import {AngleMeasurementsControl} from "./AngleMeasurementsControl.js";
4
+
5
+
6
+ const WAITING_FOR_ORIGIN_TOUCH_START = 0;
7
+ const WAITING_FOR_ORIGIN_QUICK_TOUCH_END = 1;
8
+ const WAITING_FOR_ORIGIN_LONG_TOUCH_END = 2;
9
+
10
+ const WAITING_FOR_CORNER_TOUCH_START = 3;
11
+ const WAITING_FOR_CORNER_QUICK_TOUCH_END = 4;
12
+ const WAITING_FOR_CORNER_LONG_TOUCH_END = 5;
13
+
14
+ const WAITING_FOR_TARGET_TOUCH_START = 6;
15
+ const WAITING_FOR_TARGET_QUICK_TOUCH_END = 7;
16
+ const WAITING_FOR_TARGET_LONG_TOUCH_END = 8;
17
+
18
+ const TOUCH_CANCELING = 7;
19
+
20
+ /**
21
+ * Creates {@link AngleMeasurement}s from touch input.
22
+ *
23
+ * See {@link AngleMeasurementsPlugin} for more info.
24
+ *
25
+ */
26
+ export class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
27
+
28
+ /**
29
+ * Creates a AngleMeasurementsTouchControl bound to the given AngleMeasurementsPlugin.
30
+ */
31
+ constructor(angleMeasurementsPlugin, cfg = {}) {
32
+
33
+ super(angleMeasurementsPlugin.viewer.scene);
34
+
35
+ this.pointerLens = cfg.pointerLens;
36
+ this.pointerCircle = new PointerCircle(angleMeasurementsPlugin.viewer);
37
+
38
+ this._active = false;
39
+
40
+ const markerDiv = document.createElement('div');
41
+ const canvas = this.scene.canvas.canvas;
42
+ canvas.parentNode.insertBefore(markerDiv, canvas);
43
+
44
+ markerDiv.style.background = "black";
45
+ markerDiv.style.border = "2px solid blue";
46
+ markerDiv.style.borderRadius = "10px";
47
+ markerDiv.style.width = "5px";
48
+ markerDiv.style.height = "5px";
49
+ markerDiv.style.margin = "-200px -200px";
50
+ markerDiv.style.zIndex = "100";
51
+ markerDiv.style.position = "absolute";
52
+ markerDiv.style.pointerEvents = "none";
53
+
54
+ this.markerDiv = markerDiv;
55
+
56
+ this._currentAngleMeasurement = null;
57
+
58
+ this._onCanvasTouchStart = null;
59
+ this._onCanvasTouchEnd = null;
60
+ this._longTouchTimeoutMs = 300;
61
+ this._snapToEdge = cfg.snapToEdge !== false;
62
+ this._snapToVertex = cfg.snapToVertex !== false;
63
+ this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
64
+
65
+ this._attachPlugin(angleMeasurementsPlugin, cfg);
66
+ }
67
+
68
+ _attachPlugin(angleMeasurementsPlugin) {
69
+
70
+ /**
71
+ * The {@link AngleMeasurementsPlugin} that owns this AngleMeasurementsTouchControl.
72
+ * @type {AngleMeasurementsPlugin}
73
+ */
74
+ this.angleMeasurementsPlugin = angleMeasurementsPlugin;
75
+
76
+ /**
77
+ * The {@link AngleMeasurementsPlugin} that owns this AngleMeasurementsTouchControl.
78
+ * @type {AngleMeasurementsPlugin}
79
+ */
80
+ this.plugin = angleMeasurementsPlugin;
81
+ }
82
+
83
+ /** Gets if this AngleMeasurementsTouchControl is currently active, where it is responding to input.
84
+ *
85
+ * @returns {Boolean}
86
+ */
87
+ get active() {
88
+ return this._active;
89
+ }
90
+
91
+ /**
92
+ * Sets whether snap-to-vertex is enabled for this AngleMeasurementsTouchControl.
93
+ * This is `true` by default.
94
+ * @param snapToVertex
95
+ */
96
+ set snapToVertex(snapToVertex) {
97
+ this._snapToVertex = snapToVertex;
98
+ }
99
+
100
+ /**
101
+ * Gets whether snap-to-vertex is enabled for this AngleMeasurementsTouchControl.
102
+ * This is `true` by default.
103
+ * @returns {*}
104
+ */
105
+ get snapToVertex() {
106
+ return this._snapToVertex;
107
+ }
108
+
109
+ /**
110
+ * Sets whether snap-to-edge is enabled for this AngleMeasurementsTouchControl.
111
+ * This is `true` by default.
112
+ * @param snapToEdge
113
+ */
114
+ set snapToEdge(snapToEdge) {
115
+ this._snapToEdge = snapToEdge;
116
+ }
117
+
118
+ /**
119
+ * Gets whether snap-to-edge is enabled for this AngleMeasurementsTouchControl.
120
+ * This is `true` by default.
121
+ * @returns {*}
122
+ */
123
+ get snapToEdge() {
124
+ return this._snapToEdge;
125
+ }
126
+
127
+ /**
128
+ * Activates this AngleMeasurementsTouchControl, ready to respond to input.
129
+ */
130
+ activate() {
131
+
132
+ if (this._active) {
133
+ return;
134
+ }
135
+
136
+ const plugin = this.plugin;
137
+ const scene = this.scene;
138
+ const canvas = scene.canvas.canvas;
139
+ const pointerLens = plugin.pointerLens;
140
+ const pointerWorldPos = math.vec3();
141
+
142
+ const touchTolerance = 20;
143
+
144
+ let longTouchTimeout = null;
145
+
146
+ this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
147
+
148
+ const touchStartCanvasPos = math.vec2();
149
+ const touchMoveCanvasPos = math.vec2();
150
+ const touchEndCanvasPos = math.vec2();
151
+
152
+ let touchId = null;
153
+
154
+ const disableCameraMouseControl = () => {
155
+ this.plugin.viewer.cameraControl.active = false;
156
+ }
157
+
158
+ const enableCameraMouseControl = () => {
159
+ this.plugin.viewer.cameraControl.active = true;
160
+ }
161
+
162
+ const cancel = () => {
163
+ if (longTouchTimeout) {
164
+ clearTimeout(longTouchTimeout);
165
+ longTouchTimeout = null;
166
+ }
167
+ if (this._currentAngleMeasurement) {
168
+ this._currentAngleMeasurement.destroy();
169
+ this._currentAngleMeasurement = null;
170
+ }
171
+ enableCameraMouseControl();
172
+ this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
173
+ }
174
+
175
+ canvas.addEventListener("touchstart", this._onCanvasTouchStart = (event) => {
176
+
177
+ const currentNumTouches = event.touches.length;
178
+
179
+ if (currentNumTouches !== 1) {
180
+ if (longTouchTimeout) {
181
+ clearTimeout(longTouchTimeout);
182
+ longTouchTimeout = null;
183
+ }
184
+ return;
185
+ }
186
+
187
+ const touch = event.touches[0];
188
+ const touchX = touch.clientX;
189
+ const touchY = touch.clientY;
190
+
191
+ touchStartCanvasPos.set([touchX, touchY]);
192
+ touchMoveCanvasPos.set([touchX, touchY]);
193
+
194
+ switch (this._touchState) {
195
+
196
+ case WAITING_FOR_ORIGIN_TOUCH_START:
197
+ if (currentNumTouches !== 1 && longTouchTimeout !== null) { // Two or more fingers down
198
+ cancel();
199
+ return;
200
+ }
201
+ const snapPickResult = scene.pick({
202
+ canvasPos: touchMoveCanvasPos,
203
+ snapToVertex: this._snapToVertex,
204
+ snapToEdge: this._snapToEdge
205
+ });
206
+ if (snapPickResult && snapPickResult.snapped) {
207
+ pointerWorldPos.set(snapPickResult.worldPos);
208
+ this.pointerCircle.start(snapPickResult.snappedCanvasPos);
209
+ } else {
210
+ const pickResult = scene.pick({
211
+ canvasPos: touchMoveCanvasPos,
212
+ pickSurface: true
213
+ })
214
+ if (pickResult && pickResult.worldPos) {
215
+ pointerWorldPos.set(pickResult.worldPos);
216
+ this.pointerCircle.start(pickResult.canvasPos);
217
+ } else {
218
+ return;
219
+ }
220
+ }
221
+ longTouchTimeout = setTimeout(() => {
222
+ if (currentNumTouches !== 1 ||
223
+ touchMoveCanvasPos[0] > touchStartCanvasPos[0] + touchTolerance ||
224
+ touchMoveCanvasPos[0] < touchStartCanvasPos[0] - touchTolerance ||
225
+ touchMoveCanvasPos[1] > touchStartCanvasPos[1] + touchTolerance ||
226
+ touchMoveCanvasPos[1] < touchStartCanvasPos[1] - touchTolerance) {
227
+ return; // Has moved
228
+ }
229
+ // Long touch
230
+ if (this.pointerLens) {
231
+ this.pointerLens.visible = true;
232
+ this.pointerLens.canvasPos = touchStartCanvasPos;
233
+ this.pointerLens.cursorPos = touchStartCanvasPos;
234
+ }
235
+ if (this.pointerLens) {
236
+ this.pointerLens.canvasPos = touchMoveCanvasPos;
237
+ this.pointerLens.snapped = false;
238
+ }
239
+ if (this.pointerLens) {
240
+ this.pointerLens.cursorPos = snapPickResult.canvasPos;
241
+ this.pointerLens.snapped = true;
242
+ }
243
+ // pointerWorldPos.set(snapPickResult.worldPos);
244
+ if (!this._currentAngleMeasurement) {
245
+ this._currentAngleMeasurement = plugin.createMeasurement({
246
+ id: math.createUUID(),
247
+ origin: {
248
+ worldPos: snapPickResult.worldPos
249
+ },
250
+ corner: {
251
+ worldPos: snapPickResult.worldPos
252
+ },
253
+ target: {
254
+ worldPos: snapPickResult.worldPos
255
+ }
256
+ });
257
+ this._currentAngleMeasurement.clickable = false;
258
+ this._currentAngleMeasurement.originVisible = true;
259
+ this._currentAngleMeasurement.originWireVisible = false;
260
+ this._currentAngleMeasurement.cornerVisible = false;
261
+ this._currentAngleMeasurement.cornerWireVisible = false;
262
+ this._currentAngleMeasurement.targetVisible = false;
263
+ this._currentAngleMeasurement.targetWireVisible = false;
264
+ this._currentAngleMeasurement.angleVisible = false
265
+ } else {
266
+ this._currentAngleMeasurement.origin.worldPos = pointerWorldPos;
267
+ }
268
+ this.angleMeasurementsPlugin.fire("measurementStart", this._currentAngleMeasurement);
269
+ // if (this.pointerLens) {
270
+ // this.pointerLens.cursorPos = pickResult.canvasPos;
271
+ // this.pointerLens.snapped = false;
272
+ // }
273
+ this._touchState = WAITING_FOR_ORIGIN_LONG_TOUCH_END;
274
+ // console.log("touchstart: this._touchState= WAITING_FOR_ORIGIN_TOUCH_START -> WAITING_FOR_ORIGIN_LONG_TOUCH_END")
275
+ disableCameraMouseControl();
276
+ }, this._longTouchTimeoutMs);
277
+ this._touchState = WAITING_FOR_ORIGIN_QUICK_TOUCH_END;
278
+ //console.log("touchstart: this._touchState= WAITING_FOR_ORIGIN_TOUCH_START -> WAITING_FOR_ORIGIN_QUICK_TOUCH_END")
279
+
280
+ touchId = touch.identifier;
281
+
282
+ break;
283
+
284
+ case WAITING_FOR_CORNER_TOUCH_START:
285
+
286
+ if (currentNumTouches !== 1 && longTouchTimeout !== null) { // Two or more fingers down
287
+ clearTimeout(longTouchTimeout);
288
+ longTouchTimeout = null;
289
+ return;
290
+ }
291
+ if (currentNumTouches === 1) { // One finger down
292
+ longTouchTimeout = setTimeout(() => {
293
+ longTouchTimeout = null;
294
+ if (currentNumTouches !== 1 ||
295
+ touchMoveCanvasPos[0] > touchStartCanvasPos[0] + touchTolerance ||
296
+ touchMoveCanvasPos[0] < touchStartCanvasPos[0] - touchTolerance ||
297
+ touchMoveCanvasPos[1] > touchStartCanvasPos[1] + touchTolerance ||
298
+ touchMoveCanvasPos[1] < touchStartCanvasPos[1] - touchTolerance) {
299
+ // Has moved
300
+ return;
301
+ }
302
+
303
+ // Long touch
304
+ if (this.pointerLens) {
305
+ this.pointerLens.visible = true;
306
+ this.pointerLens.canvasPos = touchStartCanvasPos;
307
+ this.pointerLens.snapped = false;
308
+ }
309
+
310
+ const snapPickResult = scene.pick({
311
+ canvasPos: touchMoveCanvasPos,
312
+ snapToVertex: this._snapToVertex,
313
+ snapToEdge: this._snapToEdge
314
+ });
315
+ if (snapPickResult && snapPickResult.snapped) {
316
+ if (this.pointerLens) {
317
+ this.pointerLens.cursorPos = snapPickResult.snappedCanvasPos;
318
+ this.pointerLens.snapped = true;
319
+ }
320
+ this.pointerCircle.start(snapPickResult.snappedCanvasPos);
321
+ pointerWorldPos.set(snapPickResult.worldPos);
322
+ this._currentAngleMeasurement.corner.worldPos = snapPickResult.worldPos;
323
+ this._currentAngleMeasurement.originVisible = true;
324
+ this._currentAngleMeasurement.originWireVisible = true;
325
+ this._currentAngleMeasurement.cornerVisible = true;
326
+ this._currentAngleMeasurement.cornerWireVisible = false;
327
+ this._currentAngleMeasurement.targetVisible = false;
328
+ this._currentAngleMeasurement.targetWireVisible = false;
329
+ this._currentAngleMeasurement.angleVisible = false
330
+ this.angleMeasurementsPlugin.fire("measurementStart", this._currentAngleMeasurement);
331
+ } else {
332
+ const pickResult = scene.pick({
333
+ canvasPos: touchMoveCanvasPos,
334
+ pickSurface: true
335
+ })
336
+ if (pickResult && pickResult.worldPos) {
337
+ if (this.pointerLens) {
338
+ this.pointerLens.cursorPos = pickResult.canvasPos;
339
+ this.pointerLens.snapped = false;
340
+ }
341
+ this.pointerCircle.start(pickResult.canvasPos);
342
+ pointerWorldPos.set(pickResult.worldPos);
343
+ this._currentAngleMeasurement.corner.worldPos = pickResult.worldPos;
344
+ this._currentAngleMeasurement.originVisible = true;
345
+ this._currentAngleMeasurement.originWireVisible = true;
346
+ this._currentAngleMeasurement.cornerVisible = true;
347
+ this._currentAngleMeasurement.cornerWireVisible = false;
348
+ this._currentAngleMeasurement.targetVisible = false;
349
+ this._currentAngleMeasurement.targetWireVisible = false;
350
+ this._currentAngleMeasurement.angleVisible = false
351
+ this.angleMeasurementsPlugin.fire("measurementStart", this._currentAngleMeasurement);
352
+ } else {
353
+ if (this.pointerLens) {
354
+ this.pointerLens.cursorPos = null;
355
+ this.pointerLens.snapped = false;
356
+
357
+ }
358
+ }
359
+ }
360
+ this._touchState = WAITING_FOR_CORNER_LONG_TOUCH_END;
361
+ // console.log("touchstart: this._touchState= WAITING_FOR_CORNER_TOUCH_START -> WAITING_FOR_CORNER_LONG_TOUCH_END")
362
+
363
+ disableCameraMouseControl();
364
+
365
+ }, this._longTouchTimeoutMs);
366
+
367
+ this._touchState = WAITING_FOR_CORNER_QUICK_TOUCH_END;
368
+ // console.log("touchstart: this._touchState= WAITING_FOR_CORNER_TOUCH_START -> WAITING_FOR_CORNER_QUICK_TOUCH_END")
369
+ }
370
+
371
+ touchId = touch.identifier;
372
+
373
+ break;
374
+
375
+ case WAITING_FOR_TARGET_TOUCH_START:
376
+
377
+ if (currentNumTouches !== 1 && longTouchTimeout !== null) { // Two or more fingers down
378
+ clearTimeout(longTouchTimeout);
379
+ longTouchTimeout = null;
380
+ return;
381
+ }
382
+ if (currentNumTouches === 1) { // One finger down
383
+ longTouchTimeout = setTimeout(() => {
384
+ longTouchTimeout = null;
385
+ if (currentNumTouches !== 1 ||
386
+ touchMoveCanvasPos[0] > touchStartCanvasPos[0] + touchTolerance ||
387
+ touchMoveCanvasPos[0] < touchStartCanvasPos[0] - touchTolerance ||
388
+ touchMoveCanvasPos[1] > touchStartCanvasPos[1] + touchTolerance ||
389
+ touchMoveCanvasPos[1] < touchStartCanvasPos[1] - touchTolerance) {
390
+ // Has moved
391
+ return;
392
+ }
393
+
394
+ // Long touch
395
+ if (this.pointerLens) {
396
+ this.pointerLens.visible = true;
397
+ this.pointerLens.canvasPos = touchStartCanvasPos;
398
+ this.pointerLens.snapped = false;
399
+ }
400
+
401
+ const snapPickResult = scene.pick({
402
+ canvasPos: touchMoveCanvasPos,
403
+ snapToVertex: this._snapToVertex,
404
+ snapToEdge: this._snapToEdge
405
+ });
406
+ if (snapPickResult && snapPickResult.snapped) {
407
+ if (this.pointerLens) {
408
+ this.pointerLens.cursorPos = snapPickResult.snappedCanvasPos;
409
+ this.pointerLens.snapped = true;
410
+ }
411
+ this.pointerCircle.start(snapPickResult.snappedCanvasPos);
412
+ pointerWorldPos.set(snapPickResult.worldPos);
413
+ this._currentAngleMeasurement.target.worldPos = snapPickResult.worldPos;
414
+ this._currentAngleMeasurement.originVisible = true;
415
+ this._currentAngleMeasurement.originWireVisible = true;
416
+ this._currentAngleMeasurement.cornerVisible = true;
417
+ this._currentAngleMeasurement.cornerWireVisible = true;
418
+ this._currentAngleMeasurement.targetVisible = true;
419
+ this._currentAngleMeasurement.targetWireVisible = true;
420
+ this._currentAngleMeasurement.angleVisible = true;
421
+ this.angleMeasurementsPlugin.fire("measurementStart", this._currentAngleMeasurement);
422
+ } else {
423
+ const pickResult = scene.pick({
424
+ canvasPos: touchMoveCanvasPos,
425
+ pickSurface: true
426
+ })
427
+ if (pickResult && pickResult.worldPos) {
428
+ if (this.pointerLens) {
429
+ this.pointerLens.cursorPos = pickResult.canvasPos;
430
+ this.pointerLens.snapped = false;
431
+ }
432
+ this.pointerCircle.start(pickResult.canvasPos);
433
+ pointerWorldPos.set(pickResult.worldPos);
434
+ this._currentAngleMeasurement.target.worldPos = pickResult.worldPos;
435
+ this._currentAngleMeasurement.originVisible = true;
436
+ this._currentAngleMeasurement.originWireVisible = true;
437
+ this._currentAngleMeasurement.cornerVisible = true;
438
+ this._currentAngleMeasurement.cornerWireVisible = true;
439
+ this._currentAngleMeasurement.targetVisible = true;
440
+ this._currentAngleMeasurement.targetWireVisible = true;
441
+ this._currentAngleMeasurement.angleVisible = true;
442
+ this.angleMeasurementsPlugin.fire("measurementStart", this._currentAngleMeasurement);
443
+ } else {
444
+ if (this.pointerLens) {
445
+ this.pointerLens.cursorPos = null;
446
+ this.pointerLens.snapped = false;
447
+
448
+ }
449
+ }
450
+ }
451
+ this._touchState = WAITING_FOR_TARGET_LONG_TOUCH_END;
452
+ // console.log("touchstart: this._touchState= WAITING_FOR_TARGET_TOUCH_START -> WAITING_FOR_TARGET_LONG_TOUCH_END")
453
+
454
+ disableCameraMouseControl();
455
+
456
+ }, this._longTouchTimeoutMs);
457
+
458
+ this._touchState = WAITING_FOR_TARGET_QUICK_TOUCH_END;
459
+ // console.log("touchstart: this._touchState= WAITING_FOR_TARGET_TOUCH_START -> WAITING_FOR_TARGET_QUICK_TOUCH_END")
460
+ }
461
+
462
+ touchId = touch.identifier;
463
+
464
+ break;
465
+
466
+
467
+ default:
468
+ if (longTouchTimeout !== null) {
469
+ clearTimeout(longTouchTimeout);
470
+ longTouchTimeout = null;
471
+ }
472
+ this._touchState = TOUCH_CANCELING;
473
+ // console.log("touchstart: this._touchState= default -> TOUCH_CANCELING")
474
+ return;
475
+ }
476
+
477
+ }, {passive: true});
478
+
479
+
480
+ canvas.addEventListener("touchmove", (event) => {
481
+
482
+ this.pointerCircle.stop();
483
+
484
+ const currentNumTouches = event.touches.length;
485
+
486
+ if (currentNumTouches !== 1 || event.changedTouches.length !== 1) {
487
+ if (longTouchTimeout) {
488
+ clearTimeout(longTouchTimeout);
489
+ longTouchTimeout = null;
490
+ }
491
+ return;
492
+ }
493
+
494
+ const touch = event.touches[0];
495
+ const touchX = touch.clientX;
496
+ const touchY = touch.clientY;
497
+
498
+ if (touch.identifier !== touchId) {
499
+ return;
500
+ }
501
+
502
+ touchMoveCanvasPos.set([touchX, touchY]);
503
+
504
+ let snapPickResult;
505
+ let pickResult;
506
+
507
+ switch (this._touchState) {
508
+
509
+ case WAITING_FOR_ORIGIN_LONG_TOUCH_END:
510
+ if (this.pointerLens) {
511
+ this.pointerLens.canvasPos = touchMoveCanvasPos;
512
+ }
513
+ snapPickResult = scene.pick({
514
+ canvasPos: touchMoveCanvasPos,
515
+ snapToVertex: this._snapToVertex,
516
+ snapToEdge: this._snapToEdge
517
+ });
518
+ if (snapPickResult && (snapPickResult.snapped)) {
519
+ if (this.pointerLens) {
520
+ this.pointerLens.snappedCanvasPos = snapPickResult.snappedCanvasPos;
521
+ this.pointerLens.snapped = true;
522
+ }
523
+ pointerWorldPos.set(snapPickResult.worldPos);
524
+ this._currentAngleMeasurement.origin.worldPos = snapPickResult.worldPos;
525
+ } else {
526
+ pickResult = scene.pick({
527
+ canvasPos: touchMoveCanvasPos,
528
+ pickSurface: true
529
+ })
530
+ if (pickResult && pickResult.worldPos) {
531
+ if (this.pointerLens) {
532
+ this.pointerLens.cursorPos = pickResult.canvasPos;
533
+ this.pointerLens.snapped = false;
534
+ }
535
+ pointerWorldPos.set(pickResult.worldPos);
536
+ this._currentAngleMeasurement.origin.worldPos = pickResult.worldPos;
537
+ } else {
538
+ if (this.pointerLens) {
539
+ this.pointerLens.cursorPos = null;
540
+ this.pointerLens.snapped = false;
541
+ }
542
+ }
543
+ }
544
+ this._touchState = WAITING_FOR_ORIGIN_LONG_TOUCH_END;
545
+ // console.log("touchmove: this._touchState= WAITING_FOR_ORIGIN_LONG_TOUCH_END -> WAITING_FOR_ORIGIN_LONG_TOUCH_END")
546
+ break;
547
+
548
+ case WAITING_FOR_CORNER_LONG_TOUCH_END:
549
+ if (currentNumTouches !== 1 && longTouchTimeout !== null) { // Two or more fingers down
550
+ clearTimeout(longTouchTimeout);
551
+ longTouchTimeout = null;
552
+ if (this.pointerLens) {
553
+ this.pointerLens.visible = false;
554
+ }
555
+ this._touchState = TOUCH_CANCELING;
556
+ // console.log("touchmove: this._touchState= QUICK_TOUCH_FINDING_CORNER -> TOUCH_CANCELING")
557
+ return;
558
+ }
559
+ if (this.pointerLens) {
560
+ this.pointerLens.canvasPos = touchMoveCanvasPos;
561
+ }
562
+ snapPickResult = scene.pick({
563
+ canvasPos: touchMoveCanvasPos,
564
+ snapToVertex: this._snapToVertex,
565
+ snapToEdge: this._snapToEdge
566
+ });
567
+ if (snapPickResult && snapPickResult.worldPos) {
568
+ if (this.pointerLens) {
569
+ this.pointerLens.cursorPos = snapPickResult.snappedCanvasPos;
570
+ this.pointerLens.snapped = true;
571
+ }
572
+ this._currentAngleMeasurement.corner.worldPos = snapPickResult.worldPos;
573
+ this._currentAngleMeasurement.originVisible = true;
574
+ this._currentAngleMeasurement.originWireVisible = true;
575
+ this._currentAngleMeasurement.cornerVisible = true;
576
+ this._currentAngleMeasurement.cornerWireVisible = false;
577
+ this._currentAngleMeasurement.targetVisible = false;
578
+ this._currentAngleMeasurement.targetWireVisible = false;
579
+ this._currentAngleMeasurement.angleVisible = false;
580
+ } else {
581
+ pickResult = scene.pick({
582
+ canvasPos: touchMoveCanvasPos,
583
+ pickSurface: true
584
+ })
585
+ if (pickResult && pickResult.worldPos) {
586
+ if (this.pointerLens) {
587
+ this.pointerLens.cursorPos = pickResult.canvasPos;
588
+ this.pointerLens.snapped = false;
589
+ }
590
+ this._currentAngleMeasurement.corner.worldPos = pickResult.worldPos;
591
+ this._currentAngleMeasurement.originVisible = true;
592
+ this._currentAngleMeasurement.originWireVisible = true;
593
+ this._currentAngleMeasurement.cornerVisible = true;
594
+ this._currentAngleMeasurement.cornerWireVisible = false;
595
+ this._currentAngleMeasurement.targetVisible = false;
596
+ this._currentAngleMeasurement.targetWireVisible = false;
597
+ this._currentAngleMeasurement.angleVisible = false;
598
+ }
599
+ }
600
+ this._touchState = WAITING_FOR_CORNER_LONG_TOUCH_END;
601
+ break;
602
+
603
+
604
+ case WAITING_FOR_TARGET_LONG_TOUCH_END:
605
+ if (currentNumTouches !== 1 && longTouchTimeout !== null) { // Two or more fingers down
606
+ clearTimeout(longTouchTimeout);
607
+ longTouchTimeout = null;
608
+ if (this.pointerLens) {
609
+ this.pointerLens.visible = false;
610
+ }
611
+ this._touchState = TOUCH_CANCELING;
612
+ // console.log("touchmove: this._touchState= QUICK_TOUCH_FINDING_TARGET -> TOUCH_CANCELING")
613
+ return;
614
+ }
615
+ if (this.pointerLens) {
616
+ this.pointerLens.canvasPos = touchMoveCanvasPos;
617
+ }
618
+ snapPickResult = scene.pick({
619
+ canvasPos: touchMoveCanvasPos,
620
+ snapToVertex: this._snapToVertex,
621
+ snapToEdge: this._snapToEdge
622
+ });
623
+ if (snapPickResult && snapPickResult.worldPos) {
624
+ if (this.pointerLens) {
625
+ this.pointerLens.cursorPos = snapPickResult.snappedCanvasPos;
626
+ this.pointerLens.snapped = true;
627
+ }
628
+ this._currentAngleMeasurement.target.worldPos = snapPickResult.worldPos;
629
+ this._currentAngleMeasurement.originVisible = true;
630
+ this._currentAngleMeasurement.originWireVisible = true;
631
+ this._currentAngleMeasurement.cornerVisible = true;
632
+ this._currentAngleMeasurement.cornerWireVisible = true;
633
+ this._currentAngleMeasurement.targetVisible = true;
634
+ this._currentAngleMeasurement.targetWireVisible = true;
635
+ this._currentAngleMeasurement.angleVisible = true;
636
+ } else {
637
+ pickResult = scene.pick({
638
+ canvasPos: touchMoveCanvasPos,
639
+ pickSurface: true
640
+ })
641
+ if (pickResult && pickResult.worldPos) {
642
+ if (this.pointerLens) {
643
+ this.pointerLens.cursorPos = pickResult.canvasPos;
644
+ this.pointerLens.snapped = false;
645
+ }
646
+ this._currentAngleMeasurement.target.worldPos = pickResult.worldPos;
647
+ this._currentAngleMeasurement.originVisible = true;
648
+ this._currentAngleMeasurement.originWireVisible = true;
649
+ this._currentAngleMeasurement.cornerVisible = true;
650
+ this._currentAngleMeasurement.cornerWireVisible = true;
651
+ this._currentAngleMeasurement.targetVisible = true;
652
+ this._currentAngleMeasurement.targetWireVisible = true;
653
+ this._currentAngleMeasurement.angleVisible = true;
654
+ }
655
+ }
656
+ this._touchState = WAITING_FOR_TARGET_LONG_TOUCH_END;
657
+ break;
658
+
659
+ default:
660
+ break;
661
+ }
662
+ }, {passive: true});
663
+
664
+ canvas.addEventListener("touchend", this._onCanvasTouchEnd = (event) => {
665
+
666
+ this.pointerCircle.stop();
667
+
668
+ const numChangedTouches = event.changedTouches.length;
669
+
670
+ if (numChangedTouches !== 1) {
671
+ return;
672
+ }
673
+
674
+ const touch = event.changedTouches[0];
675
+ const touchX = touch.clientX;
676
+ const touchY = touch.clientY;
677
+
678
+ if (touch.identifier !== touchId) {
679
+ return;
680
+ }
681
+
682
+ if (longTouchTimeout) {
683
+ clearTimeout(longTouchTimeout);
684
+ longTouchTimeout = null;
685
+ }
686
+
687
+ touchEndCanvasPos.set([touchX, touchY]);
688
+
689
+ switch (this._touchState) {
690
+
691
+ case WAITING_FOR_ORIGIN_QUICK_TOUCH_END: {
692
+ if (numChangedTouches !== 1 ||
693
+ touchX > touchStartCanvasPos[0] + touchTolerance ||
694
+ touchX < touchStartCanvasPos[0] - touchTolerance ||
695
+ touchY > touchStartCanvasPos[1] + touchTolerance ||
696
+ touchY < touchStartCanvasPos[1] - touchTolerance) {
697
+ this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
698
+ return;
699
+ }
700
+ const pickResult = scene.pick({
701
+ canvasPos: touchMoveCanvasPos,
702
+ pickSurface: true
703
+ });
704
+ if (pickResult && pickResult.worldPos) {
705
+ this._currentAngleMeasurement = plugin.createMeasurement({
706
+ id: math.createUUID(),
707
+ origin: {
708
+ worldPos: pickResult.worldPos
709
+ },
710
+ corner: {
711
+ worldPos: pickResult.worldPos
712
+ },
713
+ target: {
714
+ worldPos: pickResult.worldPos
715
+ }
716
+ });
717
+ this._currentAngleMeasurement.clickable = false;
718
+ this._currentAngleMeasurement.originVisible = true;
719
+ this._currentAngleMeasurement.originWireVisible = false;
720
+ this._currentAngleMeasurement.cornerVisible = false;
721
+ this._currentAngleMeasurement.cornerWireVisible = false;
722
+ this._currentAngleMeasurement.targetVisible = false;
723
+ this._currentAngleMeasurement.targetWireVisible = false;
724
+ this._currentAngleMeasurement.angleVisible = false
725
+ this._touchState = WAITING_FOR_CORNER_TOUCH_START;
726
+ // console.log("touchend: this._touchState= WAITING_FOR_ORIGIN_QUICK_TOUCH_END -> WAITING_FOR_CORNER_TOUCH_START")
727
+ } else {
728
+ if (this._currentAngleMeasurement) {
729
+ this._currentAngleMeasurement.destroy();
730
+ this._currentAngleMeasurement = null;
731
+ }
732
+ this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
733
+ // console.log("touchend: this._touchState= WAITING_FOR_ORIGIN_QUICK_TOUCH_END -> WAITING_FOR_ORIGIN_TOUCH_START")
734
+ }
735
+ }
736
+ enableCameraMouseControl();
737
+ break;
738
+
739
+ case WAITING_FOR_ORIGIN_LONG_TOUCH_END:
740
+ if (this.pointerLens) {
741
+ this.pointerLens.visible = false;
742
+ }
743
+ if (!this._currentAngleMeasurement) {
744
+ if (this.pointerLens) {
745
+ this.pointerLens.snapped = false;
746
+ this.pointerLens.visible = false;
747
+ }
748
+ this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
749
+ // console.log("touchend: this._touchState= WAITING_FOR_ORIGIN_LONG_TOUCH_END (no measurement) -> WAITING_FOR_ORIGIN_TOUCH_START")
750
+ } else {
751
+ this._touchState = WAITING_FOR_CORNER_TOUCH_START;
752
+ // console.log("touchend: this._touchState= WAITING_FOR_ORIGIN_LONG_TOUCH_END (picked, begin measurement) -> WAITING_FOR_CORNER_TOUCH_START")
753
+ }
754
+ enableCameraMouseControl();
755
+ break;
756
+
757
+ case WAITING_FOR_CORNER_QUICK_TOUCH_END: {
758
+ if (numChangedTouches !== 1 ||
759
+ touchX > touchStartCanvasPos[0] + touchTolerance ||
760
+ touchX < touchStartCanvasPos[0] - touchTolerance ||
761
+ touchY > touchStartCanvasPos[1] + touchTolerance ||
762
+ touchY < touchStartCanvasPos[1] - touchTolerance) {
763
+ this._touchState = WAITING_FOR_CORNER_TOUCH_START;
764
+ return;
765
+ }
766
+ const pickResult = scene.pick({
767
+ canvasPos: touchMoveCanvasPos,
768
+ pickSurface: true
769
+ });
770
+ if (pickResult && pickResult.worldPos) {
771
+ this._currentAngleMeasurement.corner.worldPos = pickResult.worldPos;
772
+ this._currentAngleMeasurement.originVisible = true;
773
+ this._currentAngleMeasurement.originWireVisible = true;
774
+ this._currentAngleMeasurement.cornerVisible = true;
775
+ this._currentAngleMeasurement.cornerWireVisible = false;
776
+ this._currentAngleMeasurement.targetVisible = false;
777
+ this._currentAngleMeasurement.targetWireVisible = false;
778
+ this._currentAngleMeasurement.angleVisible = false;
779
+ this._touchState = WAITING_FOR_TARGET_TOUCH_START;
780
+ // console.log("touchend: this._touchState= WAITING_FOR_CORNER_TOUCH_START -> WAITING_FOR_ORIGIN_TOUCH_START")
781
+ } else {
782
+ if (this._currentAngleMeasurement) {
783
+ this._currentAngleMeasurement.destroy();
784
+ this._currentAngleMeasurement = null;
785
+ }
786
+ this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
787
+ // console.log("touchend: this._touchState= WAITING_FOR_CORNER_TOUCH_START -> WAITING_FOR_ORIGIN_TOUCH_START")
788
+ }
789
+
790
+ }
791
+ enableCameraMouseControl();
792
+ break;
793
+
794
+ case WAITING_FOR_CORNER_LONG_TOUCH_END:
795
+ if (this.pointerLens) {
796
+ this.pointerLens.visible = false;
797
+ }
798
+ this._touchState = WAITING_FOR_TARGET_TOUCH_START;
799
+ // console.log("touchend: this._touchState= WAITING_FOR_CORNER_LONG_TOUCH_END -> WAITING_FOR_ORIGIN_TOUCH_START")
800
+ enableCameraMouseControl();
801
+ break;
802
+
803
+ case WAITING_FOR_TARGET_QUICK_TOUCH_END: {
804
+ if (numChangedTouches !== 1 ||
805
+ touchX > touchStartCanvasPos[0] + touchTolerance ||
806
+ touchX < touchStartCanvasPos[0] - touchTolerance ||
807
+ touchY > touchStartCanvasPos[1] + touchTolerance ||
808
+ touchY < touchStartCanvasPos[1] - touchTolerance) {
809
+ this._touchState = WAITING_FOR_TARGET_TOUCH_START;
810
+ return;
811
+ }
812
+ const pickResult = scene.pick({
813
+ canvasPos: touchMoveCanvasPos,
814
+ pickSurface: true
815
+ });
816
+ if (pickResult && pickResult.worldPos) {
817
+ this._currentAngleMeasurement.target.worldPos = pickResult.worldPos;
818
+ this._currentAngleMeasurement.originVisible = true;
819
+ this._currentAngleMeasurement.originWireVisible = true;
820
+ this._currentAngleMeasurement.cornerVisible = true;
821
+ this._currentAngleMeasurement.cornerWireVisible = true;
822
+ this._currentAngleMeasurement.targetVisible = true;
823
+ this._currentAngleMeasurement.targetWireVisible = true;
824
+ this._currentAngleMeasurement.angleVisible = true;
825
+ this.angleMeasurementsPlugin.fire("measurementEnd", this._currentAngleMeasurement);
826
+ this._currentAngleMeasurement = null;
827
+ } else {
828
+ if (this._currentAngleMeasurement) {
829
+ this._currentAngleMeasurement.destroy();
830
+ this._currentAngleMeasurement = null;
831
+ }
832
+ }
833
+ this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
834
+ // console.log("touchend: this._touchState= WAITING_FOR_TARGET_TOUCH_START -> WAITING_FOR_ORIGIN_TOUCH_START")
835
+ }
836
+ enableCameraMouseControl();
837
+ break;
838
+
839
+ case WAITING_FOR_TARGET_LONG_TOUCH_END:
840
+ if (this.pointerLens) {
841
+ this.pointerLens.visible = false;
842
+ }
843
+ if (!this._currentAngleMeasurement || !this._currentAngleMeasurement.targetVisible) {
844
+ if (this._currentAngleMeasurement) {
845
+ this._currentAngleMeasurement.destroy();
846
+ this._currentAngleMeasurement = null;
847
+ }
848
+ this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
849
+ // console.log("touchend: this._touchState= WAITING_FOR_TARGET_LONG_TOUCH_END (no target found) -> WAITING_FOR_ORIGIN_TOUCH_START")
850
+ } else {
851
+ this._currentAngleMeasurement.clickable = true;
852
+ this.angleMeasurementsPlugin.fire("measurementEnd", this._currentAngleMeasurement);
853
+ this._currentAngleMeasurement = null;
854
+ this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
855
+ // console.log("touchend: this._touchState= WAITING_FOR_TARGET_LONG_TOUCH_END -> WAITING_FOR_ORIGIN_TOUCH_START")
856
+ }
857
+ enableCameraMouseControl();
858
+ break;
859
+ }
860
+
861
+ }, {passive: true});
862
+
863
+ this._active = true;
864
+ }
865
+
866
+ /**
867
+ * Deactivates this AngleMeasurementsTouchControl, making it unresponsive to input.
868
+ *
869
+ * Destroys any {@link AngleMeasurement} under construction.
870
+ */
871
+ deactivate() {
872
+ if (!this._active) {
873
+ return;
874
+ }
875
+ if (this.plugin.pointerLens) {
876
+ this.plugin.pointerLens.visible = false;
877
+ }
878
+ this.reset();
879
+ const canvas = this.plugin.viewer.scene.canvas.canvas;
880
+ canvas.removeEventListener("touchstart", this._onCanvasTouchStart);
881
+ canvas.removeEventListener("touchend", this._onCanvasTouchEnd);
882
+ if (this._currentAngleMeasurement) {
883
+ this.angleMeasurementsPlugin.fire("measurementCancel", this._currentAngleMeasurement);
884
+ this._currentAngleMeasurement.destroy();
885
+ this._currentAngleMeasurement = null;
886
+ }
887
+ this._active = false;
888
+ this.plugin.viewer.cameraControl.active = true;
889
+ }
890
+
891
+ /**
892
+ * Resets this AngleMeasurementsTouchControl.
893
+ *
894
+ * Destroys any {@link AngleMeasurement} under construction.
895
+ *
896
+ * Does nothing if the AngleMeasurementsTouchControl is not active.
897
+ */
898
+ reset() {
899
+ if (!this._active) {
900
+ return;
901
+ }
902
+ if (this._currentAngleMeasurement) {
903
+ this.angleMeasurementsPlugin.fire("measurementCancel", this._currentAngleMeasurement);
904
+ this._currentAngleMeasurement.destroy();
905
+ this._currentAngleMeasurement = null;
906
+ }
907
+ }
908
+
909
+ /**
910
+ * Destroys this AngleMeasurementsTouchControl.
911
+ */
912
+ destroy() {
913
+ this.deactivate();
914
+ super.destroy();
915
+ }
916
+ }