@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.
@@ -9525,6 +9525,239 @@ class Plugin {
9525
9525
  }
9526
9526
  }
9527
9527
 
9528
+ const os = {
9529
+ isIphoneSafari() {
9530
+ const userAgent = window.navigator.userAgent;
9531
+ const isIphone = /iPhone/i.test(userAgent);
9532
+ const isSafari = /Safari/i.test(userAgent) && !/Chrome/i.test(userAgent);
9533
+
9534
+ return isIphone && isSafari;
9535
+ }
9536
+ };
9537
+
9538
+ /** @private */
9539
+ class Dot {
9540
+
9541
+ constructor(parentElement, cfg = {}) {
9542
+
9543
+ this._highlightClass = "viewer-ruler-dot-highlighted";
9544
+
9545
+ this._x = 0;
9546
+ this._y = 0;
9547
+
9548
+ this._dot = document.createElement('div');
9549
+ this._dot.className += this._dot.className ? ' viewer-ruler-dot' : 'viewer-ruler-dot';
9550
+
9551
+ this._dotClickable = document.createElement('div');
9552
+ this._dotClickable.className += this._dotClickable.className ? ' viewer-ruler-dot-clickable' : 'viewer-ruler-dot-clickable';
9553
+
9554
+ this._visible = !!cfg.visible;
9555
+ this._culled = false;
9556
+
9557
+ var dot = this._dot;
9558
+ var dotStyle = dot.style;
9559
+ dotStyle["border-radius"] = 25 + "px";
9560
+ dotStyle.border = "solid 2px white";
9561
+ dotStyle.background = "lightgreen";
9562
+ dotStyle.position = "absolute";
9563
+ dotStyle["z-index"] = cfg.zIndex === undefined ? "40000005" : cfg.zIndex ;
9564
+ dotStyle.width = 8 + "px";
9565
+ dotStyle.height = 8 + "px";
9566
+ dotStyle.visibility = cfg.visible !== false ? "visible" : "hidden";
9567
+ dotStyle.top = 0 + "px";
9568
+ dotStyle.left = 0 + "px";
9569
+ dotStyle["box-shadow"] = "0 2px 5px 0 #182A3D;";
9570
+ dotStyle["opacity"] = 1.0;
9571
+ dotStyle["pointer-events"] = "none";
9572
+ if (cfg.onContextMenu) ;
9573
+ parentElement.appendChild(dot);
9574
+
9575
+ var dotClickable = this._dotClickable;
9576
+ var dotClickableStyle = dotClickable.style;
9577
+ dotClickableStyle["border-radius"] = 35 + "px";
9578
+ dotClickableStyle.border = "solid 10px white";
9579
+ dotClickableStyle.position = "absolute";
9580
+ dotClickableStyle["z-index"] = cfg.zIndex === undefined ? "40000007" : (cfg.zIndex + 1);
9581
+ dotClickableStyle.width = 8 + "px";
9582
+ dotClickableStyle.height = 8 + "px";
9583
+ dotClickableStyle.visibility = "visible";
9584
+ dotClickableStyle.top = 0 + "px";
9585
+ dotClickableStyle.left = 0 + "px";
9586
+ dotClickableStyle["opacity"] = 0.0;
9587
+ dotClickableStyle["pointer-events"] = "none";
9588
+ if (cfg.onContextMenu) ;
9589
+ parentElement.appendChild(dotClickable);
9590
+
9591
+ dotClickable.addEventListener('click', (event) => {
9592
+ parentElement.dispatchEvent(new MouseEvent('mouseover', event));
9593
+ });
9594
+
9595
+ if (cfg.onMouseOver) {
9596
+ dotClickable.addEventListener('mouseover', (event) => {
9597
+ cfg.onMouseOver(event, this);
9598
+ parentElement.dispatchEvent(new MouseEvent('mouseover', event));
9599
+ });
9600
+ }
9601
+
9602
+ if (cfg.onMouseLeave) {
9603
+ dotClickable.addEventListener('mouseleave', (event) => {
9604
+ cfg.onMouseLeave(event, this);
9605
+ });
9606
+ }
9607
+
9608
+ if (cfg.onMouseWheel) {
9609
+ dotClickable.addEventListener('wheel', (event) => {
9610
+ cfg.onMouseWheel(event, this);
9611
+ });
9612
+ }
9613
+
9614
+ if (cfg.onMouseDown) {
9615
+ dotClickable.addEventListener('mousedown', (event) => {
9616
+ cfg.onMouseDown(event, this);
9617
+ });
9618
+ }
9619
+
9620
+ if (cfg.onMouseUp) {
9621
+ dotClickable.addEventListener('mouseup', (event) => {
9622
+ cfg.onMouseUp(event, this);
9623
+ });
9624
+ }
9625
+
9626
+ if (cfg.onMouseMove) {
9627
+ dotClickable.addEventListener('mousemove', (event) => {
9628
+ cfg.onMouseMove(event, this);
9629
+ });
9630
+ }
9631
+
9632
+ if (cfg.onTouchstart) {
9633
+ dotClickable.addEventListener('touchstart', (event) => {
9634
+ cfg.onTouchstart(event, this);
9635
+ });
9636
+ }
9637
+
9638
+ if (cfg.onTouchmove) {
9639
+ dotClickable.addEventListener('touchmove', (event) => {
9640
+ cfg.onTouchmove(event, this);
9641
+ });
9642
+ }
9643
+
9644
+ if (cfg.onTouchend) {
9645
+ dotClickable.addEventListener('touchend', (event) => {
9646
+ cfg.onTouchend(event, this);
9647
+ });
9648
+ }
9649
+
9650
+ if (cfg.onContextMenu) {
9651
+ if(os.isIphoneSafari()){
9652
+ dotClickable.addEventListener('touchstart', (event) => {
9653
+ event.preventDefault();
9654
+ if(this._timeout){
9655
+ clearTimeout(this._timeout);
9656
+ this._timeout = null;
9657
+ }
9658
+ this._timeout = setTimeout(() => {
9659
+ event.clientX = event.touches[0].clientX;
9660
+ event.clientY = event.touches[0].clientY;
9661
+ cfg.onContextMenu(event, this);
9662
+ clearTimeout(this._timeout);
9663
+ this._timeout = null;
9664
+ }, 500);
9665
+ });
9666
+
9667
+ dotClickable.addEventListener('touchend', (event) => {
9668
+ event.preventDefault();
9669
+ //stops short touches from calling the timeout
9670
+ if(this._timeout) {
9671
+ clearTimeout(this._timeout);
9672
+ this._timeout = null;
9673
+ }
9674
+ } );
9675
+
9676
+ }
9677
+ else {
9678
+ dotClickable.addEventListener('contextmenu', (event) => {
9679
+ console.log(event);
9680
+ cfg.onContextMenu(event, this);
9681
+ event.preventDefault();
9682
+ event.stopPropagation();
9683
+ console.log("Label context menu");
9684
+ });
9685
+ }
9686
+
9687
+ }
9688
+
9689
+ this.setPos(cfg.x || 0, cfg.y || 0);
9690
+ this.setFillColor(cfg.fillColor);
9691
+ this.setBorderColor(cfg.borderColor);
9692
+ }
9693
+
9694
+ setPos(x, y) {
9695
+ this._x = x;
9696
+ this._y = y;
9697
+ var dotStyle = this._dot.style;
9698
+ dotStyle["left"] = (Math.round(x) - 4) + 'px';
9699
+ dotStyle["top"] = (Math.round(y) - 4) + 'px';
9700
+
9701
+ var dotClickableStyle = this._dotClickable.style;
9702
+ dotClickableStyle["left"] = (Math.round(x) - 9) + 'px';
9703
+ dotClickableStyle["top"] = (Math.round(y) - 9) + 'px';
9704
+ }
9705
+
9706
+ setFillColor(color) {
9707
+ this._dot.style.background = color || "lightgreen";
9708
+ }
9709
+
9710
+ setBorderColor(color) {
9711
+ this._dot.style.border = "solid 2px" + (color || "black");
9712
+ }
9713
+
9714
+ setOpacity(opacity) {
9715
+ this._dot.style.opacity = opacity;
9716
+ }
9717
+
9718
+ setVisible(visible) {
9719
+ if (this._visible === visible) {
9720
+ return;
9721
+ }
9722
+ this._visible = !!visible;
9723
+ this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden";
9724
+ }
9725
+
9726
+ setCulled(culled) {
9727
+ if (this._culled === culled) {
9728
+ return;
9729
+ }
9730
+ this._culled = !!culled;
9731
+ this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden";
9732
+ }
9733
+
9734
+ setClickable(clickable) {
9735
+ this._dotClickable.style["pointer-events"] = (clickable) ? "all" : "none";
9736
+ }
9737
+
9738
+ setHighlighted(highlighted) {
9739
+ if (this._highlighted === highlighted) {
9740
+ return;
9741
+ }
9742
+ this._highlighted = !!highlighted;
9743
+ if (this._highlighted) {
9744
+ this._dot.classList.add(this._highlightClass);
9745
+ } else {
9746
+ this._dot.classList.remove(this._highlightClass);
9747
+ }
9748
+ }
9749
+
9750
+ destroy() {
9751
+ this.setVisible(false);
9752
+ if (this._dot.parentElement) {
9753
+ this._dot.parentElement.removeChild(this._dot);
9754
+ }
9755
+ if (this._dotClickable.parentElement) {
9756
+ this._dotClickable.parentElement.removeChild(this._dotClickable);
9757
+ }
9758
+ }
9759
+ }
9760
+
9528
9761
  const tempVec3a$L = math.vec3();
9529
9762
 
