@xeokit/xeokit-sdk 2.6.23 → 2.6.25

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.
@@ -9529,6 +9529,239 @@ class Plugin {
9529
9529
  }
9530
9530
  }
9531
9531
 
9532
+ const os = {
9533
+ isIphoneSafari() {
9534
+ const userAgent = window.navigator.userAgent;
9535
+ const isIphone = /iPhone/i.test(userAgent);
9536
+ const isSafari = /Safari/i.test(userAgent) && !/Chrome/i.test(userAgent);
9537
+
9538
+ return isIphone && isSafari;
9539
+ }
9540
+ };
9541
+
9542
+ /** @private */
9543
+ class Dot {
9544
+
9545
+ constructor(parentElement, cfg = {}) {
9546
+
9547
+ this._highlightClass = "viewer-ruler-dot-highlighted";
9548
+
9549
+ this._x = 0;
9550
+ this._y = 0;
9551
+
9552
+ this._dot = document.createElement('div');
9553
+ this._dot.className += this._dot.className ? ' viewer-ruler-dot' : 'viewer-ruler-dot';
9554
+
9555
+ this._dotClickable = document.createElement('div');
9556
+ this._dotClickable.className += this._dotClickable.className ? ' viewer-ruler-dot-clickable' : 'viewer-ruler-dot-clickable';
9557
+
9558
+ this._visible = !!cfg.visible;
9559
+ this._culled = false;
9560
+
9561
+ var dot = this._dot;
9562
+ var dotStyle = dot.style;
9563
+ dotStyle["border-radius"] = 25 + "px";
9564
+ dotStyle.border = "solid 2px white";
9565
+ dotStyle.background = "lightgreen";
9566
+ dotStyle.position = "absolute";
9567
+ dotStyle["z-index"] = cfg.zIndex === undefined ? "40000005" : cfg.zIndex ;
9568
+ dotStyle.width = 8 + "px";
9569
+ dotStyle.height = 8 + "px";
9570
+ dotStyle.visibility = cfg.visible !== false ? "visible" : "hidden";
9571
+ dotStyle.top = 0 + "px";
9572
+ dotStyle.left = 0 + "px";
9573
+ dotStyle["box-shadow"] = "0 2px 5px 0 #182A3D;";
9574
+ dotStyle["opacity"] = 1.0;
9575
+ dotStyle["pointer-events"] = "none";
9576
+ if (cfg.onContextMenu) ;
9577
+ parentElement.appendChild(dot);
9578
+
9579
+ var dotClickable = this._dotClickable;
9580
+ var dotClickableStyle = dotClickable.style;
9581
+ dotClickableStyle["border-radius"] = 35 + "px";
9582
+ dotClickableStyle.border = "solid 10px white";
9583
+ dotClickableStyle.position = "absolute";
9584
+ dotClickableStyle["z-index"] = cfg.zIndex === undefined ? "40000007" : (cfg.zIndex + 1);
9585
+ dotClickableStyle.width = 8 + "px";
9586
+ dotClickableStyle.height = 8 + "px";
9587
+ dotClickableStyle.visibility = "visible";
9588
+ dotClickableStyle.top = 0 + "px";
9589
+ dotClickableStyle.left = 0 + "px";
9590
+ dotClickableStyle["opacity"] = 0.0;
9591
+ dotClickableStyle["pointer-events"] = "none";
9592
+ if (cfg.onContextMenu) ;
9593
+ parentElement.appendChild(dotClickable);
9594
+
9595
+ dotClickable.addEventListener('click', (event) => {
9596
+ parentElement.dispatchEvent(new MouseEvent('mouseover', event));
9597
+ });
9598
+
9599
+ if (cfg.onMouseOver) {
9600
+ dotClickable.addEventListener('mouseover', (event) => {
9601
+ cfg.onMouseOver(event, this);
9602
+ parentElement.dispatchEvent(new MouseEvent('mouseover', event));
9603
+ });
9604
+ }
9605
+
9606
+ if (cfg.onMouseLeave) {
9607
+ dotClickable.addEventListener('mouseleave', (event) => {
9608
+ cfg.onMouseLeave(event, this);
9609
+ });
9610
+ }
9611
+
9612
+ if (cfg.onMouseWheel) {
9613
+ dotClickable.addEventListener('wheel', (event) => {
9614
+ cfg.onMouseWheel(event, this);
9615
+ });
9616
+ }
9617
+
9618
+ if (cfg.onMouseDown) {
9619
+ dotClickable.addEventListener('mousedown', (event) => {
9620
+ cfg.onMouseDown(event, this);
9621
+ });
9622
+ }
9623
+
9624
+ if (cfg.onMouseUp) {
9625
+ dotClickable.addEventListener('mouseup', (event) => {
9626
+ cfg.onMouseUp(event, this);
9627
+ });
9628
+ }
9629
+
9630
+ if (cfg.onMouseMove) {
9631
+ dotClickable.addEventListener('mousemove', (event) => {
9632
+ cfg.onMouseMove(event, this);
9633
+ });
9634
+ }
9635
+
9636
+ if (cfg.onTouchstart) {
9637
+ dotClickable.addEventListener('touchstart', (event) => {
9638
+ cfg.onTouchstart(event, this);
9639
+ });
9640
+ }
9641
+
9642
+ if (cfg.onTouchmove) {
9643
+ dotClickable.addEventListener('touchmove', (event) => {
9644
+ cfg.onTouchmove(event, this);
9645
+ });
9646
+ }
9647
+
9648
+ if (cfg.onTouchend) {
9649
+ dotClickable.addEventListener('touchend', (event) => {
9650
+ cfg.onTouchend(event, this);
9651
+ });
9652
+ }
9653
+
9654
+ if (cfg.onContextMenu) {
9655
+ if(os.isIphoneSafari()){
9656
+ dotClickable.addEventListener('touchstart', (event) => {
9657
+ event.preventDefault();
9658
+ if(this._timeout){
9659
+ clearTimeout(this._timeout);
9660
+ this._timeout = null;
9661
+ }
9662
+ this._timeout = setTimeout(() => {
9663
+ event.clientX = event.touches[0].clientX;
9664
+ event.clientY = event.touches[0].clientY;
9665
+ cfg.onContextMenu(event, this);
9666
+ clearTimeout(this._timeout);
9667
+ this._timeout = null;
9668
+ }, 500);
9669
+ });
9670
+
9671
+ dotClickable.addEventListener('touchend', (event) => {
9672
+ event.preventDefault();
9673
+ //stops short touches from calling the timeout
9674
+ if(this._timeout) {
9675
+ clearTimeout(this._timeout);
9676
+ this._timeout = null;
9677
+ }
9678
+ } );
9679
+
9680
+ }
9681
+ else {
9682
+ dotClickable.addEventListener('contextmenu', (event) => {
9683
+ console.log(event);
9684
+ cfg.onContextMenu(event, this);
9685
+ event.preventDefault();
9686
+ event.stopPropagation();
9687
+ console.log("Label context menu");
9688
+ });
9689
+ }
9690
+
9691
+ }
9692
+
9693
+ this.setPos(cfg.x || 0, cfg.y || 0);
9694
+ this.setFillColor(cfg.fillColor);
9695
+ this.setBorderColor(cfg.borderColor);
9696
+ }
9697
+
9698
+ setPos(x, y) {
9699
+ this._x = x;
9700
+ this._y = y;
9701
+ var dotStyle = this._dot.style;
9702
+ dotStyle["left"] = (Math.round(x) - 4) + 'px';
9703
+ dotStyle["top"] = (Math.round(y) - 4) + 'px';
9704
+
9705
+ var dotClickableStyle = this._dotClickable.style;
9706
+ dotClickableStyle["left"] = (Math.round(x) - 9) + 'px';
9707
+ dotClickableStyle["top"] = (Math.round(y) - 9) + 'px';
9708
+ }
9709
+
9710
+ setFillColor(color) {
9711
+ this._dot.style.background = color || "lightgreen";
9712
+ }
9713
+
9714
+ setBorderColor(color) {
9715
+ this._dot.style.border = "solid 2px" + (color || "black");
9716
+ }
9717
+
9718
+ setOpacity(opacity) {
9719
+ this._dot.style.opacity = opacity;
9720
+ }
9721
+
9722
+ setVisible(visible) {
9723
+ if (this._visible === visible) {
9724
+ return;
9725
+ }
9726
+ this._visible = !!visible;
9727
+ this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden";
9728
+ }
9729
+
9730
+ setCulled(culled) {
9731
+ if (this._culled === culled) {
9732
+ return;
9733
+ }
9734
+ this._culled = !!culled;
9735
+ this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden";
9736
+ }
9737
+
9738
+ setClickable(clickable) {
9739
+ this._dotClickable.style["pointer-events"] = (clickable) ? "all" : "none";
9740
+ }
9741
+
9742
+ setHighlighted(highlighted) {
9743
+ if (this._highlighted === highlighted) {
9744
+ return;
9745
+ }
9746
+ this._highlighted = !!highlighted;
9747
+ if (this._highlighted) {
9748
+ this._dot.classList.add(this._highlightClass);
9749
+ } else {
9750
+ this._dot.classList.remove(this._highlightClass);
9751
+ }
9752
+ }
9753
+
9754
+ destroy() {
9755
+ this.setVisible(false);
9756
+ if (this._dot.parentElement) {
9757
+ this._dot.parentElement.removeChild(this._dot);
9758
+ }
9759
+ if (this._dotClickable.parentElement) {
9760
+ this._dotClickable.parentElement.removeChild(this._dotClickable);
9761
+ }
9762
+ }
9763
+ }
9764
+
9532
9765
  const tempVec3a$L = math.vec3();
9533
9766
 
9534
9767
  /**
@@ -10589,11 +10822,17 @@ class Marker extends Component {
10589
10822
  return;
10590
10823
  }
10591
10824
  if (this._onEntityDestroyed !== null) {
10592
- this._entity.model.off(this._onEntityDestroyed);
10825
+ if (this._entity.model) {
10826
+ this._entity.model.off(this._onEntityDestroyed);
10827
+ } else {
10828
+ this._entity.off(this._onEntityDestroyed);
10829
+ }
10593
10830
  this._onEntityDestroyed = null;
10594
10831
  }
10595
10832
  if (this._onEntityModelDestroyed !== null) {
10596
- this._entity.model.off(this._onEntityModelDestroyed);
10833
+ if (this._entity.model) {
10834
+ this._entity.model.off(this._onEntityModelDestroyed);
10835
+ }
10597
10836
  this._onEntityModelDestroyed = null;
10598
10837
  }
10599
10838
  }
@@ -10605,7 +10844,7 @@ class Marker extends Component {
10605
10844
  this._onEntityModelDestroyed = null;
10606
10845
  });
10607
10846
  } else {
10608
- this._onEntityDestroyed = this._entity.model.on("destroyed", () => {
10847
+ this._onEntityDestroyed = this._entity.on("destroyed", () => {
10609
10848
  this._entity = null;
10610
10849
  this._onEntityDestroyed = null;
10611
10850
  });
@@ -10774,15 +11013,286 @@ class Marker extends Component {
10774
11013
  }
10775
11014
  }
10776
11015
 
10777
- const os = {
10778
- isIphoneSafari() {
10779
- const userAgent = window.navigator.userAgent;
10780
- const isIphone = /iPhone/i.test(userAgent);
10781
- const isSafari = /Safari/i.test(userAgent) && !/Chrome/i.test(userAgent);
11016
+ const nop = () => { };
10782
11017
 
10783
- return isIphone && isSafari;
11018
+ function transformToNode(from, to, vec) {
11019
+ const fromRec = from.getBoundingClientRect();
11020
+ const toRec = to.getBoundingClientRect();
11021
+ vec[0] += fromRec.left - toRec.left;
11022
+ vec[1] += fromRec.top - toRec.top;
11023
+ }
11024
+ class Dot3D extends Marker {
11025
+ constructor(scene, markerCfg, parentElement, cfg = {}) {
11026
+ super(scene, markerCfg);
11027
+
11028
+ const handler = (cfgEvent, componentEvent) => {
11029
+ return event => {
11030
+ if (cfgEvent) {
11031
+ cfgEvent(event);
11032
+ }
11033
+ this.fire(componentEvent, event, true);
11034
+ };
11035
+ };
11036
+ this._dot = new Dot(parentElement, {
11037
+ fillColor: cfg.fillColor,
11038
+ zIndex: cfg.zIndex,
11039
+ onMouseOver: handler(cfg.onMouseOver, "mouseover"),
11040
+ onMouseLeave: handler(cfg.onMouseLeave, "mouseleave"),
11041
+ onMouseWheel: handler(cfg.onMouseWheel, "wheel"),
11042
+ onMouseDown: handler(cfg.onMouseDown, "mousedown"),
11043
+ onMouseUp: handler(cfg.onMouseUp, "mouseup"),
11044
+ onMouseMove: handler(cfg.onMouseMove, "mousemove"),
11045
+ onTouchstart: handler(cfg.onTouchstart, "touchstart"),
11046
+ onTouchmove: handler(cfg.onTouchmove, "touchmove"),
11047
+ onTouchend: handler(cfg.onTouchend, "touchend"),
11048
+ onContextMenu: handler(cfg.onContextMenu, "contextmenu")
11049
+ });
11050
+
11051
+ const updateDotPos = () => {
11052
+ const pos = this.canvasPos.slice();
11053
+ transformToNode(scene.canvas.canvas, parentElement, pos);
11054
+ this._dot.setPos(pos[0], pos[1]);
11055
+ };
11056
+
11057
+ this.on("worldPos", updateDotPos);
11058
+
11059
+ const onViewMatrix = scene.camera.on("viewMatrix", updateDotPos);
11060
+ const onProjMatrix = scene.camera.on("projMatrix", updateDotPos);
11061
+ this._cleanup = () => {
11062
+ scene.camera.off(onViewMatrix);
11063
+ scene.camera.off(onProjMatrix);
11064
+ this._dot.destroy();
11065
+ };
10784
11066
  }
10785
- };
11067
+
11068
+ setClickable(value) {
11069
+ this._dot.setClickable(value);
11070
+ }
11071
+
11072
+ setCulled(value) {
11073
+ this._dot.setCulled(value);
11074
+ }
11075
+
11076
+ setFillColor(value) {
11077
+ this._dot.setFillColor(value);
11078
+ }
11079
+
11080
+ setHighlighted(value) {
11081
+ this._dot.setHighlighted(value);
11082
+ }
11083
+
11084
+ setOpacity(value) {
11085
+ this._dot.setOpacity(value);
11086
+ }
11087
+
11088
+ setVisible(value) {
11089
+ this._dot.setVisible(value);
11090
+ }
11091
+
11092
+ destroy() {
11093
+ this._cleanup();
11094
+ super.destroy();
11095
+ }
11096
+
11097
+ }
11098
+
11099
+ function activateDraggableDot(dot, cfg) {
11100
+ const extractCFG = function(propName, defaultValue) {
11101
+ if (propName in cfg) {
11102
+ return cfg[propName];
11103
+ } else if (defaultValue !== undefined) {
11104
+ return defaultValue;
11105
+ } else {
11106
+ throw "config missing: " + propName;
11107
+ }
11108
+ };
11109
+
11110
+ const viewer = extractCFG("viewer");
11111
+ const ray2WorldPos = extractCFG("ray2WorldPos");
11112
+ const handleMouseEvents = extractCFG("handleMouseEvents", false);
11113
+ const handleTouchEvents = extractCFG("handleTouchEvents", false);
11114
+ const onStart = extractCFG("onStart", nop);
11115
+ const onMove = extractCFG("onMove", nop);
11116
+ const onEnd = extractCFG("onEnd", nop);
11117
+
11118
+ const scene = viewer.scene;
11119
+ const canvas = scene.canvas.canvas;
11120
+
11121
+ const pickWorldPos = canvasPos => {
11122
+ const origin = math.vec3();
11123
+ const direction = math.vec3();
11124
+ math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
11125
+ return ray2WorldPos(origin, direction, canvasPos);
11126
+ };
11127
+
11128
+ const onChange = event => {
11129
+ const canvasPos = math.vec2([ event.clientX, event.clientY ]);
11130
+ transformToNode(canvas.ownerDocument.body, canvas, canvasPos);
11131
+ onMove(canvasPos, pickWorldPos(canvasPos));
11132
+ };
11133
+
11134
+ let currentDrag = null;
11135
+
11136
+ const onDragMove = function(event) {
11137
+ const e = currentDrag.matchesEvent(event);
11138
+ if (e)
11139
+ {
11140
+ onChange(e);
11141
+ }
11142
+ };
11143
+
11144
+ const onDragEnd = function(event) {
11145
+ const e = currentDrag.matchesEvent(event);
11146
+ if (e)
11147
+ {
11148
+ dot.setOpacity(idleOpacity);
11149
+ currentDrag.cleanup();
11150
+ onChange(e);
11151
+ onEnd();
11152
+ }
11153
+ };
11154
+
11155
+ const startDrag = function(matchesEvent, cleanupHandlers) {
11156
+ if (currentDrag) {
11157
+ currentDrag.cleanup();
11158
+ }
11159
+
11160
+ dot.setOpacity(1.0);
11161
+ dot.setClickable(false);
11162
+ viewer.cameraControl.active = false;
11163
+
11164
+ currentDrag = {
11165
+ matchesEvent: matchesEvent,
11166
+ cleanup: function() {
11167
+ currentDrag = null;
11168
+ dot.setClickable(true);
11169
+ viewer.cameraControl.active = true;
11170
+ cleanupHandlers();
11171
+ }
11172
+ };
11173
+
11174
+ onStart();
11175
+ };
11176
+
11177
+ const cleanupDotHandlers = [ ];
11178
+ const dot_on = function(event, callback) {
11179
+ const id = dot.on(event, callback);
11180
+ cleanupDotHandlers.push(() => dot.off(id));
11181
+ };
11182
+
11183
+ if (handleMouseEvents)
11184
+ {
11185
+ dot_on("mouseover", () => (! currentDrag) && dot.setOpacity(1.0));
11186
+ dot_on("mouseleave", () => (! currentDrag) && dot.setOpacity(idleOpacity));
11187
+ dot_on("mousedown", event => {
11188
+ if (event.which === 1)
11189
+ {
11190
+ canvas.addEventListener("mousemove", onDragMove);
11191
+ canvas.addEventListener("mouseup", onDragEnd);
11192
+ startDrag(
11193
+ event => (event.which === 1) && event,
11194
+ () => {
11195
+ canvas.removeEventListener("mousemove", onDragMove);
11196
+ canvas.removeEventListener("mouseup", onDragEnd);
11197
+ });
11198
+ }
11199
+ });
11200
+ }
11201
+
11202
+ if (handleTouchEvents)
11203
+ {
11204
+ let touchStartId;
11205
+ dot_on("touchstart", event => {
11206
+ event.preventDefault();
11207
+ if (event.touches.length === 1)
11208
+ {
11209
+ touchStartId = event.touches[0].identifier;
11210
+ startDrag(
11211
+ event => [...event.changedTouches].find(e => e.identifier === touchStartId),
11212
+ () => { touchStartId = null; });
11213
+ }
11214
+ });
11215
+ dot_on("touchmove", event => {
11216
+ event.preventDefault();
11217
+ onDragMove(event);
11218
+ });
11219
+ dot_on("touchend", event => {
11220
+ event.preventDefault();
11221
+ onDragEnd(event);
11222
+ });
11223
+ }
11224
+
11225
+ const idleOpacity = 0.8;
11226
+ dot.setOpacity(idleOpacity);
11227
+
11228
+ return function() {
11229
+ currentDrag && currentDrag.cleanup();
11230
+ cleanupDotHandlers.forEach(c => c());
11231
+ dot.setOpacity(1.0);
11232
+ };
11233
+ }
11234
+ function activateDraggableDots(cfg) {
11235
+ const extractCFG = function(propName, defaultValue) {
11236
+ if (propName in cfg) {
11237
+ return cfg[propName];
11238
+ } else if (defaultValue !== undefined) {
11239
+ return defaultValue;
11240
+ } else {
11241
+ throw "config missing: " + propName;
11242
+ }
11243
+ };
11244
+
11245
+ const viewer = extractCFG("viewer");
11246
+ const handleMouseEvents = extractCFG("handleMouseEvents", false);
11247
+ const handleTouchEvents = extractCFG("handleTouchEvents", false);
11248
+ const pointerLens = extractCFG("pointerLens", null);
11249
+ const dots = extractCFG("dots");
11250
+ const ray2WorldPos = extractCFG("ray2WorldPos");
11251
+ const onEnd = extractCFG("onEnd", nop);
11252
+
11253
+ const updatePointerLens = (pointerLens
11254
+ ? function(canvasPos) {
11255
+ pointerLens.visible = !! canvasPos;
11256
+ if (canvasPos)
11257
+ {
11258
+ pointerLens.canvasPos = canvasPos;
11259
+ }
11260
+ }
11261
+ : () => { });
11262
+
11263
+ const cleanups = dots.map(dot => {
11264
+ let initPos;
11265
+ return activateDraggableDot(dot, {
11266
+ handleMouseEvents: handleMouseEvents,
11267
+ handleTouchEvents: handleTouchEvents,
11268
+ viewer: viewer,
11269
+ ray2WorldPos: (orig, dir, canvasPos) => (ray2WorldPos(orig, dir, canvasPos) || initPos),
11270
+ onStart: () => {
11271
+ initPos = dot.worldPos.slice();
11272
+ setOtherDotsActive(false, dot);
11273
+ },
11274
+ onMove: (canvasPos, worldPos) => {
11275
+ updatePointerLens(canvasPos);
11276
+ dot.worldPos = worldPos;
11277
+ },
11278
+ onEnd: () => {
11279
+ if (! onEnd(initPos, dot)) {
11280
+ dot.worldPos = initPos;
11281
+ }
11282
+ updatePointerLens(null);
11283
+ setOtherDotsActive(true, dot);
11284
+ }
11285
+ });
11286
+ });
11287
+
11288
+ const setOtherDotsActive = (active, dot) => dots.forEach(d => (d !== dot) && d.setClickable(active));
11289
+ setOtherDotsActive(true);
11290
+
11291
+ return function() {
11292
+ cleanups.forEach(c => c());
11293
+ updatePointerLens(null);
11294
+ };
11295
+ }
10786
11296
 
10787
11297
  /** @private */