9530
9763
  /**
@@ -10585,11 +10818,17 @@ class Marker extends Component {
10585
10818
  return;
10586
10819
  }
10587
10820
  if (this._onEntityDestroyed !== null) {
10588
- this._entity.model.off(this._onEntityDestroyed);
10821
+ if (this._entity.model) {
10822
+ this._entity.model.off(this._onEntityDestroyed);
10823
+ } else {
10824
+ this._entity.off(this._onEntityDestroyed);
10825
+ }
10589
10826
  this._onEntityDestroyed = null;
10590
10827
  }
10591
10828
  if (this._onEntityModelDestroyed !== null) {
10592
- this._entity.model.off(this._onEntityModelDestroyed);
10829
+ if (this._entity.model) {
10830
+ this._entity.model.off(this._onEntityModelDestroyed);
10831
+ }
10593
10832
  this._onEntityModelDestroyed = null;
10594
10833
  }
10595
10834
  }
@@ -10601,7 +10840,7 @@ class Marker extends Component {
10601
10840
  this._onEntityModelDestroyed = null;
10602
10841
  });
10603
10842
  } else {
10604
- this._onEntityDestroyed = this._entity.model.on("destroyed", () => {
10843
+ this._onEntityDestroyed = this._entity.on("destroyed", () => {
10605
10844
  this._entity = null;
10606
10845
  this._onEntityDestroyed = null;
10607
10846
  });
@@ -10770,15 +11009,286 @@ class Marker extends Component {
10770
11009
  }
10771
11010
  }
10772
11011
 
10773
- const os = {
10774
- isIphoneSafari() {
10775
- const userAgent = window.navigator.userAgent;
10776
- const isIphone = /iPhone/i.test(userAgent);
10777
- const isSafari = /Safari/i.test(userAgent) && !/Chrome/i.test(userAgent);
11012
+ const nop = () => { };
10778
11013
 
10779
- return isIphone && isSafari;
11014
+ function transformToNode(from, to, vec) {
11015
+ const fromRec = from.getBoundingClientRect();
11016
+ const toRec = to.getBoundingClientRect();
11017
+ vec[0] += fromRec.left - toRec.left;
11018
+ vec[1] += fromRec.top - toRec.top;
11019
+ }
11020
+ class Dot3D extends Marker {
11021
+ constructor(scene, markerCfg, parentElement, cfg = {}) {
11022
+ super(scene, markerCfg);
11023
+
11024
+ const handler = (cfgEvent, componentEvent) => {
11025
+ return event => {
11026
+ if (cfgEvent) {
11027
+ cfgEvent(event);
11028
+ }
11029
+ this.fire(componentEvent, event, true);
11030
+ };
11031
+ };
11032
+ this._dot = new Dot(parentElement, {
11033
+ fillColor: cfg.fillColor,
11034
+ zIndex: cfg.zIndex,
11035
+ onMouseOver: handler(cfg.onMouseOver, "mouseover"),
11036
+ onMouseLeave: handler(cfg.onMouseLeave, "mouseleave"),
11037
+ onMouseWheel: handler(cfg.onMouseWheel, "wheel"),
11038
+ onMouseDown: handler(cfg.onMouseDown, "mousedown"),
11039
+ onMouseUp: handler(cfg.onMouseUp, "mouseup"),
11040
+ onMouseMove: handler(cfg.onMouseMove, "mousemove"),
11041
+ onTouchstart: handler(cfg.onTouchstart, "touchstart"),
11042
+ onTouchmove: handler(cfg.onTouchmove, "touchmove"),
11043
+ onTouchend: handler(cfg.onTouchend, "touchend"),
11044
+ onContextMenu: handler(cfg.onContextMenu, "contextmenu")
11045
+ });
11046
+
11047
+ const updateDotPos = () => {
11048
+ const pos = this.canvasPos.slice();
11049
+ transformToNode(scene.canvas.canvas, parentElement, pos);
11050
+ this._dot.setPos(pos[0], pos[1]);
11051
+ };
11052
+
11053
+ this.on("worldPos", updateDotPos);
11054
+
11055
+ const onViewMatrix = scene.camera.on("viewMatrix", updateDotPos);
11056
+ const onProjMatrix = scene.camera.on("projMatrix", updateDotPos);
11057
+ this._cleanup = () => {
11058
+ scene.camera.off(onViewMatrix);
11059
+ scene.camera.off(onProjMatrix);
11060
+ this._dot.destroy();
11061
+ };
10780
11062
  }
10781
- };
11063
+
11064
+ setClickable(value) {
11065
+ this._dot.setClickable(value);
11066
+ }
11067
+
11068
+ setCulled(value) {
11069
+ this._dot.setCulled(value);
11070
+ }
11071
+
11072
+ setFillColor(value) {
11073
+ this._dot.setFillColor(value);
11074
+ }
11075
+
11076
+ setHighlighted(value) {
11077
+ this._dot.setHighlighted(value);
11078
+ }
11079
+
11080
+ setOpacity(value) {
11081
+ this._dot.setOpacity(value);
11082
+ }
11083
+
11084
+ setVisible(value) {
11085
+ this._dot.setVisible(value);
11086
+ }
11087
+
11088
+ destroy() {
11089
+ this._cleanup();
11090
+ super.destroy();
11091
+ }
11092
+
11093
+ }
11094
+
11095
+ function activateDraggableDot(dot, cfg) {
11096
+ const extractCFG = function(propName, defaultValue) {
11097
+ if (propName in cfg) {
11098
+ return cfg[propName];
11099
+ } else if (defaultValue !== undefined) {
11100
+ return defaultValue;
11101
+ } else {
11102
+ throw "config missing: " + propName;
11103
+ }
11104
+ };
11105
+
11106
+ const viewer = extractCFG("viewer");
11107
+ const ray2WorldPos = extractCFG("ray2WorldPos");
11108
+ const handleMouseEvents = extractCFG("handleMouseEvents", false);
11109
+ const handleTouchEvents = extractCFG("handleTouchEvents", false);
11110
+ const onStart = extractCFG("onStart", nop);
11111
+ const onMove = extractCFG("onMove", nop);
11112
+ const onEnd = extractCFG("onEnd", nop);
11113
+
11114
+ const scene = viewer.scene;
11115
+ const canvas = scene.canvas.canvas;
11116
+
11117
+ const pickWorldPos = canvasPos => {
11118
+ const origin = math.vec3();
11119
+ const direction = math.vec3();
11120
+ math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
11121
+ return ray2WorldPos(origin, direction, canvasPos);
11122
+ };
11123
+
11124
+ const onChange = event => {
11125
+ const canvasPos = math.vec2([ event.clientX, event.clientY ]);
11126
+ transformToNode(canvas.ownerDocument.body, canvas, canvasPos);
11127
+ onMove(canvasPos, pickWorldPos(canvasPos));
11128
+ };
11129
+
11130
+ let currentDrag = null;
11131
+
11132
+ const onDragMove = function(event) {
11133
+ const e = currentDrag.matchesEvent(event);
11134
+ if (e)
11135
+ {
11136
+ onChange(e);
11137
+ }
11138
+ };
11139
+
11140
+ const onDragEnd = function(event) {
11141
+ const e = currentDrag.matchesEvent(event);
11142
+ if (e)
11143
+ {
11144
+ dot.setOpacity(idleOpacity);
11145
+ currentDrag.cleanup();
11146
+ onChange(e);
11147
+ onEnd();
11148
+ }
11149
+ };
11150
+
11151
+ const startDrag = function(matchesEvent, cleanupHandlers) {
11152
+ if (currentDrag) {
11153
+ currentDrag.cleanup();
11154
+ }
11155
+
11156
+ dot.setOpacity(1.0);
11157
+ dot.setClickable(false);
11158
+ viewer.cameraControl.active = false;
11159
+
11160
+ currentDrag = {
11161
+ matchesEvent: matchesEvent,
11162
+ cleanup: function() {
11163
+ currentDrag = null;
11164
+ dot.setClickable(true);
11165
+ viewer.cameraControl.active = true;
11166
+ cleanupHandlers();
11167
+ }
11168
+ };
11169
+
11170
+ onStart();
11171
+ };
11172
+
11173
+ const cleanupDotHandlers = [ ];
11174
+ const dot_on = function(event, callback) {
11175
+ const id = dot.on(event, callback);
11176
+ cleanupDotHandlers.push(() => dot.off(id));
11177
+ };
11178
+
11179
+ if (handleMouseEvents)
11180
+ {
11181
+ dot_on("mouseover", () => (! currentDrag) && dot.setOpacity(1.0));
11182
+ dot_on("mouseleave", () => (! currentDrag) && dot.setOpacity(idleOpacity));
11183
+ dot_on("mousedown", event => {
11184
+ if (event.which === 1)
11185
+ {
11186
+ canvas.addEventListener("mousemove", onDragMove);
11187
+ canvas.addEventListener("mouseup", onDragEnd);
11188
+ startDrag(
11189
+ event => (event.which === 1) && event,
11190
+ () => {
11191
+ canvas.removeEventListener("mousemove", onDragMove);
11192
+ canvas.removeEventListener("mouseup", onDragEnd);
11193
+ });
11194
+ }
11195
+ });
11196
+ }
11197
+
11198
+ if (handleTouchEvents)
11199
+ {
11200
+ let touchStartId;
11201
+ dot_on("touchstart", event => {
11202
+ event.preventDefault();
11203
+ if (event.touches.length === 1)
11204
+ {
11205
+ touchStartId = event.touches[0].identifier;
11206
+ startDrag(
11207
+ event => [...event.changedTouches].find(e => e.identifier === touchStartId),
11208
+ () => { touchStartId = null; });
11209
+ }
11210
+ });
11211
+ dot_on("touchmove", event => {
11212
+ event.preventDefault();
11213
+ onDragMove(event);
11214
+ });
11215
+ dot_on("touchend", event => {
11216
+ event.preventDefault();
11217
+ onDragEnd(event);
11218
+ });
11219
+ }
11220
+
11221
+ const idleOpacity = 0.8;
11222
+ dot.setOpacity(idleOpacity);
11223
+
11224
+ return function() {
11225
+ currentDrag && currentDrag.cleanup();
11226
+ cleanupDotHandlers.forEach(c => c());
11227
+ dot.setOpacity(1.0);
11228
+ };
11229
+ }
11230
+ function activateDraggableDots(cfg) {
11231
+ const extractCFG = function(propName, defaultValue) {
11232
+ if (propName in cfg) {
11233
+ return cfg[propName];
11234
+ } else if (defaultValue !== undefined) {
11235
+ return defaultValue;
11236
+ } else {
11237
+ throw "config missing: " + propName;
11238
+ }
11239
+ };
11240
+
11241
+ const viewer = extractCFG("viewer");
11242
+ const handleMouseEvents = extractCFG("handleMouseEvents", false);
11243
+ const handleTouchEvents = extractCFG("handleTouchEvents", false);
11244
+ const pointerLens = extractCFG("pointerLens", null);
11245
+ const dots = extractCFG("dots");
11246
+ const ray2WorldPos = extractCFG("ray2WorldPos");
11247
+ const onEnd = extractCFG("onEnd", nop);
11248
+
11249
+ const updatePointerLens = (pointerLens
11250
+ ? function(canvasPos) {
11251
+ pointerLens.visible = !! canvasPos;
11252
+ if (canvasPos)
11253
+ {
11254
+ pointerLens.canvasPos = canvasPos;
11255
+ }
11256
+ }
11257
+ : () => { });
11258
+
11259
+ const cleanups = dots.map(dot => {
11260
+ let initPos;
11261
+ return activateDraggableDot(dot, {
11262
+ handleMouseEvents: handleMouseEvents,
11263
+ handleTouchEvents: handleTouchEvents,
11264
+ viewer: viewer,
11265
+ ray2WorldPos: (orig, dir, canvasPos) => (ray2WorldPos(orig, dir, canvasPos) || initPos),
11266
+ onStart: () => {
11267
+ initPos = dot.worldPos.slice();
11268
+ setOtherDotsActive(false, dot);
11269
+ },
11270
+ onMove: (canvasPos, worldPos) => {
11271
+ updatePointerLens(canvasPos);
11272
+ dot.worldPos = worldPos;
11273
+ },
11274
+ onEnd: () => {
11275
+ if (! onEnd(initPos, dot)) {
11276
+ dot.worldPos = initPos;
11277
+ }
11278
+ updatePointerLens(null);
11279
+ setOtherDotsActive(true, dot);
11280
+ }
11281
+ });
11282
+ });
11283
+
11284
+ const setOtherDotsActive = (active, dot) => dots.forEach(d => (d !== dot) && d.setClickable(active));
11285
+ setOtherDotsActive(true);
11286
+
11287
+ return function() {
11288
+ cleanups.forEach(c => c());
11289
+ updatePointerLens(null);
11290
+ };
11291
+ }
10782
11292
 
10783
11293
  /** @private */
10784
11294
  class Wire {
@@ -11027,229 +11537,6 @@ class Wire {
11027
11537
  }
11028
11538
  }
11029
11539
 
11030
- /** @private */
11031
- class Dot {
11032
-
11033
- constructor(parentElement, cfg = {}) {
11034
-
11035
- this._highlightClass = "viewer-ruler-dot-highlighted";
11036
-
11037
- this._x = 0;
11038
- this._y = 0;
11039
-
11040
- this._dot = document.createElement('div');
11041
- this._dot.className += this._dot.className ? ' viewer-ruler-dot' : 'viewer-ruler-dot';
11042
-
11043
- this._dotClickable = document.createElement('div');
11044
- this._dotClickable.className += this._dotClickable.className ? ' viewer-ruler-dot-clickable' : 'viewer-ruler-dot-clickable';
11045
-
11046
- this._visible = !!cfg.visible;
11047
- this._culled = false;
11048
-
11049
- var dot = this._dot;
11050
- var dotStyle = dot.style;
11051
- dotStyle["border-radius"] = 25 + "px";
11052
- dotStyle.border = "solid 2px white";
11053
- dotStyle.background = "lightgreen";
11054
- dotStyle.position = "absolute";
11055
- dotStyle["z-index"] = cfg.zIndex === undefined ? "40000005" : cfg.zIndex ;
11056
- dotStyle.width = 8 + "px";
11057
- dotStyle.height = 8 + "px";
11058
- dotStyle.visibility = cfg.visible !== false ? "visible" : "hidden";
11059
- dotStyle.top = 0 + "px";
11060
- dotStyle.left = 0 + "px";
11061
- dotStyle["box-shadow"] = "0 2px 5px 0 #182A3D;";
11062
- dotStyle["opacity"] = 1.0;
11063
- dotStyle["pointer-events"] = "none";
11064
- if (cfg.onContextMenu) ;
11065
- parentElement.appendChild(dot);
11066
-
11067
- var dotClickable = this._dotClickable;
11068
- var dotClickableStyle = dotClickable.style;
11069
- dotClickableStyle["border-radius"] = 35 + "px";
11070
- dotClickableStyle.border = "solid 10px white";
11071
- dotClickableStyle.position = "absolute";
11072
- dotClickableStyle["z-index"] = cfg.zIndex === undefined ? "40000007" : (cfg.zIndex + 1);
11073
- dotClickableStyle.width = 8 + "px";
11074
- dotClickableStyle.height = 8 + "px";
11075
- dotClickableStyle.visibility = "visible";
11076
- dotClickableStyle.top = 0 + "px";
11077
- dotClickableStyle.left = 0 + "px";
11078
- dotClickableStyle["opacity"] = 0.0;
11079
- dotClickableStyle["pointer-events"] = "none";
11080
- if (cfg.onContextMenu) ;
11081
- parentElement.appendChild(dotClickable);
11082
-
11083
- dotClickable.addEventListener('click', (event) => {
11084
- parentElement.dispatchEvent(new MouseEvent('mouseover', event));
11085
- });
11086
-
11087
- if (cfg.onMouseOver) {
11088
- dotClickable.addEventListener('mouseover', (event) => {
11089
- cfg.onMouseOver(event, this);
11090
- parentElement.dispatchEvent(new MouseEvent('mouseover', event));
11091
- });
11092
- }
11093
-
11094
- if (cfg.onMouseLeave) {
11095
- dotClickable.addEventListener('mouseleave', (event) => {
11096
- cfg.onMouseLeave(event, this);
11097
- });
11098
- }
11099
-
11100
- if (cfg.onMouseWheel) {
11101
- dotClickable.addEventListener('wheel', (event) => {
11102
- cfg.onMouseWheel(event, this);
11103
- });
11104
- }
11105
-
11106
- if (cfg.onMouseDown) {
11107
- dotClickable.addEventListener('mousedown', (event) => {
11108
- cfg.onMouseDown(event, this);
11109
- });
11110
- }
11111
-
11112
- if (cfg.onMouseUp) {
11113
- dotClickable.addEventListener('mouseup', (event) => {
11114
- cfg.onMouseUp(event, this);
11115
- });
11116
- }
11117
-
11118
- if (cfg.onMouseMove) {
11119
- dotClickable.addEventListener('mousemove', (event) => {
11120
- cfg.onMouseMove(event, this);
11121
- });
11122
- }
11123
-
11124
- if (cfg.onContextMenu) {
11125
- if(os.isIphoneSafari()){
11126
- dotClickable.addEventListener('touchstart', (event) => {
11127
- event.preventDefault();
11128
- if(this._timeout){
11129
- clearTimeout(this._timeout);
11130
- this._timeout = null;
11131
- }
11132
- this._timeout = setTimeout(() => {
11133
- event.clientX = event.touches[0].clientX;
11134
- event.clientY = event.touches[0].clientY;
11135
- cfg.onContextMenu(event, this);
11136
- clearTimeout(this._timeout);
11137
- this._timeout = null;
11138
- }, 500);
11139
- });
11140
-
11141
- dotClickable.addEventListener('touchend', (event) => {
11142
- event.preventDefault();
11143
- //stops short touches from calling the timeout
11144
- if(this._timeout) {
11145
- clearTimeout(this._timeout);
11146
- this._timeout = null;
11147
- }
11148
- } );
11149
-
11150
- }
11151
- else {
11152
- dotClickable.addEventListener('contextmenu', (event) => {
11153
- console.log(event);
11154
- cfg.onContextMenu(event, this);
11155
- event.preventDefault();
11156
- event.stopPropagation();
11157
- console.log("Label context menu");
11158
- });
11159
- }
11160
-
11161
- }
11162
-
11163
- if (cfg.onTouchstart) {
11164
- dotClickable.addEventListener('touchstart', (event) => {
11165
- cfg.onTouchstart(event, this);
11166
- });
11167
- }
11168
-
11169
- if (cfg.onTouchmove) {
11170
- dotClickable.addEventListener('touchmove', (event) => {
11171
- cfg.onTouchmove(event, this);
11172
- });
11173
- }
11174
-
11175
- if (cfg.onTouchend) {
11176
- dotClickable.addEventListener('touchend', (event) => {
11177
- cfg.onTouchend(event, this);
11178
- });
11179
- }
11180
-
11181
- this.setPos(cfg.x || 0, cfg.y || 0);
11182
- this.setFillColor(cfg.fillColor);
11183
- this.setBorderColor(cfg.borderColor);
11184
- }
11185
-
11186
- setPos(x, y) {
11187
- this._x = x;
11188
- this._y = y;
11189
- var dotStyle = this._dot.style;
11190
- dotStyle["left"] = (Math.round(x) - 4) + 'px';
11191
- dotStyle["top"] = (Math.round(y) - 4) + 'px';
11192
-
11193
- var dotClickableStyle = this._dotClickable.style;
11194
- dotClickableStyle["left"] = (Math.round(x) - 9) + 'px';
11195
- dotClickableStyle["top"] = (Math.round(y) - 9) + 'px';
11196
- }
11197
-
11198
- setFillColor(color) {
11199
- this._dot.style.background = color || "lightgreen";
11200
- }
11201
-
11202
- setBorderColor(color) {
11203
- this._dot.style.border = "solid 2px" + (color || "black");
11204
- }
11205
-
11206
- setOpacity(opacity) {
11207
- this._dot.style.opacity = opacity;
11208
- }
11209
-
11210
- setVisible(visible) {
11211
- if (this._visible === visible) {
11212
- return;
11213
- }
11214
- this._visible = !!visible;
11215
- this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden";
11216
- }
11217
-
11218
- setCulled(culled) {
11219
- if (this._culled === culled) {
11220
- return;
11221
- }
11222
- this._culled = !!culled;
11223
- this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden";
11224
- }
11225
-
11226
- setClickable(clickable) {
11227
- this._dotClickable.style["pointer-events"] = (clickable) ? "all" : "none";
11228
- }
11229
-
11230
- setHighlighted(highlighted) {
11231
- if (this._highlighted === highlighted) {
11232
- return;
11233
- }
11234
- this._highlighted = !!highlighted;
11235
- if (this._highlighted) {
11236
- this._dot.classList.add(this._highlightClass);
11237
- } else {
11238
- this._dot.classList.remove(this._highlightClass);
11239
- }
11240
- }
11241
-
11242
- destroy() {
11243
- this.setVisible(false);
11244
- if (this._dot.parentElement) {
11245
- this._dot.parentElement.removeChild(this._dot);
11246
- }
11247
- if (this._dotClickable.parentElement) {
11248
- this._dotClickable.parentElement.removeChild(this._dotClickable);
11249
- }
11250
- }
11251
- }
11252
-
11253
11540
  /** @private */