10788
11298
  class Wire {
@@ -11031,229 +11541,6 @@ class Wire {
11031
11541
  }
11032
11542
  }
11033
11543
 
11034
- /** @private */
11035
- class Dot {
11036
-
11037
- constructor(parentElement, cfg = {}) {
11038
-
11039
- this._highlightClass = "viewer-ruler-dot-highlighted";
11040
-
11041
- this._x = 0;
11042
- this._y = 0;
11043
-
11044
- this._dot = document.createElement('div');
11045
- this._dot.className += this._dot.className ? ' viewer-ruler-dot' : 'viewer-ruler-dot';
11046
-
11047
- this._dotClickable = document.createElement('div');
11048
- this._dotClickable.className += this._dotClickable.className ? ' viewer-ruler-dot-clickable' : 'viewer-ruler-dot-clickable';
11049
-
11050
- this._visible = !!cfg.visible;
11051
- this._culled = false;
11052
-
11053
- var dot = this._dot;
11054
- var dotStyle = dot.style;
11055
- dotStyle["border-radius"] = 25 + "px";
11056
- dotStyle.border = "solid 2px white";
11057
- dotStyle.background = "lightgreen";
11058
- dotStyle.position = "absolute";
11059
- dotStyle["z-index"] = cfg.zIndex === undefined ? "40000005" : cfg.zIndex ;
11060
- dotStyle.width = 8 + "px";
11061
- dotStyle.height = 8 + "px";
11062
- dotStyle.visibility = cfg.visible !== false ? "visible" : "hidden";
11063
- dotStyle.top = 0 + "px";
11064
- dotStyle.left = 0 + "px";
11065
- dotStyle["box-shadow"] = "0 2px 5px 0 #182A3D;";
11066
- dotStyle["opacity"] = 1.0;
11067
- dotStyle["pointer-events"] = "none";
11068
- if (cfg.onContextMenu) ;
11069
- parentElement.appendChild(dot);
11070
-
11071
- var dotClickable = this._dotClickable;
11072
- var dotClickableStyle = dotClickable.style;
11073
- dotClickableStyle["border-radius"] = 35 + "px";
11074
- dotClickableStyle.border = "solid 10px white";
11075
- dotClickableStyle.position = "absolute";
11076
- dotClickableStyle["z-index"] = cfg.zIndex === undefined ? "40000007" : (cfg.zIndex + 1);
11077
- dotClickableStyle.width = 8 + "px";
11078
- dotClickableStyle.height = 8 + "px";
11079
- dotClickableStyle.visibility = "visible";
11080
- dotClickableStyle.top = 0 + "px";
11081
- dotClickableStyle.left = 0 + "px";
11082
- dotClickableStyle["opacity"] = 0.0;
11083
- dotClickableStyle["pointer-events"] = "none";
11084
- if (cfg.onContextMenu) ;
11085
- parentElement.appendChild(dotClickable);
11086
-
11087
- dotClickable.addEventListener('click', (event) => {
11088
- parentElement.dispatchEvent(new MouseEvent('mouseover', event));
11089
- });
11090
-
11091
- if (cfg.onMouseOver) {
11092
- dotClickable.addEventListener('mouseover', (event) => {
11093
- cfg.onMouseOver(event, this);
11094
- parentElement.dispatchEvent(new MouseEvent('mouseover', event));
11095
- });
11096
- }
11097
-
11098
- if (cfg.onMouseLeave) {
11099
- dotClickable.addEventListener('mouseleave', (event) => {
11100
- cfg.onMouseLeave(event, this);
11101
- });
11102
- }
11103
-
11104
- if (cfg.onMouseWheel) {
11105
- dotClickable.addEventListener('wheel', (event) => {
11106
- cfg.onMouseWheel(event, this);
11107
- });
11108
- }
11109
-
11110
- if (cfg.onMouseDown) {
11111
- dotClickable.addEventListener('mousedown', (event) => {
11112
- cfg.onMouseDown(event, this);
11113
- });
11114
- }
11115
-
11116
- if (cfg.onMouseUp) {
11117
- dotClickable.addEventListener('mouseup', (event) => {
11118
- cfg.onMouseUp(event, this);
11119
- });
11120
- }
11121
-
11122
- if (cfg.onMouseMove) {
11123
- dotClickable.addEventListener('mousemove', (event) => {
11124
- cfg.onMouseMove(event, this);
11125
- });
11126
- }
11127
-
11128
- if (cfg.onContextMenu) {
11129
- if(os.isIphoneSafari()){
11130
- dotClickable.addEventListener('touchstart', (event) => {
11131
- event.preventDefault();
11132
- if(this._timeout){
11133
- clearTimeout(this._timeout);
11134
- this._timeout = null;
11135
- }
11136
- this._timeout = setTimeout(() => {
11137
- event.clientX = event.touches[0].clientX;
11138
- event.clientY = event.touches[0].clientY;
11139
- cfg.onContextMenu(event, this);
11140
- clearTimeout(this._timeout);
11141
- this._timeout = null;
11142
- }, 500);
11143
- });
11144
-
11145
- dotClickable.addEventListener('touchend', (event) => {
11146
- event.preventDefault();
11147
- //stops short touches from calling the timeout
11148
- if(this._timeout) {
11149
- clearTimeout(this._timeout);
11150
- this._timeout = null;
11151
- }
11152
- } );
11153
-
11154
- }
11155
- else {
11156
- dotClickable.addEventListener('contextmenu', (event) => {
11157
- console.log(event);
11158
- cfg.onContextMenu(event, this);
11159
- event.preventDefault();
11160
- event.stopPropagation();
11161
- console.log("Label context menu");
11162
- });
11163
- }
11164
-
11165
- }
11166
-
11167
- if (cfg.onTouchstart) {
11168
- dotClickable.addEventListener('touchstart', (event) => {
11169
- cfg.onTouchstart(event, this);
11170
- });
11171
- }
11172
-
11173
- if (cfg.onTouchmove) {
11174
- dotClickable.addEventListener('touchmove', (event) => {
11175
- cfg.onTouchmove(event, this);
11176
- });
11177
- }
11178
-
11179
- if (cfg.onTouchend) {
11180
- dotClickable.addEventListener('touchend', (event) => {
11181
- cfg.onTouchend(event, this);
11182
- });
11183
- }
11184
-
11185
- this.setPos(cfg.x || 0, cfg.y || 0);
11186
- this.setFillColor(cfg.fillColor);
11187
- this.setBorderColor(cfg.borderColor);
11188
- }
11189
-
11190
- setPos(x, y) {
11191
- this._x = x;
11192
- this._y = y;
11193
- var dotStyle = this._dot.style;
11194
- dotStyle["left"] = (Math.round(x) - 4) + 'px';
11195
- dotStyle["top"] = (Math.round(y) - 4) + 'px';
11196
-
11197
- var dotClickableStyle = this._dotClickable.style;
11198
- dotClickableStyle["left"] = (Math.round(x) - 9) + 'px';
11199
- dotClickableStyle["top"] = (Math.round(y) - 9) + 'px';
11200
- }
11201
-
11202
- setFillColor(color) {
11203
- this._dot.style.background = color || "lightgreen";
11204
- }
11205
-
11206
- setBorderColor(color) {
11207
- this._dot.style.border = "solid 2px" + (color || "black");
11208
- }
11209
-
11210
- setOpacity(opacity) {
11211
- this._dot.style.opacity = opacity;
11212
- }
11213
-
11214
- setVisible(visible) {
11215
- if (this._visible === visible) {
11216
- return;
11217
- }
11218
- this._visible = !!visible;
11219
- this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden";
11220
- }
11221
-
11222
- setCulled(culled) {
11223
- if (this._culled === culled) {
11224
- return;
11225
- }
11226
- this._culled = !!culled;
11227
- this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden";
11228
- }
11229
-
11230
- setClickable(clickable) {
11231
- this._dotClickable.style["pointer-events"] = (clickable) ? "all" : "none";
11232
- }
11233
-
11234
- setHighlighted(highlighted) {
11235
- if (this._highlighted === highlighted) {
11236
- return;
11237
- }
11238
- this._highlighted = !!highlighted;
11239
- if (this._highlighted) {
11240
- this._dot.classList.add(this._highlightClass);
11241
- } else {
11242
- this._dot.classList.remove(this._highlightClass);
11243
- }
11244
- }
11245
-
11246
- destroy() {
11247
- this.setVisible(false);
11248
- if (this._dot.parentElement) {
11249
- this._dot.parentElement.removeChild(this._dot);
11250
- }
11251
- if (this._dotClickable.parentElement) {
11252
- this._dotClickable.parentElement.removeChild(this._dotClickable);
11253
- }
11254
- }
11255
- }
11256
-
11257
11544
  /** @private */