11254
11541
  class Label {
11255
11542
 
@@ -11496,10 +11783,6 @@ class AngleMeasurement extends Component {
11496
11783
 
11497
11784
  var scene = this.plugin.viewer.scene;
11498
11785
 
11499
- this._originMarker = new Marker(scene, cfg.origin);
11500
- this._cornerMarker = new Marker(scene, cfg.corner);
11501
- this._targetMarker = new Marker(scene, cfg.target);
11502
-
11503
11786
  this._originWorld = math.vec3();
11504
11787
  this._cornerWorld = math.vec3();
11505
11788
  this._targetWorld = math.vec3();
@@ -11539,7 +11822,7 @@ class AngleMeasurement extends Component {
11539
11822
  this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mousemove', event));
11540
11823
  };
11541
11824
 
11542
- this._originDot = new Dot(this._container, {
11825
+ this._originDot = new Dot3D(scene, cfg.origin, this._container, {
11543
11826
  fillColor: this._color,
11544
11827
  zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined,
11545
11828
  onMouseOver,
@@ -11550,7 +11833,7 @@ class AngleMeasurement extends Component {
11550
11833
  onMouseMove,
11551
11834
  onContextMenu
11552
11835
  });
11553
- this._cornerDot = new Dot(this._container, {
11836
+ this._cornerDot = new Dot3D(scene, cfg.corner, this._container, {
11554
11837
  fillColor: this._color,
11555
11838
  zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined,
11556
11839
  onMouseOver,
@@ -11561,7 +11844,7 @@ class AngleMeasurement extends Component {
11561
11844
  onMouseMove,
11562
11845
  onContextMenu
11563
11846
  });
11564
- this._targetDot = new Dot(this._container, {
11847
+ this._targetDot = new Dot3D(scene, cfg.target, this._container, {
11565
11848
  fillColor: this._color,
11566
11849
  zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined,
11567
11850
  onMouseOver,
@@ -11628,19 +11911,19 @@ class AngleMeasurement extends Component {
11628
11911
  this._labelsVisible = false;
11629
11912
  this._clickable = false;
11630
11913
 
11631
- this._originMarker.on("worldPos", (value) => {
11914
+ this._originDot.on("worldPos", (value) => {
11632
11915
  this._originWorld.set(value || [0, 0, 0]);
11633
11916
  this._wpDirty = true;
11634
11917
  this._needUpdate(0); // No lag
11635
11918
  });
11636
11919
 
11637
- this._cornerMarker.on("worldPos", (value) => {
11920
+ this._cornerDot.on("worldPos", (value) => {
11638
11921
  this._cornerWorld.set(value || [0, 0, 0]);
11639
11922
  this._wpDirty = true;
11640
11923
  this._needUpdate(0); // No lag
11641
11924
  });
11642
11925
 
11643
- this._targetMarker.on("worldPos", (value) => {
11926
+ this._targetDot.on("worldPos", (value) => {
11644
11927
  this._targetWorld.set(value || [0, 0, 0]);
11645
11928
  this._wpDirty = true;
11646
11929
  this._needUpdate(0); // No lag
@@ -11746,9 +12029,9 @@ class AngleMeasurement extends Component {
11746
12029
  if (this._cpDirty) {
11747
12030
 
11748
12031
  const near = -0.3;
11749
- const zOrigin = this._originMarker.viewPos[2];
11750
- const zCorner = this._cornerMarker.viewPos[2];
11751
- const zTarget = this._targetMarker.viewPos[2];
12032
+ const zOrigin = this._originDot.viewPos[2];
12033
+ const zCorner = this._cornerDot.viewPos[2];
12034
+ const zTarget = this._targetDot.viewPos[2];
11752
12035
 
11753
12036
  if (zOrigin > near || zCorner > near || zTarget > near) {
11754
12037
 
@@ -11785,10 +12068,6 @@ class AngleMeasurement extends Component {
11785
12068
  j += 2;
11786
12069
  }
11787
12070
 
11788
- this._originDot.setPos(cp[0], cp[1]);
11789
- this._cornerDot.setPos(cp[2], cp[3]);
11790
- this._targetDot.setPos(cp[4], cp[5]);
11791
-
11792
12071
  this._originWire.setStartAndEnd(cp[0], cp[1], cp[2], cp[3]);
11793
12072
  this._targetWire.setStartAndEnd(cp[2], cp[3], cp[4], cp[5]);
11794
12073
 
@@ -11869,30 +12148,30 @@ class AngleMeasurement extends Component {
11869
12148
  }
11870
12149
 
11871
12150
  /**
11872
- * Gets the origin {@link Marker}.
12151
+ * Gets the origin {@link Dot3D}.
11873
12152
  *
11874
- * @type {Marker}
12153
+ * @type {Dot3D}
11875
12154
  */
11876
12155
  get origin() {
11877
- return this._originMarker;
12156
+ return this._originDot;
11878
12157
  }
11879
12158
 
11880
12159
  /**
11881
- * Gets the corner {@link Marker}.
12160
+ * Gets the corner {@link Dot3D}.
11882
12161
  *
11883
- * @type {Marker}
12162
+ * @type {Dot3D}
11884
12163
  */
11885
12164
  get corner() {
11886
- return this._cornerMarker;
12165
+ return this._cornerDot;
11887
12166
  }
11888
12167
 
11889
12168
  /**
11890
- * Gets the target {@link Marker}.
12169
+ * Gets the target {@link Dot3D}.
11891
12170
  *
11892
- * @type {Marker}
12171
+ * @type {Dot3D}
11893
12172
  */
11894
12173
  get target() {
11895
- return this._targetMarker;
12174
+ return this._targetDot;
11896
12175
  }
11897
12176
 
11898
12177
  /**
@@ -11962,7 +12241,7 @@ class AngleMeasurement extends Component {
11962
12241
  }
11963
12242
 
11964
12243
  /**
11965
- * Sets if the origin {@link Marker} is visible.
12244
+ * Sets if the origin {@link Dot3D} is visible.
11966
12245
  *
11967
12246
  * @type {Boolean}
11968
12247
  */
@@ -11975,7 +12254,7 @@ class AngleMeasurement extends Component {
11975
12254
  }
11976
12255
 
11977
12256
  /**
11978
- * Gets if the origin {@link Marker} is visible.
12257
+ * Gets if the origin {@link Dot3D} is visible.
11979
12258
  *
11980
12259
  * @type {Boolean}
11981
12260
  */
@@ -11984,7 +12263,7 @@ class AngleMeasurement extends Component {
11984
12263
  }
11985
12264
 
11986
12265
  /**
11987
- * Sets if the corner {@link Marker} is visible.
12266
+ * Sets if the corner {@link Dot3D} is visible.
11988
12267
  *
11989
12268
  * @type {Boolean}
11990
12269
  */
@@ -11997,7 +12276,7 @@ class AngleMeasurement extends Component {
11997
12276
  }
11998
12277
 
11999
12278
  /**
12000
- * Gets if the corner {@link Marker} is visible.
12279
+ * Gets if the corner {@link Dot3D} is visible.
12001
12280
  *
12002
12281
  * @type {Boolean}
12003
12282
  */
@@ -12006,7 +12285,7 @@ class AngleMeasurement extends Component {
12006
12285
  }
12007
12286
 
12008
12287
  /**
12009
- * Sets if the target {@link Marker} is visible.
12288
+ * Sets if the target {@link Dot3D} is visible.
12010
12289
  *
12011
12290
  * @type {Boolean}
12012
12291
  */
@@ -12019,7 +12298,7 @@ class AngleMeasurement extends Component {
12019
12298
  }
12020
12299
 
12021
12300
  /**
12022
- * Gets if the target {@link Marker} is visible.
12301
+ * Gets if the target {@link Dot3D} is visible.
12023
12302
  *
12024
12303
  * @type {Boolean}
12025
12304
  */
@@ -14099,265 +14378,6 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
14099
14378
  }
14100
14379
  }
14101
14380
 
14102
- const nop = () => { };
14103
-
14104
- function transformToNode(from, to, vec) {
14105
- const fromRec = from.getBoundingClientRect();
14106
- const toRec = to.getBoundingClientRect();
14107
- vec[0] += fromRec.left - toRec.left;
14108
- vec[1] += fromRec.top - toRec.top;
14109
- }
14110
- function createDraggableDot3D(cfg) {
14111
- const extractCFG = function(propName, defaultValue) {
14112
- if (propName in cfg) {
14113
- return cfg[propName];
14114
- } else if (defaultValue !== undefined) {
14115
- return defaultValue;
14116
- } else {
14117
- throw "config missing: " + propName;
14118
- }
14119
- };
14120
-
14121
- const viewer = extractCFG("viewer");
14122
- const worldPos = extractCFG("worldPos");
14123
- const color = extractCFG("color");
14124
- const ray2WorldPos = extractCFG("ray2WorldPos");
14125
- const handleMouseEvents = extractCFG("handleMouseEvents", false);
14126
- const handleTouchEvents = extractCFG("handleTouchEvents", false);
14127
- const onStart = extractCFG("onStart", nop);
14128
- const onMove = extractCFG("onMove", nop);
14129
- const onEnd = extractCFG("onEnd", nop);
14130
-
14131
- const scene = viewer.scene;
14132
- const canvas = scene.canvas.canvas;
14133
-
14134
- const marker = new Marker(scene, {});
14135
-
14136
- const pickWorldPos = canvasPos => {
14137
- const origin = math.vec3();
14138
- const direction = math.vec3();
14139
- math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, canvasPos, origin, direction);
14140
- return ray2WorldPos(origin, direction, canvasPos);
14141
- };
14142
-
14143
- const onChange = event => {
14144
- const canvasPos = math.vec2([ event.clientX, event.clientY ]);
14145
- transformToNode(canvas.ownerDocument.body, canvas, canvasPos);
14146
-
14147
- const worldPos = pickWorldPos(canvasPos);
14148
- marker.worldPos = worldPos;
14149
- updateDotPos();
14150
- onMove(canvasPos, worldPos);
14151
- };
14152
-
14153
- let currentDrag = null;
14154
-
14155
- const onDragMove = function(event) {
14156
- const e = currentDrag.matchesEvent(event);
14157
- if (e)
14158
- {
14159
- onChange(e);
14160
- }
14161
- };
14162
-
14163
- const onDragEnd = function(event) {
14164
- const e = currentDrag.matchesEvent(event);
14165
- if (e)
14166
- {
14167
- dot.setOpacity(idleOpacity);
14168
- currentDrag.cleanup();
14169
- onChange(e);
14170
- onEnd();
14171
- }
14172
- };
14173
-
14174
- const startDrag = function(matchesEvent, cleanupHandlers) {
14175
- if (currentDrag) {
14176
- currentDrag.cleanup();
14177
- }
14178
-
14179
- dot.setOpacity(1.0);
14180
- dot.setClickable(false);
14181
- viewer.cameraControl.active = false;
14182
-
14183
- currentDrag = {
14184
- matchesEvent: matchesEvent,
14185
- cleanup: function() {
14186
- currentDrag = null;
14187
- dot.setClickable(true);
14188
- viewer.cameraControl.active = true;
14189
- cleanupHandlers();
14190
- }
14191
- };
14192
-
14193
- onStart();
14194
- };
14195
-
14196
- const dotCfg = { fillColor: color };
14197
-
14198
- if (handleMouseEvents)
14199
- {
14200
- dotCfg.onMouseOver = () => (! currentDrag) && dot.setOpacity(1.0);
14201
- dotCfg.onMouseLeave = () => (! currentDrag) && dot.setOpacity(idleOpacity);
14202
- dotCfg.onMouseDown = event => {
14203
- if (event.which === 1)
14204
- {
14205
- canvas.addEventListener("mousemove", onDragMove);
14206
- canvas.addEventListener("mouseup", onDragEnd);
14207
- startDrag(
14208
- event => (event.which === 1) && event,
14209
- () => {
14210
- canvas.removeEventListener("mousemove", onDragMove);
14211
- canvas.removeEventListener("mouseup", onDragEnd);
14212
- });
14213
- }
14214
- };
14215
- }
14216
-
14217
- if (handleTouchEvents)
14218
- {
14219
- let touchStartId;
14220
- dotCfg.onTouchstart = event => {
14221
- event.preventDefault();
14222
- if (event.touches.length === 1)
14223
- {
14224
- touchStartId = event.touches[0].identifier;
14225
- startDrag(
14226
- event => [...event.changedTouches].find(e => e.identifier === touchStartId),
14227
- () => { touchStartId = null; });
14228
- }
14229
- };
14230
- dotCfg.onTouchmove = event => {
14231
- event.preventDefault();
14232
- onDragMove(event);
14233
- };
14234
- dotCfg.onTouchend = event => {
14235
- event.preventDefault();
14236
- onDragEnd(event);
14237
- };
14238
- }
14239
-
14240
- const dotParent = canvas.ownerDocument.body;
14241
- const dot = new Dot(dotParent, dotCfg);
14242
-
14243
- const idleOpacity = 0.5;
14244
- dot.setOpacity(idleOpacity);
14245
-
14246
- const updateDotPos = function() {
14247
- const pos = marker.canvasPos.slice();
14248
- transformToNode(canvas, dotParent, pos);
14249
- dot.setPos(pos[0], pos[1]);
14250
- };
14251
-
14252
- marker.worldPos = worldPos;
14253
- updateDotPos();
14254
-
14255
- const onViewMatrix = scene.camera.on("viewMatrix", updateDotPos);
14256
- const onProjMatrix = scene.camera.on("projMatrix", updateDotPos);
14257
-
14258
- return {
14259
- setActive: value => dot.setClickable(value),
14260
- getWorldPos: () => marker.worldPos,
14261
- setWorldPos: pos => { marker.worldPos = pos; updateDotPos(); },
14262
- destroy: function() {
14263
- currentDrag && currentDrag.cleanup();
14264
- scene.camera.off(onViewMatrix);
14265
- scene.camera.off(onProjMatrix);
14266
- marker.destroy();
14267
- dot.destroy();
14268
- }
14269
- };
14270
- }
14271
- function activateDraggableDots(cfg) {
14272
- const extractCFG = function(propName, defaultValue) {
14273
- if (propName in cfg) {
14274
- return cfg[propName];
14275
- } else if (defaultValue !== undefined) {
14276
- return defaultValue;
14277
- } else {
14278
- throw "config missing: " + propName;
14279
- }
14280
- };
14281
-
14282
- const viewer = extractCFG("viewer");
14283
- const handleMouseEvents = extractCFG("handleMouseEvents", false);
14284
- const handleTouchEvents = extractCFG("handleTouchEvents", false);
14285
- const snapping = extractCFG("snapping");
14286
- const pointerLens = extractCFG("pointerLens", null);
14287
- const color = extractCFG("color");
14288
- const markers = extractCFG("markers");
14289
- const onEdit = extractCFG("onEdit", nop);
14290
-
14291
- const updatePointerLens = (pointerLens
14292
- ? function(canvasPos) {
14293
- pointerLens.visible = !! canvasPos;
14294
- if (canvasPos)
14295
- {
14296
- pointerLens.canvasPos = canvasPos;
14297
- }
14298
- }
14299
- : () => { });
14300
-
14301
- const dots = markers.map(marker => {
14302
- let initDotPos, initMarkerPos;
14303
- const setCoord = coord => marker.worldPos = coord;
14304
-
14305
- const dot = createDraggableDot3D({
14306
- handleMouseEvents: handleMouseEvents,
14307
- handleTouchEvents: handleTouchEvents,
14308
- viewer: viewer,
14309
- worldPos: marker.worldPos,
14310
- color: color,
14311
- ray2WorldPos: (orig, dir, canvasPos) => {
14312
- const tryPickWorldPos = snap => {
14313
- const pickResult = viewer.scene.pick({
14314
- canvasPos: canvasPos,
14315
- snapToEdge: snap,
14316
- snapToVertex: snap,
14317
- pickSurface: true // <<------ This causes picking to find the intersection point on the entity
14318
- });
14319
-
14320
- // If - when snapping - no pick found, then try w/o snapping
14321
- return (pickResult && pickResult.worldPos) ? pickResult.worldPos : (snap && tryPickWorldPos(false));
14322
- };
14323
-
14324
- return tryPickWorldPos(!!snapping) || initDotPos;
14325
- },
14326
- onStart: () => {
14327
- initDotPos = dot.getWorldPos().slice();
14328
- initMarkerPos = marker.worldPos.slice();
14329
- setOtherDotsActive(false, dot);
14330
- },
14331
- onMove: (canvasPos, worldPos) => {
14332
- updatePointerLens(canvasPos);
14333
- setCoord(worldPos);
14334
- },
14335
- onEnd: () => {
14336
- if (! math.compareVec3(initMarkerPos, marker.worldPos))
14337
- {
14338
- onEdit();
14339
- }
14340
- else
14341
- {
14342
- dot.setWorldPos(initDotPos);
14343
- setCoord(initMarkerPos);
14344
- }
14345
- updatePointerLens(null);
14346
- setOtherDotsActive(true, dot);
14347
- }
14348
- });
14349
- return dot;
14350
- });
14351
-
14352
- const setOtherDotsActive = (active, dot) => dots.forEach(d => (d !== dot) && d.setActive(active));
14353
- setOtherDotsActive(true);
14354
-
14355
- return function() {
14356
- dots.forEach(m => m.destroy());
14357
- updatePointerLens(null);
14358
- };
14359
- }
14360
-
14361
14381
  class AngleMeasurementEditControl extends Component {
14362
14382
 
14363
14383
  /**
@@ -14380,11 +14400,30 @@ class AngleMeasurementEditControl extends Component {
14380
14400
  viewer: viewer,
14381
14401
  handleMouseEvents: handleMouseEvents,
14382
14402
  handleTouchEvents: handleTouchEvents,
14383
- snapping: cfg.snapping,
14384
14403
  pointerLens: cfg.pointerLens,
14385
- color: measurement.color,
14386
- markers: [ measurement.origin, measurement.corner, measurement.target ],
14387
- onEdit: () => this.fire("edited")
14404
+ dots: [ measurement.origin, measurement.corner, measurement.target ],
14405
+ ray2WorldPos: (orig, dir, canvasPos) => {
14406
+ const tryPickWorldPos = snap => {
14407
+ const pickResult = viewer.scene.pick({
14408
+ canvasPos: canvasPos,
14409
+ snapToEdge: snap,
14410
+ snapToVertex: snap,
14411
+ pickSurface: true // <<------ This causes picking to find the intersection point on the entity
14412
+ });
14413
+
14414
+ // If - when snapping - no pick found, then try w/o snapping
14415
+ return (pickResult && pickResult.worldPos) ? pickResult.worldPos : (snap && tryPickWorldPos(false));
14416
+ };
14417
+
14418
+ return tryPickWorldPos(!!cfg.snapping);
14419
+ },
14420
+ onEnd: (initPos, dot) => {
14421
+ const changed = ! math.compareVec3(initPos, dot.worldPos);
14422
+ if (changed) {
14423
+ this.fire("edited");
14424
+ }
14425
+ return changed;
14426
+ }
14388
14427
  });
14389
14428
 
14390
14429
  const destroyCb = measurement.on("destroyed", cleanup);
@@ -14413,6 +14452,10 @@ class AngleMeasurementEditTouchControl extends AngleMeasurementEditControl {
14413
14452
  }
14414
14453
  }
14415
14454
 
14455
+ const tempVec3a$K = math.vec3();
14456
+ const tempVec3b$z = math.vec3();
14457
+ const tempVec3c$v = math.vec3();
14458
+
14416
14459
  /**
14417
14460
  * A {@link Marker} with an HTML label attached to it, managed by an {@link AnnotationsPlugin}.
14418
14461
  *
@@ -14452,6 +14495,9 @@ class Annotation extends Marker {
14452
14495
  this._marker.addEventListener("click", this._onMouseClickedExternalMarker = () => {
14453
14496
  this.plugin.fire("markerClicked", this);
14454
14497
  });
14498
+ this._marker.addEventListener("contextmenu", this._onContextMenuExtenalMarker = () => {
14499
+ this.plugin.fire("contextmenu", this);
14500
+ });
14455
14501
  this._marker.addEventListener("mouseenter", this._onMouseEnterExternalMarker = () => {
14456
14502
  this.plugin.fire("markerMouseEnter", this);
14457
14503
  });
@@ -14571,6 +14617,10 @@ class Annotation extends Marker {
14571
14617
  this._marker.addEventListener("click", () => {
14572
14618
  this.plugin.fire("markerClicked", this);
14573
14619
  });
14620
+ this._marker.addEventListener("contextmenu", e => {
14621
+ e.preventDefault();
14622
+ this.plugin.fire("contextmenu", this);
14623
+ });
14574
14624
  this._marker.addEventListener("mouseenter", () => {
14575
14625
  this.plugin.fire("markerMouseEnter", this);
14576
14626
  });
@@ -14632,6 +14682,24 @@ class Annotation extends Marker {
14632
14682
  return template;
14633
14683
  }
14634
14684
 
14685
+ /**
14686
+ * Sets the Marker's worldPos and entity properties based on passed {@link PickResult}
14687
+ *
14688
+ * @param {PickResult} pickResult A PickResult to position the Marker at.
14689
+ */
14690
+ setFromPickResult(pickResult) {
14691
+ if (!pickResult.worldPos || !pickResult.worldNormal) {
14692
+ this.error("Param 'pickResult' does not have both worldPos and worldNormal");
14693
+ } else {
14694
+ const normalizedWorldNormal = math.normalizeVec3(pickResult.worldNormal, tempVec3a$K);
14695
+ const offset = (this.plugin && this.plugin.surfaceOffset) || 0;
14696
+ const offsetVec = math.mulVec3Scalar(normalizedWorldNormal, offset, tempVec3b$z);
14697
+ const offsetWorldPos = math.addVec3(pickResult.worldPos, offsetVec, tempVec3c$v);
14698
+ this.entity = pickResult.entity;
14699
+ this.worldPos = offsetWorldPos;
14700
+ }
14701
+ }
14702
+
14635
14703
  /**
14636
14704
  * Sets whether or not to show this Annotation's marker.
14637
14705
  *
@@ -14762,6 +14830,7 @@ class Annotation extends Marker {
14762
14830
  this._marker = null;
14763
14831
  } else {
14764
14832
  this._marker.removeEventListener("click", this._onMouseClickedExternalMarker);
14833
+ this._marker.removeEventListener("contextmenu", this._onContextMenuExtenalMarker);
14765
14834
  this._marker.removeEventListener("mouseenter", this._onMouseEnterExternalMarker);
14766
14835
  this._marker.removeEventListener("mouseleave", this._onMouseLeaveExternalMarker);
14767
14836
  this._marker = null;
@@ -14778,10 +14847,6 @@ class Annotation extends Marker {
14778
14847
  }
14779
14848
  }
14780
14849
 
14781
- const tempVec3a$K = math.vec3();
14782
- const tempVec3b$z = math.vec3();
14783
- const tempVec3c$v = math.vec3();
14784
-
14785
14850
  /**
14786
14851
  * {@link Viewer} plugin that creates {@link Annotation}s.
14787
14852
  *
@@ -15256,24 +15321,6 @@ class AnnotationsPlugin extends Plugin {
15256
15321
  this.error("Viewer component with this ID already exists: " + params.id);
15257
15322
  delete params.id;
15258
15323
  }
15259
- var worldPos;
15260
- var entity;
15261
- params.pickResult = params.pickResult || params.pickRecord;
15262
- if (params.pickResult) {
15263
- const pickResult = params.pickResult;
15264
- if (!pickResult.worldPos || !pickResult.worldNormal) {
15265
- this.error("Param 'pickResult' does not have both worldPos and worldNormal");
15266
- } else {
15267
- const normalizedWorldNormal = math.normalizeVec3(pickResult.worldNormal, tempVec3a$K);
15268
- const offsetVec = math.mulVec3Scalar(normalizedWorldNormal, this._surfaceOffset, tempVec3b$z);
15269
- const offsetWorldPos = math.addVec3(pickResult.worldPos, offsetVec, tempVec3c$v);
15270
- worldPos = offsetWorldPos;
15271
- entity = pickResult.entity;
15272
- }
15273
- } else {
15274
- worldPos = params.worldPos;
15275
- entity = params.entity;
15276
- }
15277
15324
 
15278
15325
  var markerElement = null;
15279
15326
  if (params.markerElementId) {
@@ -15294,8 +15341,6 @@ class AnnotationsPlugin extends Plugin {
15294
15341
  const annotation = new Annotation(this.viewer.scene, {
15295
15342
  id: params.id,
15296
15343
  plugin: this,
15297
- entity: entity,
15298
- worldPos: worldPos,
15299
15344
  container: this._container,
15300
15345
  markerElement: markerElement,
15301
15346
  labelElement: labelElement,
@@ -15311,6 +15356,15 @@ class AnnotationsPlugin extends Plugin {
15311
15356
  projection: params.projection,
15312
15357
  visible: (params.visible !== false)
15313
15358
  });
15359
+
15360
+ params.pickResult = params.pickResult || params.pickRecord;
15361
+ if (params.pickResult) {
15362
+ annotation.setFromPickResult(params.pickResult);
15363
+ } else {
15364
+ annotation.entity = params.entity;
15365
+ annotation.worldPos = params.worldPos;
15366
+ }
15367
+
15314
15368
  this.annotations[annotation.id] = annotation;
15315
15369
  annotation.on("destroyed", () => {
15316
15370
  delete this.annotations[annotation.id];
@@ -49790,6 +49844,270 @@ function buildPolylineGeometryFromCurve(cfg = {}) {
49790
49844
  });
49791
49845
  }
49792
49846
 
49847
+ /**
49848
+ * @desc Creates a 3D line {@link Geometry}.
49849
+ *
49850
+ * ## Usage
49851
+ *
49852
+ * In the example below we'll create a {@link Mesh} with a line {@link ReadableGeometry}.
49853
+ *
49854
+ * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/scenegraph/#buildLineGeometry)]
49855
+ *
49856
+ * ````javascript
49857
+ * //------------------------------------------------------------------------------------------------------------------
49858
+ * // Import the modules we need for this example
49859
+ * //------------------------------------------------------------------------------------------------------------------
49860
+ *
49861
+ * import {buildLineGeometry, Viewer, Mesh, ReadableGeometry, PhongMaterial} from "../../dist/xeokit-sdk.min.es.js";
49862
+ *
49863
+ * //------------------------------------------------------------------------------------------------------------------
49864
+ * // Create a Viewer and arrange the camera
49865
+ * //------------------------------------------------------------------------------------------------------------------
49866
+ *
49867
+ * const viewer = new Viewer({
49868
+ * canvasId: "myCanvas"
49869
+ * });
49870
+ *
49871
+ * viewer.camera.eye = [0, 0, 8];
49872
+ * viewer.camera.look = [0, 0, 0];
49873
+ * viewer.camera.up = [0, 1, 0];
49874
+ *
49875
+ * //------------------------------------------------------------------------------------------------------------------
49876
+ * // Create a mesh with simple 2d line shape
49877
+ * //------------------------------------------------------------------------------------------------------------------
49878
+ *
49879
+ * new Mesh(viewer.scene, {
49880
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49881
+ * startPoint: [-5,-2,0],
49882
+ * endPoint: [-5,2,0],
49883
+ * })),
49884
+ * material: new PhongMaterial(viewer.scene, {
49885
+ * emissive: [0, 1,]
49886
+ * })
49887
+ * });
49888
+ *
49889
+ * //------------------------------------------------------------------------------------------------------------------
49890
+ * // Create a mesh with simple 2d line shape with black color
49891
+ * //------------------------------------------------------------------------------------------------------------------
49892
+ *
49893
+ * new Mesh(viewer.scene, {
49894
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49895
+ * startPoint: [-4,-2,0],
49896
+ * endPoint: [-4,2,0],
49897
+ * })),
49898
+ * material: new PhongMaterial(viewer.scene, {
49899
+ * emissive: [0, 0, 0]
49900
+ * })
49901
+ * });
49902
+ *
49903
+ * //------------------------------------------------------------------------------------------------------------------
49904
+ * // Create a mesh with simple 2d line shape with black color and simple pattern
49905
+ * //------------------------------------------------------------------------------------------------------------------
49906
+ *
49907
+ * new Mesh(viewer.scene, {
49908
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49909
+ * startPoint: [-3,-2,0],
49910
+ * endPoint: [-3,2,0],
49911
+ * pattern: [0.10],
49912
+ * })),
49913
+ * material: new PhongMaterial(viewer.scene, {
49914
+ * emissive: [0, 0, 0]
49915
+ * })
49916
+ * });
49917
+ *
49918
+ * //------------------------------------------------------------------------------------------------------------------
49919
+ * // Create a mesh with simple 2d line shape with blue color and simple pattern extended to end
49920
+ * //------------------------------------------------------------------------------------------------------------------
49921
+ *
49922
+ * new Mesh(viewer.scene, {
49923
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49924
+ * startPoint: [-2,-2,0],
49925
+ * endPoint: [-2,2,0],
49926
+ * pattern: [0.10],
49927
+ * extendToEnd: true,
49928
+ * })),
49929
+ * material: new PhongMaterial(viewer.scene, {
49930
+ * emissive: [0, 0, 1]
49931
+ * })
49932
+ * });
49933
+ *
49934
+ * //------------------------------------------------------------------------------------------------------------------
49935
+ * // Create a mesh with simple 2d line shape with black color and more complex pattern
49936
+ * //------------------------------------------------------------------------------------------------------------------
49937
+ *
49938
+ * new Mesh(viewer.scene, {
49939
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49940
+ * startPoint: [-1,-2,0],
49941
+ * endPoint: [-1,2,0],
49942
+ * pattern: [0.15, 0.05],
49943
+ * })),
49944
+ * material: new PhongMaterial(viewer.scene, {
49945
+ * emissive: [0, 0, 0]
49946
+ * })
49947
+ * });
49948
+ *
49949
+ * //------------------------------------------------------------------------------------------------------------------
49950
+ * // Create a mesh with simple 2d line shape with blue color and more complex pattern extended to end
49951
+ * //------------------------------------------------------------------------------------------------------------------
49952
+ *
49953
+ * new Mesh(viewer.scene, {
49954
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49955
+ * startPoint: [0,-2,0],
49956
+ * endPoint: [0,2,0],
49957
+ * pattern: [0.15, 0.05],
49958
+ * extendToEnd: true,
49959
+ * })),
49960
+ * material: new PhongMaterial(viewer.scene, {
49961
+ * emissive: [0, 0, 1]
49962
+ * })
49963
+ * });
49964
+ *
49965
+ * //------------------------------------------------------------------------------------------------------------------
49966
+ * // Create a mesh with simple 2d line shape with black color and complex pattern
49967
+ * //------------------------------------------------------------------------------------------------------------------
49968
+ *
49969
+ * new Mesh(viewer.scene, {
49970
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49971
+ * startPoint: [1,-2,0],
49972
+ * endPoint: [1,2,0],
49973
+ * pattern: [0.15, 0.05, 0.50],
49974
+ * })),
49975
+ * material: new PhongMaterial(viewer.scene, {
49976
+ * emissive: [0, 0, 0]
49977
+ * })
49978
+ * });
49979
+ *
49980
+ * //------------------------------------------------------------------------------------------------------------------
49981
+ * // Create a mesh with simple 2d line shape with blue color and complex pattern extended to end
49982
+ * //------------------------------------------------------------------------------------------------------------------
49983
+ *
49984
+ * new Mesh(viewer.scene, {
49985
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
49986
+ * startPoint: [2,-2,0],
49987
+ * endPoint: [2,2,0],
49988
+ * pattern: [0.15, 0.05, 0.50],
49989
+ * extendToEnd: true,
49990
+ * })),
49991
+ * material: new PhongMaterial(viewer.scene, {
49992
+ * emissive: [0, 0, 1]
49993
+ * })
49994
+ * });
49995
+ *
49996
+ * //------------------------------------------------------------------------------------------------------------------
49997
+ * // Create a mesh with simple 3d line shape with white color and simple pattern
49998
+ * //------------------------------------------------------------------------------------------------------------------
49999
+ *
50000
+ * new Mesh(viewer.scene, {
50001
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
50002
+ * startPoint: [3,-2,-1],
50003
+ * endPoint: [5,2,1],
50004
+ * pattern: [0.10],
50005
+ * })),
50006
+ * material: new PhongMaterial(viewer.scene, {
50007
+ * emissive: [1, 1, 1]
50008
+ * })
50009
+ * });
50010
+ *
50011
+ * //------------------------------------------------------------------------------------------------------------------
50012
+ * // Create a mesh with simple 3d line shape with black color and simple dot pattern
50013
+ * //------------------------------------------------------------------------------------------------------------------
50014
+ *
50015
+ * new Mesh(viewer.scene, {
50016
+ * geometry: new ReadableGeometry(viewer.scene, buildLineGeometry({
50017
+ * startPoint: [5,-2,-1],
50018
+ * endPoint: [7,2,1],
50019
+ * pattern: [0.03],
50020
+ * })),
50021
+ * material: new PhongMaterial(viewer.scene, {
50022
+ * emissive: [0, 0, 0]
50023
+ * })
50024
+ * });
50025
+ * ````
50026
+ *
50027
+ * @function buildLineGeometry
50028
+ * @param {*} [cfg] Configs
50029
+ * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted.
50030
+ * @param {Number[]} [cfg.startPoint] 3D start point (x0, y0, z0).
50031
+ * @param {Number[]} [cfg.endPoint] 3D end point (x1, y1, z1).
50032
+ * @param {Number[]} [cfg.pattern] Lengths of segments that describe a pattern.
50033
+ * @param {Bool} [cfg.extendToEnd] If true: it will try to make sure the line doesn't end up with a gap, as it will
50034
+ * extend the last segment.
50035
+ * @returns {Object} Configuration for a {@link Geometry} subtype.
50036
+ */
50037
+ function buildLineGeometry(cfg = {}) {
50038
+
50039
+ if (cfg.startPoint.length !== 3) {
50040
+ throw "Start point should contain 3 elements in array: x, y and z";
50041
+ }
50042
+ if (cfg.endPoint.length !== 3) {
50043
+ throw "End point should contain 3 elements in array: x, y and z";
50044
+ }
50045
+ let indices = [];
50046
+ let points = [];
50047
+ let x0 = cfg.startPoint[0]; let y0 = cfg.startPoint[1]; let z0 = cfg.startPoint[2];
50048
+ let x1 = cfg.endPoint[0]; let y1 = cfg.endPoint[1]; let z1 = cfg.endPoint[2];
50049
+ let lineLength = Math.sqrt((x1- x0)**2 + (y1 - y0)**2 + (z1 - z0)**2);
50050
+ let normalizedDirectionVectorOfLine = [(x1-x0)/lineLength, (y1-y0)/lineLength, (z1-z0)/lineLength];
50051
+
50052
+ if (!cfg.pattern) {
50053
+ indices.push(0);
50054
+ indices.push(1);
50055
+ points.push(x0, y0, z0, x1, y1, z1);
50056
+ }
50057
+ else {
50058
+ let patternsNumber = cfg.pattern.length;
50059
+ let gap = false;
50060
+ let segmentFilled = 0.0;
50061
+ let idOfCurrentPatternLength = 0;
50062
+ let pointIndicesCounter = 0;
50063
+ let currentStartPoint = [x0, y0, z0];
50064
+ let currentPatternLength = cfg.pattern[idOfCurrentPatternLength];
50065
+ points.push(currentStartPoint[0], currentStartPoint[1], currentStartPoint[2]);
50066
+
50067
+ while (currentPatternLength <= (lineLength - segmentFilled)) {
50068
+ let vectorFromCurrentStartPointToCurrentEndPoint = [
50069
+ normalizedDirectionVectorOfLine[0] * currentPatternLength,
50070
+ normalizedDirectionVectorOfLine[1] * currentPatternLength,
50071
+ normalizedDirectionVectorOfLine[2] * currentPatternLength,
50072
+ ];
50073
+ let currentEndPoint = [
50074
+ currentStartPoint[0] + vectorFromCurrentStartPointToCurrentEndPoint[0],
50075
+ currentStartPoint[1] + vectorFromCurrentStartPointToCurrentEndPoint[1],
50076
+ currentStartPoint[2] + vectorFromCurrentStartPointToCurrentEndPoint[2],
50077
+ ];
50078
+
50079
+ points.push(currentEndPoint[0], currentEndPoint[1], currentEndPoint[2]);
50080
+
50081
+ if (!gap) {
50082
+ indices.push(pointIndicesCounter);
50083
+ indices.push(pointIndicesCounter + 1);
50084
+ }
50085
+ gap = !gap;
50086
+
50087
+ pointIndicesCounter += 1;
50088
+ currentStartPoint = currentEndPoint;
50089
+ idOfCurrentPatternLength += 1;
50090
+ if (idOfCurrentPatternLength >= patternsNumber) {
50091
+ idOfCurrentPatternLength = 0;
50092
+ }
50093
+ segmentFilled += currentPatternLength;
50094
+ currentPatternLength = cfg.pattern[idOfCurrentPatternLength];
50095
+ }
50096
+
50097
+ if (cfg.extendToEnd) {
50098
+ points.push(x1, y1, z1);
50099
+ indices.push(indices.length - 2);
50100
+ indices.push(indices.length - 1);
50101
+ }
50102
+ }
50103
+
50104
+ return utils.apply(cfg, {
50105
+ primitive: "lines",
50106
+ positions: points,
50107
+ indices: indices,
50108
+ });
50109
+ }
50110
+
49793
50111
  /**
49794
50112
  * A plane-shaped 3D object containing a bitmap image.
49795
50113
  *
@@ -86725,8 +87043,6 @@ class DistanceMeasurement extends Component {
86725
87043
  this._eventSubs = {};
86726
87044
 
86727
87045
  var scene = this.plugin.viewer.scene;
86728
- this._originMarker = new Marker(scene, cfg.origin);
86729
- this._targetMarker = new Marker(scene, cfg.target);
86730
87046
 
86731
87047
  this._originWorld = math.vec3();
86732
87048
  this._targetWorld = math.vec3();
@@ -86772,7 +87088,7 @@ class DistanceMeasurement extends Component {
86772
87088
  this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new WheelEvent('wheel', event));
86773
87089
  };
86774
87090
 
86775
- this._originDot = new Dot(this._container, {
87091
+ this._originDot = new Dot3D(scene, cfg.origin, this._container, {
86776
87092
  fillColor: this._color,
86777
87093
  zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined,
86778
87094
  onMouseOver,
@@ -86784,7 +87100,7 @@ class DistanceMeasurement extends Component {
86784
87100
  onContextMenu
86785
87101
  });
86786
87102
 
86787
- this._targetDot = new Dot(this._container, {
87103
+ this._targetDot = new Dot3D(scene, cfg.target, this._container, {
86788
87104
  fillColor: this._color,
86789
87105
  zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined,
86790
87106
  onMouseOver,
@@ -86931,13 +87247,13 @@ class DistanceMeasurement extends Component {
86931
87247
  this._labelsOnWires = false;
86932
87248
  this._clickable = false;
86933
87249
 
86934
- this._originMarker.on("worldPos", (value) => {
87250
+ this._originDot.on("worldPos", (value) => {
86935
87251
  this._originWorld.set(value || [0,0,0]);
86936
87252
  this._wpDirty = true;
86937
87253
  this._needUpdate(0); // No lag
86938
87254
  });
86939
87255
 
86940
- this._targetMarker.on("worldPos", (value) => {
87256
+ this._targetDot.on("worldPos", (value) => {
86941
87257
  this._targetWorld.set(value || [0,0,0]);
86942
87258
  this._wpDirty = true;
86943
87259
  this._needUpdate(0); // No lag
@@ -87099,8 +87415,8 @@ class DistanceMeasurement extends Component {
87099
87415
  }
87100
87416
 
87101
87417
  const near = -0.3;
87102
- const vpz1 = this._originMarker.viewPos[2];
87103
- const vpz2 = this._targetMarker.viewPos[2];
87418
+ const vpz1 = this._originDot.viewPos[2];
87419
+ const vpz2 = this._targetDot.viewPos[2];
87104
87420
 
87105
87421
  if (vpz1 > near || vpz2 > near) {
87106
87422
 
@@ -87149,9 +87465,6 @@ class DistanceMeasurement extends Component {
87149
87465
  j += 2;
87150
87466
  }
87151
87467
 
87152
- this._originDot.setPos(cp[0], cp[1]);
87153
- this._targetDot.setPos(cp[6], cp[7]);
87154
-
87155
87468
  this._lengthWire.setStartAndEnd(cp[0], cp[1], cp[6], cp[7]);
87156
87469
 
87157
87470
  this._xAxisWire.setStartAndEnd(cp[0], cp[1], cp[2], cp[3]);
@@ -87293,21 +87606,21 @@ class DistanceMeasurement extends Component {
87293
87606
  }
87294
87607
 
87295
87608
  /**
87296
- * Gets the origin {@link Marker}.
87609
+ * Gets the origin {@link Dot3D}.
87297
87610
  *
87298
- * @type {Marker}
87611
+ * @type {Dot3D}
87299
87612
  */
87300
87613
  get origin() {
87301
- return this._originMarker;
87614
+ return this._originDot;
87302
87615
  }
87303
87616
 
87304
87617
  /**
87305
- * Gets the target {@link Marker}.
87618
+ * Gets the target {@link Dot3D}.
87306
87619
  *
87307
- * @type {Marker}
87620
+ * @type {Dot3D}
87308
87621
  */
87309
87622
  get target() {
87310
- return this._targetMarker;
87623
+ return this._targetDot;
87311
87624
  }
87312
87625
 
87313
87626
  /**
@@ -87376,7 +87689,7 @@ class DistanceMeasurement extends Component {
87376
87689
  }
87377
87690
 
87378
87691
  /**
87379
- * Sets if the origin {@link Marker} is visible.
87692
+ * Sets if the origin {@link Dot3D} is visible.
87380
87693
  *
87381
87694
  * @type {Boolean}
87382
87695
  */
@@ -87387,7 +87700,7 @@ class DistanceMeasurement extends Component {
87387
87700
  }
87388
87701
 
87389
87702
  /**
87390
- * Gets if the origin {@link Marker} is visible.
87703
+ * Gets if the origin {@link Dot3D} is visible.
87391
87704
  *
87392
87705
  * @type {Boolean}
87393
87706
  */
@@ -87396,7 +87709,7 @@ class DistanceMeasurement extends Component {
87396
87709
  }
87397
87710
 
87398
87711
  /**
87399
- * Sets if the target {@link Marker} is visible.
87712
+ * Sets if the target {@link Dot3D} is visible.
87400
87713
  *
87401
87714
  * @type {Boolean}
87402
87715
  */
@@ -87407,7 +87720,7 @@ class DistanceMeasurement extends Component {
87407
87720
  }
87408
87721
 
87409
87722
  /**
87410
- * Gets if the target {@link Marker} is visible.
87723
+ * Gets if the target {@link Dot3D} is visible.
87411
87724
  *
87412
87725
  * @type {Boolean}
87413
87726
  */
@@ -89695,11 +90008,30 @@ class DistanceMeasurementEditControl extends Component {
89695
90008
  viewer: viewer,
89696
90009
  handleMouseEvents: handleMouseEvents,
89697
90010
  handleTouchEvents: handleTouchEvents,
89698
- snapping: cfg.snapping,
89699
90011
  pointerLens: cfg.pointerLens,
89700
- color: measurement.color,
89701
- markers: [ measurement.origin, measurement.target ],
89702
- onEdit: () => this.fire("edited")
90012
+ dots: [ measurement.origin, measurement.target ],
90013
+ ray2WorldPos: (orig, dir, canvasPos) => {
90014
+ const tryPickWorldPos = snap => {
90015
+ const pickResult = viewer.scene.pick({
90016
+ canvasPos: canvasPos,
90017
+ snapToEdge: snap,
90018
+ snapToVertex: snap,
90019
+ pickSurface: true // <<------ This causes picking to find the intersection point on the entity
90020
+ });
90021
+
90022
+ // If - when snapping - no pick found, then try w/o snapping
90023
+ return (pickResult && pickResult.worldPos) ? pickResult.worldPos : (snap && tryPickWorldPos(false));
90024
+ };
90025
+
90026
+ return tryPickWorldPos(!!cfg.snapping);
90027
+ },
90028
+ onEnd: (initPos, dot) => {
90029
+ const changed = ! math.compareVec3(initPos, dot.worldPos);
90030
+ if (changed) {
90031
+ this.fire("edited");
90032
+ }
90033
+ return changed;
90034
+ }
89703
90035
  });
89704
90036
 
89705
90037
  const destroyCb = measurement.on("destroyed", cleanup);
@@ -139872,26 +140204,19 @@ class ZonesPolysurfaceTouchControl extends Component {
139872
140204
 
139873
140205
  class ZoneEditControl extends Component {
139874
140206
  constructor(zone, cfg, handleMouseEvents, handleTouchEvents) {
139875
- super(zone.plugin.viewer.scene);
139876
- const self = this;
140207
+ const viewer = zone.plugin.viewer;
140208
+ const scene = viewer.scene;
140209
+ super(scene);
139877
140210
 
139878
140211
  const altitude = zone._geometry.altitude;
139879
- const pointerLens = cfg && cfg.pointerLens;
139880
- const updatePointerLens = (pointerLens
139881
- ? function(canvasPos) {
139882
- pointerLens.visible = !! canvasPos;
139883
- if (canvasPos)
139884
- {
139885
- pointerLens.canvasPos = canvasPos;
139886
- }
139887
- }
139888
- : () => { });
139889
140212
 
139890
140213
  const dots = zone._geometry.planeCoordinates.map(planeCoord => {
139891
- let initWorldPos, initPlaneCoord;
139892
- const setPlaneCoord = function(coord) {
139893
- planeCoord[0] = coord[0];
139894
- planeCoord[1] = coord[1];
140214
+ const dotParent = scene.canvas.canvas.ownerDocument.body;
140215
+ const dot = new Dot3D(scene, {}, dotParent, { fillColor: zone._color });
140216
+ dot.worldPos = math.vec3([ planeCoord[0], altitude, planeCoord[1] ]);
140217
+ dot.on("worldPos", function() {
140218
+ planeCoord[0] = dot.worldPos[0];
140219
+ planeCoord[1] = dot.worldPos[2];
139895
140220
  try {
139896
140221
  zone._rebuildMesh();
139897
140222
  } catch (e) {
@@ -139900,46 +140225,29 @@ class ZoneEditControl extends Component {
139900
140225
  zone._zoneMesh = null;
139901
140226
  }
139902
140227
  }
139903
- };
139904
-
139905
- const dot = createDraggableDot3D({
139906
- handleMouseEvents: handleMouseEvents,
139907
- handleTouchEvents: handleTouchEvents,
139908
- viewer: zone.plugin.viewer,
139909
- worldPos: math.vec3([ planeCoord[0], altitude, planeCoord[1] ]),
139910
- color: zone._color,
139911
- ray2WorldPos: (orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir),
139912
- onStart: () => {
139913
- initWorldPos = dot.getWorldPos().slice();
139914
- initPlaneCoord = planeCoord.slice();
139915
- set_other_dots_active(false, dot);
139916
- },
139917
- onMove: (canvasPos, worldPos) => {
139918
- updatePointerLens(canvasPos);
139919
- setPlaneCoord([ worldPos[0], worldPos[2] ]);
139920
- },
139921
- onEnd: () => {
139922
- if (zone._zoneMesh)
139923
- {
139924
- self.fire("edited");
139925
- }
139926
- else
139927
- {
139928
- dot.setWorldPos(initWorldPos);
139929
- setPlaneCoord(initPlaneCoord);
139930
- }
139931
- updatePointerLens(null);
139932
- set_other_dots_active(true, dot);
139933
- }
139934
140228
  });
139935
140229
  return dot;
139936
140230
  });
139937
- const set_other_dots_active = (active, dot) => dots.forEach(d => (d !== dot) && d.setActive(active));
139938
- set_other_dots_active(true);
140231
+
140232
+ const cleanupDrag = activateDraggableDots({
140233
+ viewer: viewer,
140234
+ handleMouseEvents: handleMouseEvents,
140235
+ handleTouchEvents: handleTouchEvents,
140236
+ pointerLens: cfg && cfg.pointerLens,
140237
+ dots: dots,
140238
+ ray2WorldPos: (orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir),
140239
+ onEnd: (initPos, dot) => {
140240
+ if (zone._zoneMesh)
140241
+ {
140242
+ this.fire("edited");
140243
+ }
140244
+ return !! zone._zoneMesh;
140245
+ }
140246
+ });
139939
140247
 
139940
140248
  const cleanup = function() {
139941
- dots.forEach(m => m.destroy());
139942
- updatePointerLens(null);
140249
+ cleanupDrag();
140250
+ dots.forEach(d => d.destroy());
139943
140251
  };
139944
140252
 
139945
140253
  const destroyCb = zone.on("destroyed", cleanup);
@@ -140154,4 +140462,4 @@ class ZoneTranslateTouchControl extends ZoneTranslateControl {
140154
140462
  }
140155
140463
  }
140156
140464
 
140157
- export { AlphaFormat, AmbientLight, AngleMeasurementEditMouseControl, AngleMeasurementEditTouchControl, AngleMeasurementsControl, AngleMeasurementsMouseControl, AngleMeasurementsPlugin, AngleMeasurementsTouchControl, AnnotationsPlugin, AxisGizmoPlugin, BCFViewpointsPlugin, Bitmap, ByteType, CameraMemento, CameraPath, CameraPathAnimation, CityJSONLoaderPlugin, ClampToEdgeWrapping, Component, CompressedMediaType, Configs, ContextMenu, CubicBezierCurve, Curve, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DirLight, DistanceMeasurementEditMouseControl, DistanceMeasurementEditTouchControl, DistanceMeasurementsControl, DistanceMeasurementsMouseControl, DistanceMeasurementsPlugin, DistanceMeasurementsTouchControl, DotBIMDefaultDataSource, DotBIMLoaderPlugin, EdgeMaterial, EmphasisMaterial, FaceAlignedSectionPlanesPlugin, FastNavPlugin, FloatType, Fresnel, Frustum$1 as Frustum, FrustumPlane, GIFMediaType, GLTFDefaultDataSource, GLTFLoaderPlugin, HalfFloatType, ImagePlane, IntType, JPEGMediaType, KTX2TextureTranscoder, LASLoaderPlugin, LambertMaterial, LightMap, LineSet, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Loader, LoadingManager, LocaleService, LuminanceAlphaFormat, LuminanceFormat, Map$1 as Map, Marker, MarqueePicker, MarqueePickerMouseControl, Mesh, MetallicMaterial, MirroredRepeatWrapping, ModelMemento, NavCubePlugin, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, Node$2 as Node, OBJLoaderPlugin, ObjectsKdTree3, ObjectsMemento, PNGMediaType, Path, PerformanceModel, PhongMaterial, PickResult, Plugin, PointLight, PointerCircle, PointerLens, QuadraticBezierCurve, Queue, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, ReadableGeometry, RedFormat, RedIntegerFormat, ReflectionMap, RepeatWrapping, STLDefaultDataSource, STLLoaderPlugin, SceneModel, SceneModelMesh, SceneModelTransform, SectionPlane, SectionPlanesPlugin, ShortType, Skybox, SkyboxesPlugin, SpecularMaterial, SplineCurve, SpriteMarker, StoreyViewsPlugin, Texture, TextureTranscoder, TreeViewPlugin, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VBOGeometry, ViewCullPlugin, Viewer, WebIFCLoaderPlugin, WorkerPool$1 as WorkerPool, XKTDefaultDataSource, XKTLoaderPlugin, XML3DLoaderPlugin, ZoneEditControl, ZoneEditMouseControl, ZoneEditTouchControl, ZoneTranslateControl, ZoneTranslateMouseControl, ZoneTranslateTouchControl, ZonesMouseControl, ZonesPlugin, ZonesPolysurfaceMouseControl, ZonesPolysurfaceTouchControl, ZonesTouchControl, buildBoxGeometry, buildBoxLinesGeometry, buildBoxLinesGeometryFromAABB, buildCylinderGeometry, buildGridGeometry, buildPlaneGeometry, buildPolylineGeometry, buildPolylineGeometryFromCurve, buildSphereGeometry, buildTorusGeometry, buildVectorTextGeometry, createRTCViewMat, frustumIntersectsAABB3, getKTX2TextureTranscoder, getPlaneRTCPos, load3DSGeometry, loadOBJGeometry, math, rtcToWorldPos, sRGBEncoding, setFrustum, stats, utils, worldToRTCPos, worldToRTCPositions };
140465
+ export { AlphaFormat, AmbientLight, AngleMeasurementEditMouseControl, AngleMeasurementEditTouchControl, AngleMeasurementsControl, AngleMeasurementsMouseControl, AngleMeasurementsPlugin, AngleMeasurementsTouchControl, AnnotationsPlugin, AxisGizmoPlugin, BCFViewpointsPlugin, Bitmap, ByteType, CameraMemento, CameraPath, CameraPathAnimation, CityJSONLoaderPlugin, ClampToEdgeWrapping, Component, CompressedMediaType, Configs, ContextMenu, CubicBezierCurve, Curve, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DirLight, DistanceMeasurementEditMouseControl, DistanceMeasurementEditTouchControl, DistanceMeasurementsControl, DistanceMeasurementsMouseControl, DistanceMeasurementsPlugin, DistanceMeasurementsTouchControl, DotBIMDefaultDataSource, DotBIMLoaderPlugin, EdgeMaterial, EmphasisMaterial, FaceAlignedSectionPlanesPlugin, FastNavPlugin, FloatType, Fresnel, Frustum$1 as Frustum, FrustumPlane, GIFMediaType, GLTFDefaultDataSource, GLTFLoaderPlugin, HalfFloatType, ImagePlane, IntType, JPEGMediaType, KTX2TextureTranscoder, LASLoaderPlugin, LambertMaterial, LightMap, LineSet, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Loader, LoadingManager, LocaleService, LuminanceAlphaFormat, LuminanceFormat, Map$1 as Map, Marker, MarqueePicker, MarqueePickerMouseControl, Mesh, MetallicMaterial, MirroredRepeatWrapping, ModelMemento, NavCubePlugin, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, Node$2 as Node, OBJLoaderPlugin, ObjectsKdTree3, ObjectsMemento, PNGMediaType, Path, PerformanceModel, PhongMaterial, PickResult, Plugin, PointLight, PointerCircle, PointerLens, QuadraticBezierCurve, Queue, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, ReadableGeometry, RedFormat, RedIntegerFormat, ReflectionMap, RepeatWrapping, STLDefaultDataSource, STLLoaderPlugin, SceneModel, SceneModelMesh, SceneModelTransform, SectionPlane, SectionPlanesPlugin, ShortType, Skybox, SkyboxesPlugin, SpecularMaterial, SplineCurve, SpriteMarker, StoreyViewsPlugin, Texture, TextureTranscoder, TreeViewPlugin, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VBOGeometry, ViewCullPlugin, Viewer, WebIFCLoaderPlugin, WorkerPool$1 as WorkerPool, XKTDefaultDataSource, XKTLoaderPlugin, XML3DLoaderPlugin, ZoneEditControl, ZoneEditMouseControl, ZoneEditTouchControl, ZoneTranslateControl, ZoneTranslateMouseControl, ZoneTranslateTouchControl, ZonesMouseControl, ZonesPlugin, ZonesPolysurfaceMouseControl, ZonesPolysurfaceTouchControl, ZonesTouchControl, buildBoxGeometry, buildBoxLinesGeometry, buildBoxLinesGeometryFromAABB, buildCylinderGeometry, buildGridGeometry, buildLineGeometry, buildPlaneGeometry, buildPolylineGeometry, buildPolylineGeometryFromCurve, buildSphereGeometry, buildTorusGeometry, buildVectorTextGeometry, createRTCViewMat, frustumIntersectsAABB3, getKTX2TextureTranscoder, getPlaneRTCPos, load3DSGeometry, loadOBJGeometry, math, rtcToWorldPos, sRGBEncoding, setFrustum, stats, utils, worldToRTCPos, worldToRTCPositions };