11258
11545
  class Label {
11259
11546
 
@@ -11500,10 +11787,6 @@ class AngleMeasurement extends Component {
11500
11787
 
11501
11788
  var scene = this.plugin.viewer.scene;
11502
11789
 
11503
- this._originMarker = new Marker(scene, cfg.origin);
11504
- this._cornerMarker = new Marker(scene, cfg.corner);
11505
- this._targetMarker = new Marker(scene, cfg.target);
11506
-
11507
11790
  this._originWorld = math.vec3();
11508
11791
  this._cornerWorld = math.vec3();
11509
11792
  this._targetWorld = math.vec3();
@@ -11543,7 +11826,7 @@ class AngleMeasurement extends Component {
11543
11826
  this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mousemove', event));
11544
11827
  };
11545
11828
 
11546
- this._originDot = new Dot(this._container, {
11829
+ this._originDot = new Dot3D(scene, cfg.origin, this._container, {
11547
11830
  fillColor: this._color,
11548
11831
  zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined,
11549
11832
  onMouseOver,
@@ -11554,7 +11837,7 @@ class AngleMeasurement extends Component {
11554
11837
  onMouseMove,
11555
11838
  onContextMenu
11556
11839
  });
11557
- this._cornerDot = new Dot(this._container, {
11840
+ this._cornerDot = new Dot3D(scene, cfg.corner, this._container, {
11558
11841
  fillColor: this._color,
11559
11842
  zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined,
11560
11843
  onMouseOver,
@@ -11565,7 +11848,7 @@ class AngleMeasurement extends Component {
11565
11848
  onMouseMove,
11566
11849
  onContextMenu
11567
11850
  });
11568
- this._targetDot = new Dot(this._container, {
11851
+ this._targetDot = new Dot3D(scene, cfg.target, this._container, {
11569
11852
  fillColor: this._color,
11570
11853
  zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined,
11571
11854
  onMouseOver,
@@ -11632,19 +11915,19 @@ class AngleMeasurement extends Component {
11632
11915
  this._labelsVisible = false;
11633
11916
  this._clickable = false;
11634
11917
 
11635
- this._originMarker.on("worldPos", (value) => {
11918
+ this._originDot.on("worldPos", (value) => {
11636
11919
  this._originWorld.set(value || [0, 0, 0]);
11637
11920
  this._wpDirty = true;
11638
11921
  this._needUpdate(0); // No lag
11639
11922
  });
11640
11923
 
11641
- this._cornerMarker.on("worldPos", (value) => {
11924
+ this._cornerDot.on("worldPos", (value) => {
11642
11925
  this._cornerWorld.set(value || [0, 0, 0]);
11643
11926
  this._wpDirty = true;
11644
11927
  this._needUpdate(0); // No lag
11645
11928
  });
11646
11929
 
11647
- this._targetMarker.on("worldPos", (value) => {
11930
+ this._targetDot.on("worldPos", (value) => {
11648
11931
  this._targetWorld.set(value || [0, 0, 0]);
11649
11932
  this._wpDirty = true;
11650
11933
  this._needUpdate(0); // No lag
@@ -11750,9 +12033,9 @@ class AngleMeasurement extends Component {
11750
12033
  if (this._cpDirty) {
11751
12034
 
11752
12035
  const near = -0.3;
11753
- const zOrigin = this._originMarker.viewPos[2];
11754
- const zCorner = this._cornerMarker.viewPos[2];
11755
- const zTarget = this._targetMarker.viewPos[2];
12036
+ const zOrigin = this._originDot.viewPos[2];
12037
+ const zCorner = this._cornerDot.viewPos[2];
12038
+ const zTarget = this._targetDot.viewPos[2];
11756
12039
 
11757
12040
  if (zOrigin > near || zCorner > near || zTarget > near) {
11758
12041
 
@@ -11789,10 +12072,6 @@ class AngleMeasurement extends Component {
11789
12072
  j += 2;
11790
12073
  }
11791
12074
 
11792
- this._originDot.setPos(cp[0], cp[1]);
11793
- this._cornerDot.setPos(cp[2], cp[3]);
11794
- this._targetDot.setPos(cp[4], cp[5]);
11795
-
11796
12075
  this._originWire.setStartAndEnd(cp[0], cp[1], cp[2], cp[3]);
11797
12076
  this._targetWire.setStartAndEnd(cp[2], cp[3], cp[4], cp[5]);
11798
12077
 
@@ -11873,30 +12152,30 @@ class AngleMeasurement extends Component {
11873
12152
  }
11874
12153
 
11875
12154
  /**
11876
- * Gets the origin {@link Marker}.
12155
+ * Gets the origin {@link Dot3D}.
11877
12156
  *
11878
- * @type {Marker}
12157
+ * @type {Dot3D}
11879
12158
  */
11880
12159
  get origin() {
11881
- return this._originMarker;
12160
+ return this._originDot;
11882
12161
  }
11883
12162
 
11884
12163
  /**
11885
- * Gets the corner {@link Marker}.
12164
+ * Gets the corner {@link Dot3D}.
11886
12165
  *
11887
- * @type {Marker}
12166
+ * @type {Dot3D}
11888
12167
  */
11889
12168
  get corner() {
11890
- return this._cornerMarker;
12169
+ return this._cornerDot;
11891
12170
  }
11892
12171
 
11893
12172
  /**
11894
- * Gets the target {@link Marker}.
12173
+ * Gets the target {@link Dot3D}.
11895
12174
  *
11896
- * @type {Marker}
12175
+ * @type {Dot3D}
11897
12176
  */
11898
12177
  get target() {
11899
- return this._targetMarker;
12178
+ return this._targetDot;
11900
12179
  }
11901
12180
 
11902
12181
  /**
@@ -11966,7 +12245,7 @@ class AngleMeasurement extends Component {
11966
12245
  }
11967
12246
 
11968
12247
  /**
11969
- * Sets if the origin {@link Marker} is visible.
12248
+ * Sets if the origin {@link Dot3D} is visible.
11970
12249
  *
11971
12250
  * @type {Boolean}
11972
12251
  */
@@ -11979,7 +12258,7 @@ class AngleMeasurement extends Component {
11979
12258
  }
11980
12259
 
11981
12260
  /**
11982
- * Gets if the origin {@link Marker} is visible.
12261
+ * Gets if the origin {@link Dot3D} is visible.
11983
12262
  *
11984
12263
  * @type {Boolean}
11985
12264
  */
@@ -11988,7 +12267,7 @@ class AngleMeasurement extends Component {
11988
12267
  }
11989
12268
 
11990
12269
  /**
11991
- * Sets if the corner {@link Marker} is visible.
12270
+ * Sets if the corner {@link Dot3D} is visible.
11992
12271
  *
11993
12272
  * @type {Boolean}
11994
12273
  */
@@ -12001,7 +12280,7 @@ class AngleMeasurement extends Component {
12001
12280
  }
12002
12281
 
12003
12282
  /**
12004
- * Gets if the corner {@link Marker} is visible.
12283
+ * Gets if the corner {@link Dot3D} is visible.
12005
12284
  *
12006
12285
  * @type {Boolean}
12007
12286
  */
@@ -12010,7 +12289,7 @@ class AngleMeasurement extends Component {
12010
12289
  }
12011
12290
 
12012
12291
  /**
12013
- * Sets if the target {@link Marker} is visible.
12292
+ * Sets if the target {@link Dot3D} is visible.
12014
12293
  *
12015
12294
  * @type {Boolean}
12016
12295
  */
@@ -12023,7 +12302,7 @@ class AngleMeasurement extends Component {
12023
12302
  }
12024
12303
 
12025
12304
  /**
12026
- * Gets if the target {@link Marker} is visible.
12305
+ * Gets if the target {@link Dot3D} is visible.
12027
12306
  *
12028
12307
  * @type {Boolean}
12029
12308
  */
@@ -14103,265 +14382,6 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
14103
14382
  }
14104
14383
  }
14105
14384
 
14106
- const nop = () => { };
14107
-
14108
- function transformToNode(from, to, vec) {
14109
- const fromRec = from.getBoundingClientRect();
14110
- const toRec = to.getBoundingClientRect();
14111
- vec[0] += fromRec.left - toRec.left;
14112
- vec[1] += fromRec.top - toRec.top;
14113
- }
14114
- function createDraggableDot3D(cfg) {
14115
- const extractCFG = function(propName, defaultValue) {
14116
- if (propName in cfg) {
14117
- return cfg[propName];
14118
- } else if (defaultValue !== undefined) {
14119
- return defaultValue;
14120
- } else {
14121
- throw "config missing: " + propName;
14122
- }
14123
- };
14124
-
14125
- const viewer = extractCFG("viewer");
14126
- const worldPos = extractCFG("worldPos");
14127
- const color = extractCFG("color");
14128
- const ray2WorldPos = extractCFG("ray2WorldPos");
14129
- const handleMouseEvents = extractCFG("handleMouseEvents", false);
14130
- const handleTouchEvents = extractCFG("handleTouchEvents", false);
14131
- const onStart = extractCFG("onStart", nop);
14132
- const onMove = extractCFG("onMove", nop);
14133
- const onEnd = extractCFG("onEnd", nop);
14134
-
14135
- const scene = viewer.scene;
14136
- const canvas = scene.canvas.canvas;
14137
-
14138
- const marker = new Marker(scene, {});
14139
-
14140
- const pickWorldPos = canvasPos => {
14141
- const origin = math.vec3();
14142
- const direction = math.vec3();
14143
- math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
14144
- return ray2WorldPos(origin, direction, canvasPos);
14145
- };
14146
-
14147
- const onChange = event => {
14148
- const canvasPos = math.vec2([ event.clientX, event.clientY ]);
14149
- transformToNode(canvas.ownerDocument.body, canvas, canvasPos);
14150
-
14151
- const worldPos = pickWorldPos(canvasPos);
14152
- marker.worldPos = worldPos;
14153
- updateDotPos();
14154
- onMove(canvasPos, worldPos);
14155
- };
14156
-
14157
- let currentDrag = null;
14158
-
14159
- const onDragMove = function(event) {
14160
- const e = currentDrag.matchesEvent(event);
14161
- if (e)
14162
- {
14163
- onChange(e);
14164
- }
14165
- };
14166
-
14167
- const onDragEnd = function(event) {
14168
- const e = currentDrag.matchesEvent(event);
14169
- if (e)
14170
- {
14171
- dot.setOpacity(idleOpacity);
14172
- currentDrag.cleanup();
14173
- onChange(e);
14174
- onEnd();
14175
- }
14176
- };
14177
-
14178
- const startDrag = function(matchesEvent, cleanupHandlers) {
14179
- if (currentDrag) {
14180
- currentDrag.cleanup();
14181
- }
14182
-
14183
- dot.setOpacity(1.0);
14184
- dot.setClickable(false);
14185
- viewer.cameraControl.active = false;
14186
-
14187
- currentDrag = {
14188
- matchesEvent: matchesEvent,
14189
- cleanup: function() {
14190
- currentDrag = null;
14191
- dot.setClickable(true);
14192
- viewer.cameraControl.active = true;
14193
- cleanupHandlers();
14194
- }
14195
- };
14196
-
14197
- onStart();
14198
- };
14199
-
14200
- const dotCfg = { fillColor: color };
14201
-
14202
- if (handleMouseEvents)
14203
- {
14204
- dotCfg.onMouseOver = () => (! currentDrag) && dot.setOpacity(1.0);
14205
- dotCfg.onMouseLeave = () => (! currentDrag) && dot.setOpacity(idleOpacity);
14206
- dotCfg.onMouseDown = event => {
14207
- if (event.which === 1)
14208
- {
14209
- canvas.addEventListener("mousemove", onDragMove);
14210
- canvas.addEventListener("mouseup", onDragEnd);
14211
- startDrag(
14212
- event => (event.which === 1) && event,
14213
- () => {
14214
- canvas.removeEventListener("mousemove", onDragMove);
14215
- canvas.removeEventListener("mouseup", onDragEnd);
14216
- });
14217
- }
14218
- };
14219
- }
14220
-
14221
- if (handleTouchEvents)
14222
- {
14223
- let touchStartId;
14224
- dotCfg.onTouchstart = event => {
14225
- event.preventDefault();
14226
- if (event.touches.length === 1)
14227
- {
14228
- touchStartId = event.touches[0].identifier;
14229
- startDrag(
14230
- event => [...event.changedTouches].find(e => e.identifier === touchStartId),
14231
- () => { touchStartId = null; });
14232
- }
14233
- };
14234
- dotCfg.onTouchmove = event => {
14235
- event.preventDefault();
14236
- onDragMove(event);
14237
- };
14238
- dotCfg.onTouchend = event => {
14239
- event.preventDefault();
14240
- onDragEnd(event);
14241
- };
14242
- }
14243
-
14244
- const dotParent = canvas.ownerDocument.body;
14245
- const dot = new Dot(dotParent, dotCfg);
14246
-
14247
- const idleOpacity = 0.5;
14248
- dot.setOpacity(idleOpacity);
14249
-
14250
- const updateDotPos = function() {
14251
- const pos = marker.canvasPos.slice();
14252
- transformToNode(canvas, dotParent, pos);
14253
- dot.setPos(pos[0], pos[1]);
14254
- };
14255
-
14256
- marker.worldPos = worldPos;
14257
- updateDotPos();
14258
-
14259
- const onViewMatrix = scene.camera.on("viewMatrix", updateDotPos);
14260
- const onProjMatrix = scene.camera.on("projMatrix", updateDotPos);
14261
-
14262
- return {
14263
- setActive: value => dot.setClickable(value),
14264
- getWorldPos: () => marker.worldPos,
14265
- setWorldPos: pos => { marker.worldPos = pos; updateDotPos(); },
14266
- destroy: function() {
14267
- currentDrag && currentDrag.cleanup();
14268
- scene.camera.off(onViewMatrix);
14269
- scene.camera.off(onProjMatrix);
14270
- marker.destroy();
14271
- dot.destroy();
14272
- }
14273
- };
14274
- }
14275
- function activateDraggableDots(cfg) {
14276
- const extractCFG = function(propName, defaultValue) {
14277
- if (propName in cfg) {
14278
- return cfg[propName];
14279
- } else if (defaultValue !== undefined) {
14280
- return defaultValue;
14281
- } else {
14282
- throw "config missing: " + propName;
14283
- }
14284
- };
14285
-
14286
- const viewer = extractCFG("viewer");
14287
- const handleMouseEvents = extractCFG("handleMouseEvents", false);
14288
- const handleTouchEvents = extractCFG("handleTouchEvents", false);
14289
- const snapping = extractCFG("snapping");
14290
- const pointerLens = extractCFG("pointerLens", null);
14291
- const color = extractCFG("color");
14292
- const markers = extractCFG("markers");
14293
- const onEdit = extractCFG("onEdit", nop);
14294
-
14295
- const updatePointerLens = (pointerLens
14296
- ? function(canvasPos) {
14297
- pointerLens.visible = !! canvasPos;
14298
- if (canvasPos)
14299
- {
14300
- pointerLens.canvasPos = canvasPos;
14301
- }
14302
- }
14303
- : () => { });
14304
-
14305
- const dots = markers.map(marker => {
14306
- let initDotPos, initMarkerPos;
14307
- const setCoord = coord => marker.worldPos = coord;
14308
-
14309
- const dot = createDraggableDot3D({
14310
- handleMouseEvents: handleMouseEvents,
14311
- handleTouchEvents: handleTouchEvents,
14312
- viewer: viewer,
14313
- worldPos: marker.worldPos,
14314
- color: color,
14315
- ray2WorldPos: (orig, dir, canvasPos) => {
14316
- const tryPickWorldPos = snap => {
14317
- const pickResult = viewer.scene.pick({
14318
- canvasPos: canvasPos,
14319
- snapToEdge: snap,
14320
- snapToVertex: snap,
14321
- pickSurface: true // <<------ This causes picking to find the intersection point on the entity
14322
- });
14323
-
14324
- // If - when snapping - no pick found, then try w/o snapping
14325
- return (pickResult && pickResult.worldPos) ? pickResult.worldPos : (snap && tryPickWorldPos(false));
14326
- };
14327
-
14328
- return tryPickWorldPos(!!snapping) || initDotPos;
14329
- },
14330
- onStart: () => {
14331
- initDotPos = dot.getWorldPos().slice();
14332
- initMarkerPos = marker.worldPos.slice();
14333
- setOtherDotsActive(false, dot);
14334
- },
14335
- onMove: (canvasPos, worldPos) => {
14336
- updatePointerLens(canvasPos);
14337
- setCoord(worldPos);
14338
- },
14339
- onEnd: () => {
14340
- if (! math.compareVec3(initMarkerPos, marker.worldPos))
14341
- {
14342
- onEdit();
14343
- }
14344
- else
14345
- {
14346
- dot.setWorldPos(initDotPos);
14347
- setCoord(initMarkerPos);
14348
- }
14349
- updatePointerLens(null);
14350
- setOtherDotsActive(true, dot);
14351
- }
14352
- });
14353
- return dot;
14354
- });
14355
-
14356
- const setOtherDotsActive = (active, dot) => dots.forEach(d => (d !== dot) && d.setActive(active));
14357
- setOtherDotsActive(true);
14358
-
14359
- return function() {
14360
- dots.forEach(m => m.destroy());
14361
- updatePointerLens(null);
14362
- };
14363
- }
14364
-
14365
14385
  class AngleMeasurementEditControl extends Component {
14366
14386
 
14367
14387
  /**
@@ -14384,11 +14404,30 @@ class AngleMeasurementEditControl extends Component {
14384
14404
  viewer: viewer,
14385
14405
  handleMouseEvents: handleMouseEvents,
14386
14406
  handleTouchEvents: handleTouchEvents,
14387
- snapping: cfg.snapping,
14388
14407
  pointerLens: cfg.pointerLens,
14389
- color: measurement.color,
14390
- markers: [ measurement.origin, measurement.corner, measurement.target ],
14391
- onEdit: () => this.fire("edited")
14408
+ dots: [ measurement.origin, measurement.corner, measurement.target ],
14409
+ ray2WorldPos: (orig, dir, canvasPos) => {
14410
+ const tryPickWorldPos = snap => {
14411
+ const pickResult = viewer.scene.pick({
14412
+ canvasPos: canvasPos,
14413
+ snapToEdge: snap,
14414
+ snapToVertex: snap,
14415
+ pickSurface: true // <<------ This causes picking to find the intersection point on the entity
14416
+ });
14417
+
14418
+ // If - when snapping - no pick found, then try w/o snapping
14419
+ return (pickResult && pickResult.worldPos) ? pickResult.worldPos : (snap && tryPickWorldPos(false));
14420
+ };
14421
+
14422
+ return tryPickWorldPos(!!cfg.snapping);
14423
+ },
14424
+ onEnd: (initPos, dot) => {
14425
+ const changed = ! math.compareVec3(initPos, dot.worldPos);
14426
+ if (changed) {
14427
+ this.fire("edited");
14428
+ }
14429
+ return changed;
14430
+ }
14392
14431
  });
14393
14432
 
14394
14433
  const destroyCb = measurement.on("destroyed", cleanup);
@@ -14417,6 +14456,10 @@ class AngleMeasurementEditTouchControl extends AngleMeasurementEditControl {
14417
14456
  }
14418
14457
  }
14419
14458
 
14459
+ const tempVec3a$K = math.vec3();
14460
+ const tempVec3b$z = math.vec3();
14461
+ const tempVec3c$v = math.vec3();
14462
+
14420
14463
  /**
14421
14464
  * A {@link Marker} with an HTML label attached to it, managed by an {@link AnnotationsPlugin}.
14422
14465
  *
@@ -14456,6 +14499,9 @@ class Annotation extends Marker {
14456
14499
  this._marker.addEventListener("click", this._onMouseClickedExternalMarker = () => {
14457
14500
  this.plugin.fire("markerClicked", this);
14458
14501
  });
14502
+ this._marker.addEventListener("contextmenu", this._onContextMenuExtenalMarker = () => {
14503
+ this.plugin.fire("contextmenu", this);
14504
+ });
14459
14505
  this._marker.addEventListener("mouseenter", this._onMouseEnterExternalMarker = () => {
14460
14506
  this.plugin.fire("markerMouseEnter", this);
14461
14507
  });
@@ -14575,6 +14621,10 @@ class Annotation extends Marker {
14575
14621
  this._marker.addEventListener("click", () => {
14576
14622
  this.plugin.fire("markerClicked", this);
14577
14623
  });
14624
+ this._marker.addEventListener("contextmenu", e => {
14625
+ e.preventDefault();
14626
+ this.plugin.fire("contextmenu", this);
14627
+ });
14578
14628
  this._marker.addEventListener("mouseenter", () => {
14579
14629
  this.plugin.fire("markerMouseEnter", this);
14580
14630
  });
@@ -14636,6 +14686,24 @@ class Annotation extends Marker {
14636
14686
  return template;
14637
14687
  }
14638
14688
 
14689
+ /**
14690
+ * Sets the Marker's worldPos and entity properties based on passed {@link PickResult}
14691
+ *
14692
+ * @param {PickResult} pickResult A PickResult to position the Marker at.
14693
+ */
14694
+ setFromPickResult(pickResult) {
14695
+ if (!pickResult.worldPos || !pickResult.worldNormal) {
14696
+ this.error("Param 'pickResult' does not have both worldPos and worldNormal");
14697
+ } else {
14698
+ const normalizedWorldNormal = math.normalizeVec3(pickResult.worldNormal, tempVec3a$K);
14699
+ const offset = (this.plugin && this.plugin.surfaceOffset) || 0;
14700
+ const offsetVec = math.mulVec3Scalar(normalizedWorldNormal, offset, tempVec3b$z);
14701
+ const offsetWorldPos = math.addVec3(pickResult.worldPos, offsetVec, tempVec3c$v);
14702
+ this.entity = pickResult.entity;
14703
+ this.worldPos = offsetWorldPos;
14704
+ }
14705
+ }
14706
+
14639
14707
  /**
14640
14708
  * Sets whether or not to show this Annotation's marker.
14641
14709
  *
@@ -14766,6 +14834,7 @@ class Annotation extends Marker {
14766
14834
  this._marker = null;
14767
14835
  } else {
14768
14836
  this._marker.removeEventListener("click", this._onMouseClickedExternalMarker);
14837
+ this._marker.removeEventListener("contextmenu", this._onContextMenuExtenalMarker);
14769
14838
  this._marker.removeEventListener("mouseenter", this._onMouseEnterExternalMarker);
14770
14839
  this._marker.removeEventListener("mouseleave", this._onMouseLeaveExternalMarker);
14771
14840
  this._marker = null;
@@ -14782,10 +14851,6 @@ class Annotation extends Marker {
14782
14851
  }
14783
14852
  }
14784
14853
 
14785
- const tempVec3a$K = math.vec3();
14786
- const tempVec3b$z = math.vec3();
14787
- const tempVec3c$v = math.vec3();
14788
-
14789
14854
  /**
14790
14855
  * {@link Viewer} plugin that creates {@link Annotation}s.
14791
14856
  *
@@ -15260,24 +15325,6 @@ class AnnotationsPlugin extends Plugin {
15260
15325
  this.error("Viewer component with this ID already exists: " + params.id);
15261
15326
  delete params.id;
15262
15327
  }
15263
- var worldPos;
15264
- var entity;
15265
- params.pickResult = params.pickResult || params.pickRecord;
15266
- if (params.pickResult) {
15267
- const pickResult = params.pickResult;
15268
- if (!pickResult.worldPos || !pickResult.worldNormal) {
15269
- this.error("Param 'pickResult' does not have both worldPos and worldNormal");
15270
- } else {
15271
- const normalizedWorldNormal = math.normalizeVec3(pickResult.worldNormal, tempVec3a$K);
15272
- const offsetVec = math.mulVec3Scalar(normalizedWorldNormal, this._surfaceOffset, tempVec3b$z);
15273
- const offsetWorldPos = math.addVec3(pickResult.worldPos, offsetVec, tempVec3c$v);
15274
- worldPos = offsetWorldPos;
15275
- entity = pickResult.entity;
15276
- }
15277
- } else {
15278
- worldPos = params.worldPos;
15279
- entity = params.entity;
15280
- }
15281
15328
 
15282
15329
  var markerElement = null;
15283
15330
  if (params.markerElementId) {
@@ -15298,8 +15345,6 @@ class AnnotationsPlugin extends Plugin {
15298
15345
  const annotation = new Annotation(this.viewer.scene, {
15299
15346
  id: params.id,
15300
15347
  plugin: this,
15301
- entity: entity,
15302
- worldPos: worldPos,
15303
15348
  container: this._container,
15304
15349
  markerElement: markerElement,
15305
15350
  labelElement: labelElement,
@@ -15315,6 +15360,15 @@ class AnnotationsPlugin extends Plugin {
15315
15360
  projection: params.projection,
15316
15361
  visible: (params.visible !== false)
15317
15362
  });
15363
+
15364
+ params.pickResult = params.pickResult || params.pickRecord;
15365
+ if (params.pickResult) {
15366
+ annotation.setFromPickResult(params.pickResult);
15367
+ } else {
15368
+ annotation.entity = params.entity;
15369
+ annotation.worldPos = params.worldPos;
15370
+ }
15371
+
15318
15372
  this.annotations[annotation.id] = annotation;
15319
15373
  annotation.on("destroyed", () => {
15320
15374
  delete this.annotations[annotation.id];
@@ -49794,6 +49848,270 @@ function buildPolylineGeometryFromCurve(cfg = {}) {
49794
49848
  });
49795
49849
  }
49796
49850
 
49851
+ /**
49852
+ * @desc Creates a 3D line {@link Geometry}.
49853
+ *
49854
+ * ## Usage
49855
+ *
49856
+ * In the example below we'll create a {@link Mesh} with a line {@link ReadableGeometry}.
49857
+ *
49858
+ * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/scenegraph/#buildLineGeometry)]
49859
+ *
49860
+ * ````javascript
49861
+ * //------------------------------------------------------------------------------------------------------------------
49862
+ * // Import the modules we need for this example
49863
+ * //------------------------------------------------------------------------------------------------------------------
49864
+ *
49865
+ * import {buildLineGeometry, Viewer, Mesh, ReadableGeometry, PhongMaterial} from "../../dist/xeokit-sdk.min.es.js";
49866
+ *
49867
+ * //------------------------------------------------------------------------------------------------------------------
49868
+ * // Create a Viewer and arrange the camera
49869
+ * //------------------------------------------------------------------------------------------------------------------
49870
+ *
49871
+ * const viewer = new Viewer({
49872
+ * canvasId: "myCanvas"
49873
+ * });
49874
+ *
49875
+ * viewer.camera.eye = [0, 0, 8];
49876
+ * viewer.camera.look = [0, 0, 0];
49877
+ * viewer.camera.up = [0, 1, 0];
49878
+ *
49879
+ * //------------------------------------------------------------------------------------------------------------------
49880
+ * // Create a mesh with simple 2d line shape
49881
+ * //------------------------------------------------------------------------------------------------------------------
49882
+ *
49883
+ * new Mesh(viewer.scene, {
49884
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49885
+ * startPoint: [-5,-2,0],
49886
+ * endPoint: [-5,2,0],
49887
+ * })),
49888
+ * material: new PhongMaterial(viewer.scene, {
49889
+ * emissive: [0, 1,]
49890
+ * })
49891
+ * });
49892
+ *
49893
+ * //------------------------------------------------------------------------------------------------------------------
49894
+ * // Create a mesh with simple 2d line shape with black color
49895
+ * //------------------------------------------------------------------------------------------------------------------
49896
+ *
49897
+ * new Mesh(viewer.scene, {
49898
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49899
+ * startPoint: [-4,-2,0],
49900
+ * endPoint: [-4,2,0],
49901
+ * })),
49902
+ * material: new PhongMaterial(viewer.scene, {
49903
+ * emissive: [0, 0, 0]
49904
+ * })
49905
+ * });
49906
+ *
49907
+ * //------------------------------------------------------------------------------------------------------------------
49908
+ * // Create a mesh with simple 2d line shape with black color and simple pattern
49909
+ * //------------------------------------------------------------------------------------------------------------------
49910
+ *
49911
+ * new Mesh(viewer.scene, {
49912
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49913
+ * startPoint: [-3,-2,0],
49914
+ * endPoint: [-3,2,0],
49915
+ * pattern: [0.10],
49916
+ * })),
49917
+ * material: new PhongMaterial(viewer.scene, {
49918
+ * emissive: [0, 0, 0]
49919
+ * })
49920
+ * });
49921
+ *
49922
+ * //------------------------------------------------------------------------------------------------------------------
49923
+ * // Create a mesh with simple 2d line shape with blue color and simple pattern extended to end
49924
+ * //------------------------------------------------------------------------------------------------------------------
49925
+ *
49926
+ * new Mesh(viewer.scene, {
49927
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49928
+ * startPoint: [-2,-2,0],
49929
+ * endPoint: [-2,2,0],
49930
+ * pattern: [0.10],
49931
+ * extendToEnd: true,
49932
+ * })),
49933
+ * material: new PhongMaterial(viewer.scene, {
49934
+ * emissive: [0, 0, 1]
49935
+ * })
49936
+ * });
49937
+ *
49938
+ * //------------------------------------------------------------------------------------------------------------------
49939
+ * // Create a mesh with simple 2d line shape with black color and more complex pattern
49940
+ * //------------------------------------------------------------------------------------------------------------------
49941
+ *
49942
+ * new Mesh(viewer.scene, {
49943
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49944
+ * startPoint: [-1,-2,0],
49945
+ * endPoint: [-1,2,0],
49946
+ * pattern: [0.15, 0.05],
49947
+ * })),
49948
+ * material: new PhongMaterial(viewer.scene, {
49949
+ * emissive: [0, 0, 0]
49950
+ * })
49951
+ * });
49952
+ *
49953
+ * //------------------------------------------------------------------------------------------------------------------
49954
+ * // Create a mesh with simple 2d line shape with blue color and more complex pattern extended to end
49955
+ * //------------------------------------------------------------------------------------------------------------------
49956
+ *
49957
+ * new Mesh(viewer.scene, {
49958
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49959
+ * startPoint: [0,-2,0],
49960
+ * endPoint: [0,2,0],
49961
+ * pattern: [0.15, 0.05],
49962
+ * extendToEnd: true,
49963
+ * })),
49964
+ * material: new PhongMaterial(viewer.scene, {
49965
+ * emissive: [0, 0, 1]
49966
+ * })
49967
+ * });
49968
+ *
49969
+ * //------------------------------------------------------------------------------------------------------------------
49970
+ * // Create a mesh with simple 2d line shape with black color and complex pattern
49971
+ * //------------------------------------------------------------------------------------------------------------------
49972
+ *
49973
+ * new Mesh(viewer.scene, {
49974
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49975
+ * startPoint: [1,-2,0],
49976
+ * endPoint: [1,2,0],
49977
+ * pattern: [0.15, 0.05, 0.50],
49978
+ * })),
49979
+ * material: new PhongMaterial(viewer.scene, {
49980
+ * emissive: [0, 0, 0]
49981
+ * })
49982
+ * });
49983
+ *
49984
+ * //------------------------------------------------------------------------------------------------------------------
49985
+ * // Create a mesh with simple 2d line shape with blue color and complex pattern extended to end
49986
+ * //------------------------------------------------------------------------------------------------------------------
49987
+ *
49988
+ * new Mesh(viewer.scene, {
49989
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49990
+ * startPoint: [2,-2,0],
49991
+ * endPoint: [2,2,0],
49992
+ * pattern: [0.15, 0.05, 0.50],
49993
+ * extendToEnd: true,
49994
+ * })),
49995
+ * material: new PhongMaterial(viewer.scene, {
49996
+ * emissive: [0, 0, 1]
49997
+ * })
49998
+ * });
49999
+ *
50000
+ * //------------------------------------------------------------------------------------------------------------------
50001
+ * // Create a mesh with simple 3d line shape with white color and simple pattern
50002
+ * //------------------------------------------------------------------------------------------------------------------
50003
+ *
50004
+ * new Mesh(viewer.scene, {
50005
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
50006
+ * startPoint: [3,-2,-1],
50007
+ * endPoint: [5,2,1],
50008
+ * pattern: [0.10],
50009
+ * })),
50010
+ * material: new PhongMaterial(viewer.scene, {
50011
+ * emissive: [1, 1, 1]
50012
+ * })
50013
+ * });
50014
+ *
50015
+ * //------------------------------------------------------------------------------------------------------------------
50016
+ * // Create a mesh with simple 3d line shape with black color and simple dot pattern
50017
+ * //------------------------------------------------------------------------------------------------------------------
50018
+ *
50019
+ * new Mesh(viewer.scene, {
50020
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
50021
+ * startPoint: [5,-2,-1],
50022
+ * endPoint: [7,2,1],
50023
+ * pattern: [0.03],
50024
+ * })),
50025
+ * material: new PhongMaterial(viewer.scene, {
50026
+ * emissive: [0, 0, 0]
50027
+ * })
50028
+ * });
50029
+ * ````
50030
+ *
50031
+ * @function buildLineGeometry
50032
+ * @param {*} [cfg] Configs
50033
+ * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted.
50034
+ * @param {Number[]} [cfg.startPoint] 3D start point (x0, y0, z0).
50035
+ * @param {Number[]} [cfg.endPoint] 3D end point (x1, y1, z1).
50036
+ * @param {Number[]} [cfg.pattern] Lengths of segments that describe a pattern.
50037
+ * @param {Bool} [cfg.extendToEnd] If true: it will try to make sure the line doesn't end up with a gap, as it will
50038
+ * extend the last segment.
50039
+ * @returns {Object} Configuration for a {@link Geometry} subtype.
50040
+ */
50041
+ function buildLineGeometry(cfg = {}) {
50042
+
50043
+ if (cfg.startPoint.length !== 3) {
50044
+ throw "Start point should contain 3 elements in array: x, y and z";
50045
+ }
50046
+ if (cfg.endPoint.length !== 3) {
50047
+ throw "End point should contain 3 elements in array: x, y and z";
50048
+ }
50049
+ let indices = [];
50050
+ let points = [];
50051
+ let x0 = cfg.startPoint[0]; let y0 = cfg.startPoint[1]; let z0 = cfg.startPoint[2];
50052
+ let x1 = cfg.endPoint[0]; let y1 = cfg.endPoint[1]; let z1 = cfg.endPoint[2];
50053
+ let lineLength = Math.sqrt((x1- x0)**2 + (y1 - y0)**2 + (z1 - z0)**2);
50054
+ let normalizedDirectionVectorOfLine = [(x1-x0)/lineLength, (y1-y0)/lineLength, (z1-z0)/lineLength];
50055
+
50056
+ if (!cfg.pattern) {
50057
+ indices.push(0);
50058
+ indices.push(1);
50059
+ points.push(x0, y0, z0, x1, y1, z1);
50060
+ }
50061
+ else {
50062
+ let patternsNumber = cfg.pattern.length;
50063
+ let gap = false;
50064
+ let segmentFilled = 0.0;
50065
+ let idOfCurrentPatternLength = 0;
50066
+ let pointIndicesCounter = 0;
50067
+ let currentStartPoint = [x0, y0, z0];
50068
+ let currentPatternLength = cfg.pattern[idOfCurrentPatternLength];
50069
+ points.push(currentStartPoint[0], currentStartPoint[1], currentStartPoint[2]);
50070
+
50071
+ while (currentPatternLength <= (lineLength - segmentFilled)) {
50072
+ let vectorFromCurrentStartPointToCurrentEndPoint = [
50073
+ normalizedDirectionVectorOfLine[0] * currentPatternLength,
50074
+ normalizedDirectionVectorOfLine[1] * currentPatternLength,
50075
+ normalizedDirectionVectorOfLine[2] * currentPatternLength,
50076
+ ];
50077
+ let currentEndPoint = [
50078
+ currentStartPoint[0] + vectorFromCurrentStartPointToCurrentEndPoint[0],
50079
+ currentStartPoint[1] + vectorFromCurrentStartPointToCurrentEndPoint[1],
50080
+ currentStartPoint[2] + vectorFromCurrentStartPointToCurrentEndPoint[2],
50081
+ ];
50082
+
50083
+ points.push(currentEndPoint[0], currentEndPoint[1], currentEndPoint[2]);
50084
+
50085
+ if (!gap) {
50086
+ indices.push(pointIndicesCounter);
50087
+ indices.push(pointIndicesCounter + 1);
50088
+ }
50089
+ gap = !gap;
50090
+
50091
+ pointIndicesCounter += 1;
50092
+ currentStartPoint = currentEndPoint;
50093
+ idOfCurrentPatternLength += 1;
50094
+ if (idOfCurrentPatternLength >= patternsNumber) {
50095
+ idOfCurrentPatternLength = 0;
50096
+ }
50097
+ segmentFilled += currentPatternLength;
50098
+ currentPatternLength = cfg.pattern[idOfCurrentPatternLength];
50099
+ }
50100
+
50101
+ if (cfg.extendToEnd) {
50102
+ points.push(x1, y1, z1);
50103
+ indices.push(indices.length - 2);
50104
+ indices.push(indices.length - 1);
50105
+ }
50106
+ }
50107
+
50108
+ return utils.apply(cfg, {
50109
+ primitive: "lines",
50110
+ positions: points,
50111
+ indices: indices,
50112
+ });
50113
+ }
50114
+
49797
50115
  /**
49798
50116
  * A plane-shaped 3D object containing a bitmap image.
49799
50117
  *
@@ -86729,8 +87047,6 @@ class DistanceMeasurement extends Component {
86729
87047
  this._eventSubs = {};
86730
87048
 
86731
87049
  var scene = this.plugin.viewer.scene;
86732
- this._originMarker = new Marker(scene, cfg.origin);
86733
- this._targetMarker = new Marker(scene, cfg.target);
86734
87050
 
86735
87051
  this._originWorld = math.vec3();
86736
87052
  this._targetWorld = math.vec3();
@@ -86776,7 +87092,7 @@ class DistanceMeasurement extends Component {
86776
87092
  this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new WheelEvent('wheel', event));
86777
87093
  };
86778
87094
 
86779
- this._originDot = new Dot(this._container, {
87095
+ this._originDot = new Dot3D(scene, cfg.origin, this._container, {
86780
87096
  fillColor: this._color,
86781
87097
  zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined,
86782
87098
  onMouseOver,
@@ -86788,7 +87104,7 @@ class DistanceMeasurement extends Component {
86788
87104
  onContextMenu
86789
87105
  });
86790
87106
 
86791
- this._targetDot = new Dot(this._container, {
87107
+ this._targetDot = new Dot3D(scene, cfg.target, this._container, {
86792
87108
  fillColor: this._color,
86793
87109
  zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined,
86794
87110
  onMouseOver,
@@ -86935,13 +87251,13 @@ class DistanceMeasurement extends Component {
86935
87251
  this._labelsOnWires = false;
86936
87252
  this._clickable = false;
86937
87253
 
86938
- this._originMarker.on("worldPos", (value) => {
87254
+ this._originDot.on("worldPos", (value) => {
86939
87255
  this._originWorld.set(value || [0,0,0]);
86940
87256
  this._wpDirty = true;
86941
87257
  this._needUpdate(0); // No lag
86942
87258
  });
86943
87259
 
86944
- this._targetMarker.on("worldPos", (value) => {
87260
+ this._targetDot.on("worldPos", (value) => {
86945
87261
  this._targetWorld.set(value || [0,0,0]);
86946
87262
  this._wpDirty = true;
86947
87263
  this._needUpdate(0); // No lag
@@ -87103,8 +87419,8 @@ class DistanceMeasurement extends Component {
87103
87419
  }
87104
87420
 
87105
87421
  const near = -0.3;
87106
- const vpz1 = this._originMarker.viewPos[2];
87107
- const vpz2 = this._targetMarker.viewPos[2];
87422
+ const vpz1 = this._originDot.viewPos[2];
87423
+ const vpz2 = this._targetDot.viewPos[2];
87108
87424
 
87109
87425
  if (vpz1 > near || vpz2 > near) {
87110
87426
 
@@ -87153,9 +87469,6 @@ class DistanceMeasurement extends Component {
87153
87469
  j += 2;
87154
87470
  }
87155
87471
 
87156
- this._originDot.setPos(cp[0], cp[1]);
87157
- this._targetDot.setPos(cp[6], cp[7]);
87158
-
87159
87472
  this._lengthWire.setStartAndEnd(cp[0], cp[1], cp[6], cp[7]);
87160
87473
 
87161
87474
  this._xAxisWire.setStartAndEnd(cp[0], cp[1], cp[2], cp[3]);
@@ -87297,21 +87610,21 @@ class DistanceMeasurement extends Component {
87297
87610
  }
87298
87611
 
87299
87612
  /**
87300
- * Gets the origin {@link Marker}.
87613
+ * Gets the origin {@link Dot3D}.
87301
87614
  *
87302
- * @type {Marker}
87615
+ * @type {Dot3D}
87303
87616
  */
87304
87617
  get origin() {
87305
- return this._originMarker;
87618
+ return this._originDot;
87306
87619
  }
87307
87620
 
87308
87621
  /**
87309
- * Gets the target {@link Marker}.
87622
+ * Gets the target {@link Dot3D}.
87310
87623
  *
87311
- * @type {Marker}
87624
+ * @type {Dot3D}
87312
87625
  */
87313
87626
  get target() {
87314
- return this._targetMarker;
87627
+ return this._targetDot;
87315
87628
  }
87316
87629
 
87317
87630
  /**
@@ -87380,7 +87693,7 @@ class DistanceMeasurement extends Component {
87380
87693
  }
87381
87694
 
87382
87695
  /**
87383
- * Sets if the origin {@link Marker} is visible.
87696
+ * Sets if the origin {@link Dot3D} is visible.
87384
87697
  *
87385
87698
  * @type {Boolean}
87386
87699
  */
@@ -87391,7 +87704,7 @@ class DistanceMeasurement extends Component {
87391
87704
  }
87392
87705
 
87393
87706
  /**
87394
- * Gets if the origin {@link Marker} is visible.
87707
+ * Gets if the origin {@link Dot3D} is visible.
87395
87708
  *
87396
87709
  * @type {Boolean}
87397
87710
  */
@@ -87400,7 +87713,7 @@ class DistanceMeasurement extends Component {
87400
87713
  }
87401
87714
 
87402
87715
  /**
87403
- * Sets if the target {@link Marker} is visible.
87716
+ * Sets if the target {@link Dot3D} is visible.
87404
87717
  *
87405
87718
  * @type {Boolean}
87406
87719
  */
@@ -87411,7 +87724,7 @@ class DistanceMeasurement extends Component {
87411
87724
  }
87412
87725
 
87413
87726
  /**
87414
- * Gets if the target {@link Marker} is visible.
87727
+ * Gets if the target {@link Dot3D} is visible.
87415
87728
  *
87416
87729
  * @type {Boolean}
87417
87730
  */
@@ -89699,11 +90012,30 @@ class DistanceMeasurementEditControl extends Component {
89699
90012
  viewer: viewer,
89700
90013
  handleMouseEvents: handleMouseEvents,
89701
90014
  handleTouchEvents: handleTouchEvents,
89702
- snapping: cfg.snapping,
89703
90015
  pointerLens: cfg.pointerLens,
89704
- color: measurement.color,
89705
- markers: [ measurement.origin, measurement.target ],
89706
- onEdit: () => this.fire("edited")
90016
+ dots: [ measurement.origin, measurement.target ],
90017
+ ray2WorldPos: (orig, dir, canvasPos) => {
90018
+ const tryPickWorldPos = snap => {
90019
+ const pickResult = viewer.scene.pick({
90020
+ canvasPos: canvasPos,
90021
+ snapToEdge: snap,
90022
+ snapToVertex: snap,
90023
+ pickSurface: true // <<------ This causes picking to find the intersection point on the entity
90024
+ });
90025
+
90026
+ // If - when snapping - no pick found, then try w/o snapping
90027
+ return (pickResult && pickResult.worldPos) ? pickResult.worldPos : (snap && tryPickWorldPos(false));
90028
+ };
90029
+
90030
+ return tryPickWorldPos(!!cfg.snapping);
90031
+ },
90032
+ onEnd: (initPos, dot) => {
90033
+ const changed = ! math.compareVec3(initPos, dot.worldPos);
90034
+ if (changed) {
90035
+ this.fire("edited");
90036
+ }
90037
+ return changed;
90038
+ }
89707
90039
  });
89708
90040
 
89709
90041
  const destroyCb = measurement.on("destroyed", cleanup);
@@ -139876,26 +140208,19 @@ class ZonesPolysurfaceTouchControl extends Component {
139876
140208
 
139877
140209
  class ZoneEditControl extends Component {
139878
140210
  constructor(zone, cfg, handleMouseEvents, handleTouchEvents) {
139879
- super(zone.plugin.viewer.scene);
139880
- const self = this;
140211
+ const viewer = zone.plugin.viewer;
140212
+ const scene = viewer.scene;
140213
+ super(scene);
139881
140214
 
139882
140215
  const altitude = zone._geometry.altitude;
139883
- const pointerLens = cfg && cfg.pointerLens;
139884
- const updatePointerLens = (pointerLens
139885
- ? function(canvasPos) {
139886
- pointerLens.visible = !! canvasPos;
139887
- if (canvasPos)
139888
- {
139889
- pointerLens.canvasPos = canvasPos;
139890
- }
139891
- }
139892
- : () => { });
139893
140216
 
139894
140217
  const dots = zone._geometry.planeCoordinates.map(planeCoord => {
139895
- let initWorldPos, initPlaneCoord;
139896
- const setPlaneCoord = function(coord) {
139897
- planeCoord[0] = coord[0];
139898
- planeCoord[1] = coord[1];
140218
+ const dotParent = scene.canvas.canvas.ownerDocument.body;
140219
+ const dot = new Dot3D(scene, {}, dotParent, { fillColor: zone._color });
140220
+ dot.worldPos = math.vec3([ planeCoord[0], altitude, planeCoord[1] ]);
140221
+ dot.on("worldPos", function() {
140222
+ planeCoord[0] = dot.worldPos[0];
140223
+ planeCoord[1] = dot.worldPos[2];
139899
140224
  try {
139900
140225
  zone._rebuildMesh();
139901
140226
  } catch (e) {
@@ -139904,46 +140229,29 @@ class ZoneEditControl extends Component {
139904
140229
  zone._zoneMesh = null;
139905
140230
  }
139906
140231
  }
139907
- };
139908
-
139909
- const dot = createDraggableDot3D({
139910
- handleMouseEvents: handleMouseEvents,
139911
- handleTouchEvents: handleTouchEvents,
139912
- viewer: zone.plugin.viewer,
139913
- worldPos: math.vec3([ planeCoord[0], altitude, planeCoord[1] ]),
139914
- color: zone._color,
139915
- ray2WorldPos: (orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir),
139916
- onStart: () => {
139917
- initWorldPos = dot.getWorldPos().slice();
139918
- initPlaneCoord = planeCoord.slice();
139919
- set_other_dots_active(false, dot);
139920
- },
139921
- onMove: (canvasPos, worldPos) => {
139922
- updatePointerLens(canvasPos);
139923
- setPlaneCoord([ worldPos[0], worldPos[2] ]);
139924
- },
139925
- onEnd: () => {
139926
- if (zone._zoneMesh)
139927
- {
139928
- self.fire("edited");
139929
- }
139930
- else
139931
- {
139932
- dot.setWorldPos(initWorldPos);
139933
- setPlaneCoord(initPlaneCoord);
139934
- }
139935
- updatePointerLens(null);
139936
- set_other_dots_active(true, dot);
139937
- }
139938
140232
  });
139939
140233
  return dot;
139940
140234
  });
139941
- const set_other_dots_active = (active, dot) => dots.forEach(d => (d !== dot) && d.setActive(active));
139942
- set_other_dots_active(true);
140235
+
140236
+ const cleanupDrag = activateDraggableDots({
140237
+ viewer: viewer,
140238
+ handleMouseEvents: handleMouseEvents,
140239
+ handleTouchEvents: handleTouchEvents,
140240
+ pointerLens: cfg && cfg.pointerLens,
140241
+ dots: dots,
140242
+ ray2WorldPos: (orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir),
140243
+ onEnd: (initPos, dot) => {
140244
+ if (zone._zoneMesh)
140245
+ {
140246
+ this.fire("edited");
140247
+ }
140248
+ return !! zone._zoneMesh;
140249
+ }
140250
+ });
139943
140251
 
139944
140252
  const cleanup = function() {
139945
- dots.forEach(m => m.destroy());
139946
- updatePointerLens(null);
140253
+ cleanupDrag();
140254
+ dots.forEach(d => d.destroy());
139947
140255
  };
139948
140256
 
139949
140257
  const destroyCb = zone.on("destroyed", cleanup);
@@ -140337,6 +140645,7 @@ exports.buildBoxLinesGeometry = buildBoxLinesGeometry;
140337
140645
  exports.buildBoxLinesGeometryFromAABB = buildBoxLinesGeometryFromAABB;
140338
140646
  exports.buildCylinderGeometry = buildCylinderGeometry;
140339
140647
  exports.buildGridGeometry = buildGridGeometry;
140648
+ exports.buildLineGeometry = buildLineGeometry;
140340
140649
  exports.buildPlaneGeometry = buildPlaneGeometry;
140341
140650
  exports.buildPolylineGeometry = buildPolylineGeometry;
140342
140651
  exports.buildPolylineGeometryFromCurve = buildPolylineGeometryFromCurve;