@inweb/viewer-three 25.10.1 → 25.11.1

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.
@@ -1,8 +1,8 @@
1
- import { Box3, Vector3, Sphere, Vector2, Raycaster, MeshBasicMaterial, LoadingManager, LoaderUtils, MOUSE, TOUCH, EventDispatcher, Clock, Quaternion, Object3D, Euler, Matrix4, LineBasicMaterial, CylinderGeometry, BoxGeometry, BufferGeometry, Float32BufferAttribute, Mesh, OctahedronGeometry, Line, SphereGeometry, TorusGeometry, PlaneGeometry, DoubleSide, Plane, AmbientLight, DirectionalLight, Color, PMREMGenerator, OrthographicCamera, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, Vector4, Scene, PerspectiveCamera, WebGLRenderer, LinearToneMapping } from "three";
1
+ import { Vector2, Raycaster, MeshBasicMaterial, Box3, Vector3, Sphere, LoadingManager, LoaderUtils, EventDispatcher, MOUSE, TOUCH, Quaternion, Spherical, Clock, Object3D, Euler, Matrix4, LineBasicMaterial, CylinderGeometry, BoxGeometry, BufferGeometry, Float32BufferAttribute, Mesh, OctahedronGeometry, Line, SphereGeometry, TorusGeometry, PlaneGeometry, DoubleSide, Plane, AmbientLight, DirectionalLight, Color, PMREMGenerator, OrthographicCamera, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, Vector4, Scene, PerspectiveCamera, WebGLRenderer, LinearToneMapping } from "three";
2
2
 
3
3
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
4
4
 
5
- import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
5
+ import Konva from "konva";
6
6
 
7
7
  import { RoomEnvironment } from "three/examples/jsm/environments/RoomEnvironment.js";
8
8
 
@@ -105,7 +105,8 @@ function defaultOptions() {
105
105
  reverseZoomWheel: false,
106
106
  enableZoomWheel: true,
107
107
  enableGestures: true,
108
- geometryType: "vsfx"
108
+ geometryType: "vsfx",
109
+ rulerUnit: "Default"
109
110
  };
110
111
  }
111
112
 
@@ -365,6 +366,13 @@ class Options {
365
366
  this._data.geometryType = value;
366
367
  this.change();
367
368
  }
369
+ get rulerUnit() {
370
+ return this._data.rulerUnit;
371
+ }
372
+ set rulerUnit(value) {
373
+ this._data.rulerUnit = value;
374
+ this.change();
375
+ }
368
376
  }
369
377
 
370
378
  const CanvasEvents = [ "click", "contextmenu", "dblclick", "mousedown", "mouseleave", "mousemove", "mouseup", "pointercancel", "pointerdown", "pointerleave", "pointermove", "pointerup", "touchcancel", "touchend", "touchmove", "touchstart", "wheel" ];
@@ -386,16 +394,106 @@ function applyModelTransform(viewer, model) {
386
394
 
387
395
  commands("ThreeJS").registerCommand("applyModelTransform", applyModelTransform);
388
396
 
389
- commands("ThreeJS").registerCommand("clearMarkup", (viewer => console.warn("clearMarkup not implemented")));
397
+ commands("ThreeJS").registerCommand("clearMarkup", (viewer => viewer.clearOverlay()));
390
398
 
391
399
  commands("ThreeJS").registerCommandAlias("clearMarkup", "clearOverlay");
392
400
 
393
- function clearSlices(viewer) {
394
- viewer.renderer.clippingPlanes = [];
401
+ class SelectionComponent {
402
+ constructor(viewer) {
403
+ this.onPointerDown = event => {
404
+ if (!event.isPrimary || event.button !== 0) return;
405
+ this.getMousePosition(event, this.downPosition);
406
+ };
407
+ this.onPointerUp = event => {
408
+ if (!event.isPrimary) return;
409
+ const upPosition = this.getMousePosition(event, new Vector2);
410
+ if (this.downPosition.distanceTo(upPosition) !== 0) return;
411
+ const intersects = this.getPointerIntersects(upPosition);
412
+ this.clearSelection();
413
+ if (intersects.length > 0) this.select(intersects[0].object);
414
+ this.viewer.update();
415
+ this.viewer.emitEvent({
416
+ type: "select",
417
+ data: undefined,
418
+ handles: this.viewer.getSelected()
419
+ });
420
+ };
421
+ this.onDoubleClick = event => {
422
+ if (event.button !== 0) return;
423
+ this.viewer.executeCommand("zoomToSelected");
424
+ };
425
+ this.optionsChange = () => {
426
+ const {facesColor: facesColor, facesTransparancy: facesTransparancy} = this.viewer.options;
427
+ this.facesMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
428
+ this.facesMaterial.opacity = (255 - facesTransparancy) / 255;
429
+ this.viewer.update();
430
+ };
431
+ this.viewer = viewer;
432
+ this.raycaster = new Raycaster;
433
+ this.downPosition = new Vector2;
434
+ const {facesColor: facesColor, facesTransparancy: facesTransparancy} = this.viewer.options;
435
+ this.facesMaterial = new MeshBasicMaterial;
436
+ this.facesMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
437
+ this.facesMaterial.opacity = (255 - facesTransparancy) / 255;
438
+ this.facesMaterial.transparent = true;
439
+ this.viewer.addEventListener("pointerdown", this.onPointerDown);
440
+ this.viewer.addEventListener("pointerup", this.onPointerUp);
441
+ this.viewer.addEventListener("dblclick", this.onDoubleClick);
442
+ this.viewer.addEventListener("optionschange", this.optionsChange);
443
+ }
444
+ dispose() {
445
+ this.facesMaterial.dispose();
446
+ this.viewer.removeEventListener("pointerdown", this.onPointerDown);
447
+ this.viewer.removeEventListener("pointerup", this.onPointerUp);
448
+ this.viewer.removeEventListener("dblclick", this.onDoubleClick);
449
+ this.viewer.removeEventListener("optionschange", this.optionsChange);
450
+ }
451
+ getMousePosition(event, target) {
452
+ return target.set(event.clientX, event.clientY);
453
+ }
454
+ getPointerIntersects(mouse) {
455
+ const rect = this.viewer.canvas.getBoundingClientRect();
456
+ const x = (mouse.x - rect.left) / rect.width * 2 - 1;
457
+ const y = -(mouse.y - rect.top) / rect.height * 2 + 1;
458
+ const coords = new Vector2(x, y);
459
+ this.raycaster.setFromCamera(coords, this.viewer.camera);
460
+ const objects = [];
461
+ this.viewer.scene.traverseVisible((child => objects.push(child)));
462
+ return this.raycaster.intersectObjects(objects, false);
463
+ }
464
+ select(object) {
465
+ if (object.isSelected) return;
466
+ object.isSelected = true;
467
+ object.originalMaterial = object.material;
468
+ object.material = this.facesMaterial;
469
+ this.viewer.selected.push(object);
470
+ }
471
+ clearSelection() {
472
+ this.viewer.selected.forEach((object => {
473
+ object.isSelected = false;
474
+ object.material = object.originalMaterial;
475
+ }));
476
+ this.viewer.selected.length = 0;
477
+ }
478
+ }
479
+
480
+ function clearSelected(viewer) {
481
+ const selection = new SelectionComponent(viewer);
482
+ selection.clearSelection();
483
+ selection.dispose();
395
484
  viewer.update();
485
+ viewer.emitEvent({
486
+ type: "select",
487
+ data: undefined,
488
+ handles: []
489
+ });
396
490
  }
397
491
 
398
- commands("ThreeJS").registerCommand("clearSlices", clearSlices);
492
+ commands("ThreeJS").registerCommand("clearSelected", clearSelected);
493
+
494
+ commands("ThreeJS").registerCommandAlias("clearSelected", "unselect");
495
+
496
+ commands("ThreeJS").registerCommand("clearSlices", (viewer => viewer.clearSlices()));
399
497
 
400
498
  function createPreview(viewer, type = "image/jpeg", encoderOptions = .25) {
401
499
  viewer.update(true);
@@ -444,7 +542,7 @@ function explodeScene(scene, scale = 0) {
444
542
  function explode(viewer, index = 0) {
445
543
  viewer.models.forEach((gltf => explodeScene(gltf.scene, index)));
446
544
  viewer.update();
447
- viewer.emit({
545
+ viewer.emitEvent({
448
546
  type: "explode",
449
547
  data: index
450
548
  });
@@ -459,8 +557,8 @@ const defaultViewPositions = {
459
557
  bottom: new Vector3(0, 0, -1),
460
558
  left: new Vector3(-1, 0, 0),
461
559
  right: new Vector3(1, 0, 0),
462
- front: new Vector3(0, 1, 0),
463
- back: new Vector3(0, -1, 0),
560
+ front: new Vector3(0, -1, 0),
561
+ back: new Vector3(0, 1, 0),
464
562
  sw: new Vector3(-.5, -.5, 1).normalize(),
465
563
  se: new Vector3(.5, -.5, 1).normalize(),
466
564
  ne: new Vector3(.5, .5, 1).normalize(),
@@ -469,15 +567,15 @@ const defaultViewPositions = {
469
567
 
470
568
  function setDefaultViewPosition(viewer, position) {
471
569
  const direction = defaultViewPositions[position] || defaultViewPositions["sw"];
472
- const camera = viewer.camera;
473
570
  const center = viewer.extents.getCenter(new Vector3);
474
571
  const sphere = viewer.extents.getBoundingSphere(new Sphere);
475
- const offset = (new Vector3).copy(direction).multiplyScalar(sphere.radius);
476
- camera.position.copy(center);
477
- camera.position.add(offset);
478
- camera.rotation.set(0, 0, 0);
572
+ const offet = direction.clone().multiplyScalar(sphere.radius);
573
+ const camera = viewer.camera;
574
+ camera.position.copy(center).add(offet);
479
575
  camera.lookAt(center);
480
576
  camera.updateProjectionMatrix();
577
+ camera.updateMatrixWorld();
578
+ viewer.target.copy(center);
481
579
  viewer.update();
482
580
  viewer.emit({
483
581
  type: "viewposition",
@@ -550,95 +648,16 @@ function getSelected(viewer) {
550
648
 
551
649
  commands("ThreeJS").registerCommand("getSelected", getSelected);
552
650
 
553
- class SelectionComponent {
554
- constructor(viewer) {
555
- this.onPointerDown = event => {
556
- if (!event.isPrimary || event.button !== 0) return;
557
- this.getMousePosition(event, this.downPosition);
558
- };
559
- this.onPointerUp = event => {
560
- if (!event.isPrimary) return;
561
- const upPosition = this.getMousePosition(event, new Vector2);
562
- if (this.downPosition.distanceTo(upPosition) !== 0) return;
563
- const intersects = this.getPointerIntersects(upPosition);
564
- this.clearSelection();
565
- if (intersects.length > 0) this.select(intersects[0].object);
566
- this.viewer.update();
567
- this.viewer.emitEvent({
568
- type: "select",
569
- data: undefined,
570
- handles: this.viewer.getSelected()
571
- });
572
- };
573
- this.onDoubleClick = event => {
574
- if (event.button !== 0) return;
575
- this.viewer.executeCommand("zoomToSelected");
576
- };
577
- this.optionsChange = () => {
578
- const {facesColor: facesColor, facesTransparancy: facesTransparancy} = this.viewer.options;
579
- this.facesMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
580
- this.facesMaterial.opacity = (255 - facesTransparancy) / 255;
581
- this.viewer.update();
582
- };
583
- this.viewer = viewer;
584
- this.raycaster = new Raycaster;
585
- this.downPosition = new Vector2;
586
- const {facesColor: facesColor, facesTransparancy: facesTransparancy} = this.viewer.options;
587
- this.facesMaterial = new MeshBasicMaterial;
588
- this.facesMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
589
- this.facesMaterial.opacity = (255 - facesTransparancy) / 255;
590
- this.facesMaterial.transparent = true;
591
- this.viewer.addEventListener("pointerdown", this.onPointerDown);
592
- this.viewer.addEventListener("pointerup", this.onPointerUp);
593
- this.viewer.addEventListener("dblclick", this.onDoubleClick);
594
- this.viewer.addEventListener("optionschange", this.optionsChange);
595
- }
596
- dispose() {
597
- this.facesMaterial.dispose();
598
- this.viewer.removeEventListener("pointerdown", this.onPointerDown);
599
- this.viewer.removeEventListener("pointerup", this.onPointerUp);
600
- this.viewer.removeEventListener("dblclick", this.onDoubleClick);
601
- this.viewer.removeEventListener("optionschange", this.optionsChange);
602
- }
603
- getMousePosition(event, position) {
604
- const rect = this.viewer.canvas.getBoundingClientRect();
605
- position.setX((event.clientX - rect.left) / rect.width);
606
- position.setY((event.clientY - rect.top) / rect.height);
607
- return position;
608
- }
609
- getPointerIntersects(position) {
610
- const mouse = new Vector2(position.x * 2 - 1, -(position.y * 2) + 1);
611
- this.raycaster.setFromCamera(mouse, this.viewer.camera);
612
- const objects = [];
613
- this.viewer.scene.traverseVisible((child => objects.push(child)));
614
- return this.raycaster.intersectObjects(objects, false);
615
- }
616
- select(object) {
617
- if (object.isSelected) return;
618
- object.isSelected = true;
619
- object.originalMaterial = object.material;
620
- object.material = this.facesMaterial;
621
- this.viewer.selected.push(object);
622
- }
623
- clearSelection() {
624
- this.viewer.selected.forEach((object => {
625
- object.isSelected = false;
626
- object.material = object.originalMaterial;
627
- }));
628
- this.viewer.selected.length = 0;
629
- }
630
- }
631
-
632
651
  function hideSelected(viewer) {
633
652
  viewer.selected.forEach((object => object.visible = false));
634
653
  const selection = new SelectionComponent(viewer);
635
654
  selection.clearSelection();
636
655
  selection.dispose();
637
656
  viewer.update();
638
- viewer.emit({
657
+ viewer.emitEvent({
639
658
  type: "hide"
640
659
  });
641
- viewer.emit({
660
+ viewer.emitEvent({
642
661
  type: "select",
643
662
  data: undefined,
644
663
  handles: []
@@ -659,7 +678,7 @@ function isolateSelected(viewer) {
659
678
  }
660
679
  isolateObject(viewer.scene, 0);
661
680
  viewer.update();
662
- viewer.emit({
681
+ viewer.emitEvent({
663
682
  type: "isolate"
664
683
  });
665
684
  }
@@ -676,11 +695,11 @@ function regenerateAll(viewer) {
676
695
  commands("ThreeJS").registerCommand("regenerateAll", regenerateAll);
677
696
 
678
697
  function resetView(viewer) {
679
- viewer.executeCommand("setActiveDragger", "");
698
+ viewer.executeCommand("setActiveDragger");
680
699
  viewer.executeCommand("clearSlices");
681
700
  viewer.executeCommand("clearOverlay");
682
701
  viewer.executeCommand("setMarkupColor");
683
- viewer.executeCommand("unselect");
702
+ viewer.executeCommand("clearSelected");
684
703
  viewer.executeCommand("showAll");
685
704
  viewer.executeCommand("explode", 0);
686
705
  viewer.executeCommand("zoomToExtents", true);
@@ -722,7 +741,7 @@ function setSelected(viewer, handles = []) {
722
741
  objects.forEach((object => selection.select(object)));
723
742
  selection.dispose();
724
743
  viewer.update();
725
- viewer.emit({
744
+ viewer.emitEvent({
726
745
  type: "select",
727
746
  data: undefined,
728
747
  handles: handles
@@ -734,160 +753,2679 @@ commands("ThreeJS").registerCommand("setSelected", setSelected);
734
753
  function showAll(viewer) {
735
754
  viewer.scene.traverse((object => object.visible = true));
736
755
  viewer.update();
737
- viewer.emit({
756
+ viewer.emitEvent({
738
757
  type: "showall"
739
758
  });
740
759
  }
741
760
 
742
- commands("ThreeJS").registerCommand("showAll", showAll);
761
+ commands("ThreeJS").registerCommand("showAll", showAll);
762
+
763
+ function zoomToExtents(viewer) {
764
+ if (viewer.extents.isEmpty()) return;
765
+ const center = viewer.extents.getCenter(new Vector3);
766
+ const distance = viewer.extents.getBoundingSphere(new Sphere).radius;
767
+ const delta = new Vector3(0, 0, 1);
768
+ delta.applyQuaternion(viewer.camera.quaternion);
769
+ delta.multiplyScalar(distance * 3);
770
+ viewer.camera.position.copy(center).add(delta);
771
+ viewer.target.copy(center);
772
+ viewer.update();
773
+ viewer.emitEvent({
774
+ type: "zoom"
775
+ });
776
+ }
777
+
778
+ commands("ThreeJS").registerCommand("zoomToExtents", zoomToExtents);
779
+
780
+ commands("ThreeJS").registerCommandAlias("zoomToExtents", "zoomExtents");
781
+
782
+ function zoomToObjects(viewer, handles = []) {
783
+ const handleSet = new Set(handles);
784
+ const objects = [];
785
+ viewer.scene.traverseVisible((child => {
786
+ var _a;
787
+ if (handleSet.has((_a = child.userData) === null || _a === void 0 ? void 0 : _a.handle)) objects.push(child);
788
+ }));
789
+ const extents = objects.reduce(((result, object) => {
790
+ const objectExtents = (new Box3).setFromObject(object);
791
+ return result.isEmpty() ? result.copy(objectExtents) : result.union(objectExtents);
792
+ }), new Box3);
793
+ const center = extents.getCenter(new Vector3);
794
+ const distance = extents.getBoundingSphere(new Sphere).radius;
795
+ const delta = new Vector3(0, 0, 1);
796
+ delta.applyQuaternion(viewer.camera.quaternion);
797
+ delta.multiplyScalar(distance * 3);
798
+ viewer.camera.position.copy(center).add(delta);
799
+ viewer.target.copy(center);
800
+ viewer.update();
801
+ viewer.emitEvent({
802
+ type: "zoom"
803
+ });
804
+ }
805
+
806
+ commands("ThreeJS").registerCommand("zoomToObjects", zoomToObjects);
807
+
808
+ function zoomToSelected(viewer) {
809
+ const extents = viewer.selected.reduce(((result, object) => {
810
+ const objectExtents = (new Box3).setFromObject(object);
811
+ return result.isEmpty() ? result.copy(objectExtents) : result.union(objectExtents);
812
+ }), new Box3);
813
+ if (extents.isEmpty()) extents.copy(viewer.extents);
814
+ const center = extents.getCenter(new Vector3);
815
+ const distance = extents.getBoundingSphere(new Sphere).radius;
816
+ const delta = new Vector3(0, 0, 1);
817
+ delta.applyQuaternion(viewer.camera.quaternion);
818
+ delta.multiplyScalar(distance * 3);
819
+ viewer.camera.position.copy(center).add(delta);
820
+ viewer.target.copy(center);
821
+ viewer.update();
822
+ viewer.emitEvent({
823
+ type: "zoom"
824
+ });
825
+ }
826
+
827
+ commands("ThreeJS").registerCommand("zoomToSelected", zoomToSelected);
828
+
829
+ class GLTFLoadingManager extends LoadingManager {
830
+ constructor(file, externalData = new Map, params = {}) {
831
+ super();
832
+ this.path = "";
833
+ this.resourcePath = "";
834
+ this.fileURL = "";
835
+ this.dataURLs = new Map;
836
+ this.path = params.path || "";
837
+ if (typeof file === "string") {
838
+ this.fileURL = file;
839
+ this.resourcePath = LoaderUtils.extractUrlBase(file);
840
+ } else {
841
+ externalData.forEach(((value, key) => this.fileURL = value === file ? key : this.fileURL));
842
+ externalData.set(this.fileURL, file);
843
+ }
844
+ externalData.forEach(((value, key) => {
845
+ let dataURL;
846
+ if (typeof value === "string") dataURL = value; else dataURL = URL.createObjectURL(new Blob([ value ]));
847
+ this.dataURLs.set(key, dataURL);
848
+ }));
849
+ this.setURLModifier((url => {
850
+ const key = decodeURI(url).replace(this.path, "").replace(this.resourcePath, "").replace(/^(\.?\/)/, "");
851
+ const dataURL = this.dataURLs.get(key);
852
+ return dataURL !== null && dataURL !== void 0 ? dataURL : url;
853
+ }));
854
+ }
855
+ dispose() {
856
+ this.dataURLs.forEach(URL.revokeObjectURL);
857
+ }
858
+ }
859
+
860
+ class EventEmitter2 {
861
+ constructor() {
862
+ this._listeners = {};
863
+ }
864
+ addEventListener(type, listener) {
865
+ if (this._listeners[type] === undefined) this._listeners[type] = [];
866
+ this._listeners[type].push(listener);
867
+ return this;
868
+ }
869
+ removeEventListener(type, listener) {
870
+ if (this._listeners[type] === undefined) return this;
871
+ const listeners = this._listeners[type].filter((x => x !== listener));
872
+ if (listeners.length !== 0) this._listeners[type] = listeners; else delete this._listeners[type];
873
+ return this;
874
+ }
875
+ removeAllListeners(type) {
876
+ if (type) delete this._listeners[type]; else this._listeners = {};
877
+ return this;
878
+ }
879
+ emitEvent(event) {
880
+ if (this._listeners[event.type] === undefined) return false;
881
+ const invoke = this._listeners[event.type].slice();
882
+ invoke.forEach((listener => listener.call(this, event)));
883
+ return true;
884
+ }
885
+ on(type, listener) {
886
+ return this.addEventListener(type, listener);
887
+ }
888
+ off(type, listener) {
889
+ return this.removeEventListener(type, listener);
890
+ }
891
+ emit(type, ...args) {
892
+ if (typeof type === "string") return this.emitEvent({
893
+ type: type,
894
+ args: args
895
+ }); else if (typeof type === "object") return this.emitEvent(type); else return false;
896
+ }
897
+ }
898
+
899
+ class WorldTransform {
900
+ screenToWorld(position) {
901
+ return {
902
+ x: position.x,
903
+ y: position.y,
904
+ z: 0
905
+ };
906
+ }
907
+ worldToScreen(position) {
908
+ return {
909
+ x: position.x,
910
+ y: position.y
911
+ };
912
+ }
913
+ getScale() {
914
+ return {
915
+ x: 1,
916
+ y: 1,
917
+ z: 1
918
+ };
919
+ }
920
+ }
921
+
922
+ class MarkupColor {
923
+ constructor(r, g, b) {
924
+ this.setColor(r, g, b);
925
+ }
926
+ asHex() {
927
+ return "#" + this.HEX;
928
+ }
929
+ asRGB() {
930
+ return {
931
+ r: this.R,
932
+ g: this.G,
933
+ b: this.B
934
+ };
935
+ }
936
+ setColor(r, g, b) {
937
+ this.R = r;
938
+ this.G = g;
939
+ this.B = b;
940
+ this.HEX = this.rgbToHex(r, g, b);
941
+ }
942
+ rgbToHex(r, g, b) {
943
+ const valueToHex = c => {
944
+ const hex = c.toString(16);
945
+ return hex === "0" ? "00" : hex;
946
+ };
947
+ return valueToHex(r) + valueToHex(g) + valueToHex(b);
948
+ }
949
+ }
950
+
951
+ const LineTypeSpecs = new Map([ [ "solid", [] ], [ "dot", [ 30, 30, .001, 30 ] ], [ "dash", [ 30, 30 ] ] ]);
952
+
953
+ class KonvaLine {
954
+ constructor(params, ref = null) {
955
+ var _a, _b;
956
+ if (ref) {
957
+ this._ref = ref;
958
+ return;
959
+ }
960
+ if (!params) params = {};
961
+ if (!params.points) params.points = [ {
962
+ x: 50,
963
+ y: 50
964
+ }, {
965
+ x: 100,
966
+ y: 100
967
+ } ];
968
+ const konvaPoints = [];
969
+ params.points.forEach((point => konvaPoints.push(point.x, point.y)));
970
+ this._ref = new Konva.Line({
971
+ stroke: (_a = params.color) !== null && _a !== void 0 ? _a : "#ff0000",
972
+ strokeWidth: (_b = params.width) !== null && _b !== void 0 ? _b : 4,
973
+ globalCompositeOperation: "source-over",
974
+ lineCap: "round",
975
+ lineJoin: "round",
976
+ points: konvaPoints,
977
+ draggable: true,
978
+ strokeScaleEnabled: false,
979
+ dash: LineTypeSpecs.get(params.type) || []
980
+ });
981
+ this._ref.on("transform", (e => {
982
+ const attrs = e.target.attrs;
983
+ if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
984
+ }));
985
+ this._ref.id(this._ref._id.toString());
986
+ }
987
+ ref() {
988
+ return this._ref;
989
+ }
990
+ id() {
991
+ return this._ref.id();
992
+ }
993
+ enableMouseEditing(value) {
994
+ this._ref.draggable(value);
995
+ }
996
+ type() {
997
+ return "Line";
998
+ }
999
+ getColor() {
1000
+ return this._ref.stroke();
1001
+ }
1002
+ setColor(hex) {
1003
+ this._ref.stroke(hex);
1004
+ }
1005
+ getRotation() {
1006
+ return this._ref.rotation();
1007
+ }
1008
+ setRotation(degrees) {
1009
+ this._ref.rotation(degrees);
1010
+ }
1011
+ getZIndex() {
1012
+ return this._ref.zIndex();
1013
+ }
1014
+ setZIndex(zIndex) {
1015
+ this._ref.zIndex(zIndex);
1016
+ }
1017
+ delete() {
1018
+ this._ref.destroy();
1019
+ this._ref = null;
1020
+ }
1021
+ getPoints() {
1022
+ return this._ref.points();
1023
+ }
1024
+ setLineWidth(size) {
1025
+ this._ref.strokeWidth(size);
1026
+ }
1027
+ getLineWidth() {
1028
+ return this._ref.strokeWidth();
1029
+ }
1030
+ getLineType() {
1031
+ const typeSpecs = this._ref.dash() || [];
1032
+ let type;
1033
+ switch (typeSpecs) {
1034
+ case LineTypeSpecs.get("dot"):
1035
+ type = "dot";
1036
+ break;
1037
+
1038
+ case LineTypeSpecs.get("dash"):
1039
+ type = "dash";
1040
+ break;
1041
+
1042
+ default:
1043
+ type = "solid";
1044
+ break;
1045
+ }
1046
+ return type;
1047
+ }
1048
+ setLineType(type) {
1049
+ const specs = LineTypeSpecs.get(type);
1050
+ if (specs) this._ref.dash(specs);
1051
+ }
1052
+ addPoints(points) {
1053
+ let newPoints = this._ref.points();
1054
+ points.forEach((point => {
1055
+ newPoints = newPoints.concat([ point.x, point.y ]);
1056
+ }));
1057
+ this._ref.points(newPoints);
1058
+ }
1059
+ }
1060
+
1061
+ class KonvaText {
1062
+ constructor(params, ref = null) {
1063
+ var _a, _b, _c;
1064
+ this.TEXT_FONT_FAMILY = "Calibri";
1065
+ if (ref) {
1066
+ this._ref = ref;
1067
+ return;
1068
+ }
1069
+ if (!params) params = {};
1070
+ if (!params.position) params.position = {
1071
+ x: 100,
1072
+ y: 100
1073
+ };
1074
+ if (!params.text) params.text = "default";
1075
+ this._ref = new Konva.Text({
1076
+ x: params.position.x,
1077
+ y: params.position.y,
1078
+ text: params.text,
1079
+ fontSize: (_a = params.fontSize) !== null && _a !== void 0 ? _a : 34,
1080
+ fontFamily: this.TEXT_FONT_FAMILY,
1081
+ fill: (_b = params.color) !== null && _b !== void 0 ? _b : "#ff0000",
1082
+ align: "left",
1083
+ draggable: true,
1084
+ rotation: (_c = params.rotation) !== null && _c !== void 0 ? _c : 0
1085
+ });
1086
+ this._ref.width(this._ref.getTextWidth());
1087
+ this._ref.on("transform", (e => {
1088
+ const attrs = e.target.attrs;
1089
+ if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
1090
+ const scaleByX = Math.abs(attrs.scaleX - 1) > 1e-5;
1091
+ const scaleByY = Math.abs(attrs.scaleY - 1) > 1e-5;
1092
+ let newWidth = this._ref.width();
1093
+ if (scaleByX) newWidth *= attrs.scaleX;
1094
+ let newHeight = this._ref.height();
1095
+ if (scaleByY) newHeight *= attrs.scaleY;
1096
+ const minWidth = 50;
1097
+ if (newWidth < minWidth) newWidth = minWidth;
1098
+ if (newHeight < Math.round(this.getFontSize())) newHeight = Math.round(this.getFontSize());
1099
+ if (scaleByX) {
1100
+ this._ref.width(newWidth);
1101
+ }
1102
+ if (scaleByY) {
1103
+ this._ref.height(newHeight);
1104
+ }
1105
+ this._ref.scale({
1106
+ x: 1,
1107
+ y: 1
1108
+ });
1109
+ }));
1110
+ this._ref.id(this._ref._id.toString());
1111
+ }
1112
+ ref() {
1113
+ return this._ref;
1114
+ }
1115
+ id() {
1116
+ return this._ref.id();
1117
+ }
1118
+ enableMouseEditing(value) {
1119
+ this._ref.draggable(value);
1120
+ }
1121
+ type() {
1122
+ return "Text";
1123
+ }
1124
+ getColor() {
1125
+ return this._ref.fill();
1126
+ }
1127
+ setColor(hex) {
1128
+ this._ref.fill(hex);
1129
+ }
1130
+ getRotation() {
1131
+ return this._ref.rotation();
1132
+ }
1133
+ setRotation(degrees) {
1134
+ this._ref.rotation(degrees);
1135
+ }
1136
+ getZIndex() {
1137
+ return this._ref.zIndex();
1138
+ }
1139
+ setZIndex(zIndex) {
1140
+ this._ref.zIndex(zIndex);
1141
+ }
1142
+ delete() {
1143
+ this._ref.destroy();
1144
+ this._ref = null;
1145
+ }
1146
+ getText() {
1147
+ return this._ref.text();
1148
+ }
1149
+ setText(text) {
1150
+ this._ref.text(text);
1151
+ }
1152
+ getPosition() {
1153
+ return this._ref.getPosition();
1154
+ }
1155
+ setPosition(x, y) {
1156
+ this._ref.setPosition({
1157
+ x: x,
1158
+ y: y
1159
+ });
1160
+ }
1161
+ getFontSize() {
1162
+ return this._ref.fontSize();
1163
+ }
1164
+ setFontSize(size) {
1165
+ this._ref.fontSize(size);
1166
+ }
1167
+ }
1168
+
1169
+ class KonvaRectangle {
1170
+ constructor(params, ref = null) {
1171
+ var _a, _b, _c, _d;
1172
+ if (ref) {
1173
+ this._ref = ref;
1174
+ return;
1175
+ }
1176
+ if (!params) params = {};
1177
+ if (!params.position) params.position = {
1178
+ x: 100,
1179
+ y: 100
1180
+ };
1181
+ this._ref = new Konva.Rect({
1182
+ stroke: (_a = params.color) !== null && _a !== void 0 ? _a : "#ff0000",
1183
+ strokeWidth: (_b = params.lineWidth) !== null && _b !== void 0 ? _b : 4,
1184
+ globalCompositeOperation: "source-over",
1185
+ lineCap: "round",
1186
+ lineJoin: "round",
1187
+ x: params.position.x,
1188
+ y: params.position.y,
1189
+ width: (_c = params.width) !== null && _c !== void 0 ? _c : 200,
1190
+ height: (_d = params.height) !== null && _d !== void 0 ? _d : 200,
1191
+ draggable: true,
1192
+ strokeScaleEnabled: false
1193
+ });
1194
+ this._ref.on("transform", (e => {
1195
+ const attrs = e.target.attrs;
1196
+ if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
1197
+ const scaleByX = Math.abs(attrs.scaleX - 1) > 1e-5;
1198
+ const scaleByY = Math.abs(attrs.scaleY - 1) > 1e-5;
1199
+ let newWidth = this._ref.width();
1200
+ if (scaleByX) newWidth *= attrs.scaleX;
1201
+ let newHeight = this._ref.height();
1202
+ if (scaleByY) newHeight *= attrs.scaleY;
1203
+ const minWidth = 50;
1204
+ const minHeight = 50;
1205
+ if (newWidth < minWidth) newWidth = minWidth;
1206
+ if (newHeight < minHeight) newHeight = minHeight;
1207
+ if (scaleByX) {
1208
+ this._ref.width(newWidth);
1209
+ }
1210
+ if (scaleByY) {
1211
+ this._ref.height(newHeight);
1212
+ }
1213
+ this._ref.scale({
1214
+ x: 1,
1215
+ y: 1
1216
+ });
1217
+ }));
1218
+ this._ref.id(this._ref._id.toString());
1219
+ }
1220
+ getPosition() {
1221
+ return this._ref.position();
1222
+ }
1223
+ getWidth() {
1224
+ return this._ref.width();
1225
+ }
1226
+ getHeigth() {
1227
+ return this._ref.height();
1228
+ }
1229
+ setWidth(w) {
1230
+ this._ref.width(w);
1231
+ }
1232
+ setHeight(h) {
1233
+ this._ref.height(h);
1234
+ }
1235
+ setPosition(x, y) {
1236
+ this._ref.setPosition({
1237
+ x: x,
1238
+ y: y
1239
+ });
1240
+ }
1241
+ ref() {
1242
+ return this._ref;
1243
+ }
1244
+ id() {
1245
+ return this._ref.id();
1246
+ }
1247
+ enableMouseEditing(value) {
1248
+ this._ref.draggable(value);
1249
+ }
1250
+ type() {
1251
+ return "Rectangle";
1252
+ }
1253
+ getColor() {
1254
+ return this._ref.stroke();
1255
+ }
1256
+ setColor(hex) {
1257
+ this._ref.stroke(hex);
1258
+ }
1259
+ getRotation() {
1260
+ return this._ref.rotation();
1261
+ }
1262
+ setRotation(degrees) {
1263
+ this._ref.rotation(degrees);
1264
+ }
1265
+ getZIndex() {
1266
+ return this._ref.zIndex();
1267
+ }
1268
+ setZIndex(zIndex) {
1269
+ this._ref.zIndex(zIndex);
1270
+ }
1271
+ delete() {
1272
+ this._ref.destroy();
1273
+ this._ref = null;
1274
+ }
1275
+ setLineWidth(size) {
1276
+ this._ref.strokeWidth(size);
1277
+ }
1278
+ getLineWidth() {
1279
+ return this._ref.strokeWidth();
1280
+ }
1281
+ }
1282
+
1283
+ class KonvaEllipse {
1284
+ constructor(params, ref = null) {
1285
+ var _a, _b;
1286
+ if (ref) {
1287
+ this._ref = ref;
1288
+ return;
1289
+ }
1290
+ if (!params) params = {};
1291
+ if (!params.position) params.position = {
1292
+ x: 100,
1293
+ y: 100
1294
+ };
1295
+ if (!params.radius) params.radius = {
1296
+ x: 25,
1297
+ y: 25
1298
+ };
1299
+ this._ref = new Konva.Ellipse({
1300
+ stroke: (_a = params.color) !== null && _a !== void 0 ? _a : "#ff0000",
1301
+ strokeWidth: (_b = params.lineWidth) !== null && _b !== void 0 ? _b : 4,
1302
+ globalCompositeOperation: "source-over",
1303
+ lineCap: "round",
1304
+ lineJoin: "round",
1305
+ x: params.position.x,
1306
+ y: params.position.y,
1307
+ radiusX: params.radius.x,
1308
+ radiusY: params.radius.y,
1309
+ draggable: true,
1310
+ strokeScaleEnabled: false
1311
+ });
1312
+ this._ref.on("transform", (e => {
1313
+ const attrs = e.target.attrs;
1314
+ if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
1315
+ const scaleByX = Math.abs(attrs.scaleX - 1) > 1e-5;
1316
+ const scaleByY = Math.abs(attrs.scaleY - 1) > 1e-5;
1317
+ let newRadiusX = this._ref.radiusX();
1318
+ if (scaleByX) newRadiusX *= attrs.scaleX;
1319
+ let newRadiusY = this._ref.radiusY();
1320
+ if (scaleByY) newRadiusY *= attrs.scaleY;
1321
+ const minRadiusX = 25;
1322
+ const minRadiusY = 25;
1323
+ if (newRadiusX < minRadiusX) newRadiusX = minRadiusX;
1324
+ if (newRadiusY < minRadiusY) newRadiusY = minRadiusY;
1325
+ if (e.evt.ctrlKey || e.evt.shiftKey) {
1326
+ if (scaleByX) {
1327
+ this._ref.radius({
1328
+ x: newRadiusX,
1329
+ y: newRadiusX
1330
+ });
1331
+ } else {
1332
+ this._ref.radius({
1333
+ x: newRadiusY,
1334
+ y: newRadiusY
1335
+ });
1336
+ }
1337
+ } else {
1338
+ this._ref.radius({
1339
+ x: newRadiusX,
1340
+ y: newRadiusY
1341
+ });
1342
+ }
1343
+ this._ref.scale({
1344
+ x: 1,
1345
+ y: 1
1346
+ });
1347
+ }));
1348
+ this._ref.id(this._ref._id.toString());
1349
+ }
1350
+ getPosition() {
1351
+ return this._ref.position();
1352
+ }
1353
+ setPosition(x, y) {
1354
+ this._ref.setPosition({
1355
+ x: x,
1356
+ y: y
1357
+ });
1358
+ }
1359
+ getRadiusX() {
1360
+ return this._ref.radiusX();
1361
+ }
1362
+ setRadiusX(r) {
1363
+ this._ref.radiusX(r);
1364
+ }
1365
+ getRadiusY() {
1366
+ return this._ref.radiusY();
1367
+ }
1368
+ setRadiusY(r) {
1369
+ this._ref.radiusY(r);
1370
+ }
1371
+ getLineWidth() {
1372
+ return this._ref.strokeWidth();
1373
+ }
1374
+ setLineWidth(size) {
1375
+ this._ref.strokeWidth(size);
1376
+ }
1377
+ ref() {
1378
+ return this._ref;
1379
+ }
1380
+ id() {
1381
+ return this._ref.id();
1382
+ }
1383
+ enableMouseEditing(value) {
1384
+ this._ref.draggable(value);
1385
+ }
1386
+ type() {
1387
+ return "Ellipse";
1388
+ }
1389
+ getColor() {
1390
+ return this._ref.stroke();
1391
+ }
1392
+ setColor(hex) {
1393
+ this._ref.stroke(hex);
1394
+ }
1395
+ getRotation() {
1396
+ return this._ref.rotation();
1397
+ }
1398
+ setRotation(degrees) {
1399
+ this._ref.rotation(degrees);
1400
+ }
1401
+ getZIndex() {
1402
+ return this._ref.zIndex();
1403
+ }
1404
+ setZIndex(zIndex) {
1405
+ this._ref.zIndex(zIndex);
1406
+ }
1407
+ delete() {
1408
+ this._ref.destroy();
1409
+ this._ref = null;
1410
+ }
1411
+ }
1412
+
1413
+ class KonvaArrow {
1414
+ constructor(params, ref = null) {
1415
+ var _a, _b;
1416
+ if (ref) {
1417
+ this._ref = ref;
1418
+ return;
1419
+ }
1420
+ if (!params) params = {};
1421
+ if (!params.start) params.start = {
1422
+ x: 50,
1423
+ y: 50
1424
+ };
1425
+ if (!params.end) params.end = {
1426
+ x: 100,
1427
+ y: 100
1428
+ };
1429
+ this._ref = new Konva.Arrow({
1430
+ stroke: (_a = params.color) !== null && _a !== void 0 ? _a : "#ff0000",
1431
+ fill: (_b = params.color) !== null && _b !== void 0 ? _b : "#ff0000",
1432
+ strokeWidth: 4,
1433
+ globalCompositeOperation: "source-over",
1434
+ lineCap: "round",
1435
+ lineJoin: "round",
1436
+ points: [ params.start.x, params.start.y, params.end.x, params.end.y ],
1437
+ draggable: true,
1438
+ strokeScaleEnabled: false
1439
+ });
1440
+ this._ref.on("transform", (e => {
1441
+ const attrs = e.target.attrs;
1442
+ if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
1443
+ }));
1444
+ this._ref.id(this._ref._id.toString());
1445
+ }
1446
+ ref() {
1447
+ return this._ref;
1448
+ }
1449
+ id() {
1450
+ return this._ref.id();
1451
+ }
1452
+ enableMouseEditing(value) {
1453
+ this._ref.draggable(value);
1454
+ }
1455
+ type() {
1456
+ return "Arrow";
1457
+ }
1458
+ getColor() {
1459
+ return this._ref.stroke();
1460
+ }
1461
+ setColor(hex) {
1462
+ this._ref.stroke(hex);
1463
+ this._ref.fill(hex);
1464
+ }
1465
+ getRotation() {
1466
+ return this._ref.rotation();
1467
+ }
1468
+ setRotation(degrees) {
1469
+ this._ref.rotation(degrees);
1470
+ }
1471
+ getZIndex() {
1472
+ return this._ref.zIndex();
1473
+ }
1474
+ setZIndex(zIndex) {
1475
+ this._ref.zIndex(zIndex);
1476
+ }
1477
+ delete() {
1478
+ this._ref.destroy();
1479
+ this._ref = null;
1480
+ }
1481
+ getPoints() {
1482
+ const points = this._ref.points();
1483
+ return [ {
1484
+ x: points[0],
1485
+ y: points[1]
1486
+ }, {
1487
+ x: points[2],
1488
+ y: points[3]
1489
+ } ];
1490
+ }
1491
+ setPoints(points) {
1492
+ if (points.length === 2) {
1493
+ this._ref.points([ points[0].x, points[0].y, points[1].x, points[1].y ]);
1494
+ }
1495
+ }
1496
+ getStartPoint() {
1497
+ const points = this._ref.points();
1498
+ return {
1499
+ x: points[0],
1500
+ y: points[1]
1501
+ };
1502
+ }
1503
+ setStartPoint(x, y) {
1504
+ const points = this._ref.points();
1505
+ this._ref.points([ x, y, points[2], points[3] ]);
1506
+ }
1507
+ getEndPoint() {
1508
+ const points = this._ref.points();
1509
+ return {
1510
+ x: points[2],
1511
+ y: points[3]
1512
+ };
1513
+ }
1514
+ setEndPoint(x, y) {
1515
+ const points = this._ref.points();
1516
+ this._ref.points([ points[0], points[1], x, y ]);
1517
+ }
1518
+ }
1519
+
1520
+ class KonvaImage {
1521
+ constructor(params, ref = null) {
1522
+ var _a, _b;
1523
+ this._ratio = 1;
1524
+ this.EPSILON = 1e-5;
1525
+ this.BASE64_HEADER_START = "data:image/";
1526
+ this.BASE64_NOT_FOUND = "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAADsAAAA7AF5KHG9AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAmhJREFUWIXtlr9rVEEQxz+H8RQUJIdeIopYm0vkCg0GBBtbG1NF7Kxt7dR/IGIw/uhTaBNLERURg2kCEUyCYCPi70b0InjGS57FzOZN3r19d+9HJIVfWO52dma/s7Mz8xa2KAaBCWAR+AkECWOmSOIdwC1gtQOpHc+NfQ8wClQ8+1d0vcdH/lQ3bSIRGAZ2pTjAqNovANXIWlXlAXA2zvi2Ln4AjqYgtagYEutENSLvjRoOImFv5iB32Ae8UrLXwFBk3h9ndF0VJnKSO9gTu3yKu5Z1LKnS8YIcABgw5Ks692JZFXcXRJ46Aq6kikCnHNi/mQ50WwVtfaIoBzL3gRk2drSscJ2wrc4VvUoe2wn/41/iBfoVLRnBGnDSY3AAKacy8AmYR+o7K1zCl6wgrgpOAc/MuhvfgMuk+1JGHQgSBcAloKXy78AjYBppJk5/noTulseBMZ23iD/piHFkEdgTQzKk+5wHjmHC3cmBg0BD5xcSTrFXyQPgIWFtDwMvab+2N8DpbhyY1v/3E8gdDgNfVX9SCVZ0/gW4B0wB71S2BpxLcuCM/jaQSHSDEeAX4VMuAG4gTzyHbcAVXXO6GxxwIX+vvxe7JHcYQ07nHqklj96UIW/YhSWzMKcep8VVtf8B1Dw6h4DfhB+sdbgn2R+gnoEc5NR3dZ+3QJ9H74HqXLPCGlJyTfI9y3YCs0owq3OLOpKkLeBI1HhSDT/mdKIPiUCARMTlQx34TMLjtww8IczmO8AJ/N/2JNSQXAiQ671JePePge0+wzJSQq4FFzlaenIvucUAkiQLhC/mLGNZ9xgn5s63BP4CCk0QDtm4BhoAAAAASUVORK5CYII=";
1527
+ if (ref) {
1528
+ if (!ref.src || !ref.src.startsWith(this.BASE64_HEADER_START)) ref.src = this.BASE64_NOT_FOUND;
1529
+ if (ref.height() <= this.EPSILON) ref.height(32);
1530
+ if (ref.width() <= this.EPSILON) ref.width(32);
1531
+ this._ref = ref;
1532
+ this._canvasImage = ref.image();
1533
+ this._ratio = this._ref.height() <= this.EPSILON || this._ref.width() <= this.EPSILON ? 1 : this._ref.height() / this._ref.width();
1534
+ return;
1535
+ }
1536
+ if (!params) params = {};
1537
+ if (!params.position) params.position = {
1538
+ x: 50,
1539
+ y: 50
1540
+ };
1541
+ if (!params.src || !params.src.startsWith(this.BASE64_HEADER_START)) params.src = this.BASE64_NOT_FOUND;
1542
+ this._canvasImage = new Image;
1543
+ this._canvasImage.onload = () => {
1544
+ this._ref.image(this._canvasImage);
1545
+ if (this._ref.height() <= this.EPSILON) this._ref.height(this._canvasImage.height);
1546
+ if (this._ref.width() <= this.EPSILON) this._ref.width(this._canvasImage.width);
1547
+ this._ratio = this._ref.height() <= this.EPSILON || this._ref.width() <= this.EPSILON ? 1 : this._ref.height() / this._ref.width();
1548
+ if ((params.width <= this.EPSILON || params.height <= this.EPSILON) && (params.maxWidth >= this.EPSILON || params.maxWidth >= this.EPSILON)) {
1549
+ const heightOutOfCanvas = params.maxHeight - this._canvasImage.height;
1550
+ const widthOutOfCanvas = params.maxWidth - this._canvasImage.width;
1551
+ if (heightOutOfCanvas <= this.EPSILON || widthOutOfCanvas <= this.EPSILON) {
1552
+ if (widthOutOfCanvas <= this.EPSILON && widthOutOfCanvas < heightOutOfCanvas / this._ratio) {
1553
+ this._ref.height(params.maxWidth * this._ratio);
1554
+ this._ref.width(params.maxWidth);
1555
+ } else {
1556
+ this._ref.width(params.maxHeight / this._ratio);
1557
+ this._ref.height(params.maxHeight);
1558
+ }
1559
+ }
1560
+ }
1561
+ };
1562
+ this._canvasImage.onerror = () => {
1563
+ this._canvasImage.onerror = function() {};
1564
+ this._canvasImage.src = this.BASE64_NOT_FOUND;
1565
+ };
1566
+ this._canvasImage.src = params.src;
1567
+ this._ref = new Konva.Image({
1568
+ x: params.position.x,
1569
+ y: params.position.y,
1570
+ image: this._canvasImage,
1571
+ width: (_a = params.width) !== null && _a !== void 0 ? _a : 0,
1572
+ height: (_b = params.height) !== null && _b !== void 0 ? _b : 0,
1573
+ draggable: true
1574
+ });
1575
+ this._ref.on("transform", (e => {
1576
+ const attrs = e.target.attrs;
1577
+ if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
1578
+ const scaleByX = Math.abs(attrs.scaleX - 1) > 1e-5;
1579
+ const scaleByY = Math.abs(attrs.scaleY - 1) > 1e-5;
1580
+ let newWidth = this._ref.width();
1581
+ if (scaleByX) newWidth *= attrs.scaleX;
1582
+ let newHeight = this._ref.height();
1583
+ if (scaleByY) newHeight *= attrs.scaleY;
1584
+ if (e.evt.ctrlKey || e.evt.shiftKey) {
1585
+ if (scaleByX) {
1586
+ this._ref.width(newWidth);
1587
+ this._ref.height(newWidth * this._ratio);
1588
+ } else {
1589
+ this._ref.width(newHeight / this._ratio);
1590
+ this._ref.height(newHeight);
1591
+ }
1592
+ } else {
1593
+ if (scaleByX) {
1594
+ this._ref.width(newWidth);
1595
+ }
1596
+ if (scaleByY) {
1597
+ this._ref.height(newHeight);
1598
+ }
1599
+ }
1600
+ this._ref.scale({
1601
+ x: 1,
1602
+ y: 1
1603
+ });
1604
+ }));
1605
+ this._ref.id(this._ref._id.toString());
1606
+ }
1607
+ getSrc() {
1608
+ return this._canvasImage.src;
1609
+ }
1610
+ setSrc(src) {
1611
+ this._canvasImage.src = src;
1612
+ }
1613
+ getWidth() {
1614
+ return this._ref.width();
1615
+ }
1616
+ setWidth(w) {
1617
+ this._ref.width(w);
1618
+ this._ref.height(w * this._ratio);
1619
+ }
1620
+ getHeight() {
1621
+ return this._ref.height();
1622
+ }
1623
+ setHeight(h) {
1624
+ this._ref.height(h);
1625
+ this._ref.width(h / this._ratio);
1626
+ }
1627
+ ref() {
1628
+ return this._ref;
1629
+ }
1630
+ id() {
1631
+ return this._ref.id();
1632
+ }
1633
+ enableMouseEditing(value) {
1634
+ this._ref.draggable(value);
1635
+ }
1636
+ type() {
1637
+ return "Image";
1638
+ }
1639
+ getRotation() {
1640
+ return this._ref.rotation();
1641
+ }
1642
+ setRotation(degrees) {
1643
+ this._ref.rotation(degrees);
1644
+ }
1645
+ getZIndex() {
1646
+ return this._ref.zIndex();
1647
+ }
1648
+ setZIndex(zIndex) {
1649
+ this._ref.zIndex(zIndex);
1650
+ }
1651
+ delete() {
1652
+ this._ref.destroy();
1653
+ this._ref = null;
1654
+ }
1655
+ getPosition() {
1656
+ return this._ref.getPosition();
1657
+ }
1658
+ setPosition(x, y) {
1659
+ this._ref.setPosition({
1660
+ x: x,
1661
+ y: y
1662
+ });
1663
+ }
1664
+ }
1665
+
1666
+ class KonvaCloud {
1667
+ constructor(params, ref = null) {
1668
+ var _a, _b, _c, _d;
1669
+ if (ref) {
1670
+ this._ref = ref;
1671
+ return;
1672
+ }
1673
+ if (!params) params = {};
1674
+ if (!params.position) params.position = {
1675
+ x: 100,
1676
+ y: 100
1677
+ };
1678
+ const arcRadius = 16;
1679
+ this._ref = new Konva.Shape({
1680
+ x: params.position.x,
1681
+ y: params.position.y,
1682
+ width: (_a = params.width) !== null && _a !== void 0 ? _a : 200,
1683
+ height: (_b = params.height) !== null && _b !== void 0 ? _b : 200,
1684
+ stroke: (_c = params.color) !== null && _c !== void 0 ? _c : "#ff0000",
1685
+ strokeWidth: (_d = params.lineWidth) !== null && _d !== void 0 ? _d : 4,
1686
+ draggable: true,
1687
+ strokeScaleEnabled: false,
1688
+ globalCompositeOperation: "source-over",
1689
+ sceneFunc: (context, shape) => {
1690
+ function calculateMidpoint(position, width, height) {
1691
+ const midX = position.x + width / 2;
1692
+ const midY = position.y + height / 2;
1693
+ return {
1694
+ x: midX,
1695
+ y: midY
1696
+ };
1697
+ }
1698
+ const points = [ {
1699
+ x: 0,
1700
+ y: 0
1701
+ }, {
1702
+ x: 0 + this._ref.width(),
1703
+ y: 0
1704
+ }, {
1705
+ x: 0 + this._ref.width(),
1706
+ y: 0 + this._ref.height()
1707
+ }, {
1708
+ x: 0,
1709
+ y: 0 + this._ref.height()
1710
+ }, {
1711
+ x: 0,
1712
+ y: 0
1713
+ } ];
1714
+ const midPoint = calculateMidpoint({
1715
+ x: 0,
1716
+ y: 0
1717
+ }, this._ref.width(), this._ref.height());
1718
+ const baseArcLength = 30;
1719
+ context.beginPath();
1720
+ for (let iPoint = 0; iPoint < points.length - 1; iPoint++) {
1721
+ let approxArcLength = baseArcLength;
1722
+ const dx = points[iPoint + 1].x - points[iPoint].x;
1723
+ const dy = points[iPoint + 1].y - points[iPoint].y;
1724
+ const length = Math.sqrt(dx * dx + dy * dy);
1725
+ const arcCount = Math.floor(length / approxArcLength);
1726
+ const lengthMod = length % approxArcLength;
1727
+ approxArcLength = baseArcLength + arcCount / lengthMod;
1728
+ let pX = points[iPoint].x + dx / arcCount / 2;
1729
+ let pY = points[iPoint].y + dy / arcCount / 2;
1730
+ const pEndX = points[iPoint + 1].x;
1731
+ const pEndY = points[iPoint + 1].y;
1732
+ const endAngle = Math.atan((pEndY - pY) / (pEndX - pX));
1733
+ const startAngle = endAngle + Math.PI;
1734
+ const counterClockwise = pX > midPoint.x && pY > midPoint.y;
1735
+ for (let iArc = 0; iArc < arcCount; iArc++) {
1736
+ if (counterClockwise) {
1737
+ context.arc(pX, pY, arcRadius, endAngle, startAngle);
1738
+ } else {
1739
+ context.arc(pX, pY, arcRadius, startAngle, endAngle);
1740
+ }
1741
+ pX += dx / arcCount;
1742
+ pY += dy / arcCount;
1743
+ }
1744
+ }
1745
+ context.closePath();
1746
+ context.fillStrokeShape(shape);
1747
+ }
1748
+ });
1749
+ this._ref.className = "Cloud";
1750
+ this._ref.on("transform", (e => {
1751
+ const attrs = e.target.attrs;
1752
+ if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
1753
+ const scaleByX = Math.abs(attrs.scaleX - 1) > 1e-5;
1754
+ const scaleByY = Math.abs(attrs.scaleY - 1) > 1e-5;
1755
+ let newWidth = this._ref.width();
1756
+ if (scaleByX) newWidth *= attrs.scaleX;
1757
+ let newHeight = this._ref.height();
1758
+ if (scaleByY) newHeight *= attrs.scaleY;
1759
+ const minWidth = 100;
1760
+ const minHeight = 100;
1761
+ if (newWidth < minWidth) newWidth = minWidth;
1762
+ if (newHeight < minHeight) newHeight = minHeight;
1763
+ if (scaleByX) {
1764
+ this._ref.width(newWidth);
1765
+ }
1766
+ if (scaleByY) {
1767
+ this._ref.height(newHeight);
1768
+ }
1769
+ this._ref.scale({
1770
+ x: 1,
1771
+ y: 1
1772
+ });
1773
+ }));
1774
+ this._ref.getSelfRect = () => ({
1775
+ x: 0 - arcRadius,
1776
+ y: 0 - arcRadius,
1777
+ width: this._ref.width() + 2 * arcRadius,
1778
+ height: this._ref.height() + 2 * arcRadius
1779
+ });
1780
+ this._ref.id(this._ref._id.toString());
1781
+ }
1782
+ ref() {
1783
+ return this._ref;
1784
+ }
1785
+ id() {
1786
+ return this._ref.id();
1787
+ }
1788
+ enableMouseEditing(value) {
1789
+ this._ref.draggable(value);
1790
+ }
1791
+ type() {
1792
+ return "Cloud";
1793
+ }
1794
+ getColor() {
1795
+ return this._ref.stroke();
1796
+ }
1797
+ setColor(hex) {
1798
+ this._ref.stroke(hex);
1799
+ }
1800
+ getRotation() {
1801
+ return this._ref.rotation();
1802
+ }
1803
+ setRotation(degrees) {
1804
+ this._ref.rotation(degrees);
1805
+ }
1806
+ getZIndex() {
1807
+ return this._ref.zIndex();
1808
+ }
1809
+ setZIndex(zIndex) {
1810
+ this._ref.zIndex(zIndex);
1811
+ }
1812
+ delete() {
1813
+ this._ref.destroy();
1814
+ this._ref = null;
1815
+ }
1816
+ getPosition() {
1817
+ return this._ref.position();
1818
+ }
1819
+ setPosition(x, y) {
1820
+ this._ref.position({
1821
+ x: x,
1822
+ y: y
1823
+ });
1824
+ }
1825
+ getWidth() {
1826
+ return this._ref.width();
1827
+ }
1828
+ setWidth(w) {
1829
+ this._ref.width(w);
1830
+ }
1831
+ getHeigth() {
1832
+ return this._ref.height();
1833
+ }
1834
+ setHeight(h) {
1835
+ this._ref.height(h);
1836
+ }
1837
+ getLineWidth() {
1838
+ return this._ref.strokeWidth();
1839
+ }
1840
+ setLineWidth(size) {
1841
+ this._ref.strokeWidth(size);
1842
+ }
1843
+ }
1844
+
1845
+ const MarkupMode2Konva = {
1846
+ SelectMarkup: {
1847
+ name: "SelectMarkup",
1848
+ initializer: null
1849
+ },
1850
+ Line: {
1851
+ name: "Line",
1852
+ initializer: (ref, params = null) => new KonvaLine(params, ref)
1853
+ },
1854
+ Text: {
1855
+ name: "Text",
1856
+ initializer: (ref, params = null) => new KonvaText(params, ref)
1857
+ },
1858
+ Rectangle: {
1859
+ name: "Rect",
1860
+ initializer: (ref, params = null) => new KonvaRectangle(params, ref)
1861
+ },
1862
+ Ellipse: {
1863
+ name: "Ellipse",
1864
+ initializer: (ref, params = null) => new KonvaEllipse(params, ref)
1865
+ },
1866
+ Arrow: {
1867
+ name: "Arrow",
1868
+ initializer: (ref, params = null) => new KonvaArrow(params, ref)
1869
+ },
1870
+ Image: {
1871
+ name: "Image",
1872
+ initializer: (ref, params = null) => new KonvaImage(params, ref)
1873
+ },
1874
+ Cloud: {
1875
+ name: "Cloud",
1876
+ initializer: (ref, params = null) => new KonvaCloud(params, ref)
1877
+ }
1878
+ };
1879
+
1880
+ class KonvaMarkup {
1881
+ constructor() {
1882
+ this._containerEvents = [];
1883
+ this._markupIsActive = false;
1884
+ this._markupColor = new MarkupColor(255, 0, 0);
1885
+ this.lineWidth = 4;
1886
+ this.lineType = "solid";
1887
+ this.fontSize = 34;
1888
+ this.changeActiveDragger = event => {
1889
+ const draggerName = event.data;
1890
+ this._markupContainer.className = this._container.className.split(" ").filter((x => !x.startsWith("oda-cursor-"))).filter((x => x)).concat(`oda-cursor-${draggerName.toLowerCase()}`).join(" ");
1891
+ this.removeTextInput();
1892
+ this.removeImageInput();
1893
+ this.enableEditMode(draggerName);
1894
+ };
1895
+ this.resizeContainer = entries => {
1896
+ const {width: width, height: height} = entries[0].contentRect;
1897
+ if (!width || !height) return;
1898
+ if (!this._konvaStage) return;
1899
+ this._konvaStage.width(width);
1900
+ this._konvaStage.height(height);
1901
+ };
1902
+ this.pan = event => {
1903
+ const newPos = {
1904
+ x: this._konvaStage.x() + event.dX,
1905
+ y: this._konvaStage.y() + event.dY
1906
+ };
1907
+ this._konvaStage.position(newPos);
1908
+ };
1909
+ this.zoomAt = event => {
1910
+ const newScale = this._konvaStage.scaleX() * event.data;
1911
+ this._konvaStage.scale({
1912
+ x: newScale,
1913
+ y: newScale
1914
+ });
1915
+ const newPos = {
1916
+ x: event.x - (event.x - this._konvaStage.x()) * event.data,
1917
+ y: event.y - (event.y - this._konvaStage.y()) * event.data
1918
+ };
1919
+ this._konvaStage.position(newPos);
1920
+ };
1921
+ this.redirectToViewer = event => {
1922
+ if (this._viewer) this._viewer.emit(event);
1923
+ };
1924
+ this.getRelativePointPosition = (point, node) => {
1925
+ const transform = node.getAbsoluteTransform().copy();
1926
+ transform.invert();
1927
+ return transform.point(point);
1928
+ };
1929
+ this.getRelativePointerPosition = node => this.getRelativePointPosition(node.getStage().getPointerPosition(), node);
1930
+ }
1931
+ initialize(container, containerEvents, viewer, worldTransformer) {
1932
+ if (!Konva) throw new Error('Markup error: Konva is not initialized. Forgot to add <script src="https://unpkg.com/konva@9/konva.min.js"><\/script> to your page?');
1933
+ this._viewer = viewer;
1934
+ this._worldTransformer = worldTransformer !== null && worldTransformer !== void 0 ? worldTransformer : new WorldTransform;
1935
+ this._container = container;
1936
+ this._containerEvents = containerEvents !== null && containerEvents !== void 0 ? containerEvents : [];
1937
+ this._markupContainer = document.createElement("div");
1938
+ this._markupContainer.id = "markup-container";
1939
+ this._markupContainer.style.position = "absolute";
1940
+ this._markupContainer.style.top = "0px";
1941
+ this._markupContainer.style.left = "0px";
1942
+ this._markupContainer.style.outline = "0px";
1943
+ this._markupContainer.style.pointerEvents = "none";
1944
+ const parentDiv = this._container.parentElement;
1945
+ parentDiv.appendChild(this._markupContainer);
1946
+ this._resizeObserver = new ResizeObserver(this.resizeContainer);
1947
+ this._resizeObserver.observe(parentDiv);
1948
+ this._markupColor.setColor(255, 0, 0);
1949
+ this.initializeKonva();
1950
+ if (this._viewer) {
1951
+ this._viewer.addEventListener("changeactivedragger", this.changeActiveDragger);
1952
+ this._viewer.addEventListener("pan", this.pan);
1953
+ this._viewer.addEventListener("zoomat", this.zoomAt);
1954
+ }
1955
+ }
1956
+ dispose() {
1957
+ var _a, _b;
1958
+ if (this._viewer) {
1959
+ this._viewer.removeEventListener("zoomat", this.zoomAt);
1960
+ this._viewer.removeEventListener("pan", this.pan);
1961
+ this._viewer.removeEventListener("changeactivedragger", this.changeActiveDragger);
1962
+ }
1963
+ this.destroyKonva();
1964
+ (_a = this._resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
1965
+ this._resizeObserver = undefined;
1966
+ (_b = this._markupContainer) === null || _b === void 0 ? void 0 : _b.remove();
1967
+ this._markupContainer = undefined;
1968
+ this._container = undefined;
1969
+ this._viewer = undefined;
1970
+ this._worldTransformer = undefined;
1971
+ this._markupIsActive = false;
1972
+ }
1973
+ syncOverlay() {}
1974
+ clearOverlay() {
1975
+ this.removeTextInput();
1976
+ this.removeImageInput();
1977
+ this.clearSelected();
1978
+ this.getObjects().forEach((obj => obj.delete()));
1979
+ }
1980
+ getMarkupColor() {
1981
+ return this._markupColor.asRGB();
1982
+ }
1983
+ setMarkupColor(r, g, b) {
1984
+ this._markupColor.setColor(r, g, b);
1985
+ this._viewer.emit({
1986
+ type: "changemarkupcolor",
1987
+ data: {
1988
+ r: r,
1989
+ g: g,
1990
+ b: b
1991
+ }
1992
+ });
1993
+ }
1994
+ colorizeAllMarkup(r, g, b) {
1995
+ const hexColor = new MarkupColor(r, g, b).asHex();
1996
+ this.getObjects().filter((obj => {
1997
+ var _a;
1998
+ return (_a = obj.setColor) === null || _a === void 0 ? void 0 : _a.call(obj, hexColor);
1999
+ }));
2000
+ }
2001
+ colorizeSelectedMarkups(r, g, b) {
2002
+ const hexColor = new MarkupColor(r, g, b).asHex();
2003
+ this.getSelectedObjects().filter((obj => {
2004
+ var _a;
2005
+ return (_a = obj.setColor) === null || _a === void 0 ? void 0 : _a.call(obj, hexColor);
2006
+ }));
2007
+ }
2008
+ setViewpoint(viewpoint) {
2009
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2010
+ this.clearSelected();
2011
+ this.removeTextInput();
2012
+ this.removeImageInput();
2013
+ this._konvaStage.scale({
2014
+ x: 1,
2015
+ y: 1
2016
+ });
2017
+ this._konvaStage.position({
2018
+ x: 0,
2019
+ y: 0
2020
+ });
2021
+ const markupColor = ((_a = viewpoint.custom_fields) === null || _a === void 0 ? void 0 : _a.markup_color) || {
2022
+ r: 255,
2023
+ g: 0,
2024
+ b: 0
2025
+ };
2026
+ this.setMarkupColor(markupColor.r, markupColor.g, markupColor.b);
2027
+ (_b = viewpoint.lines) === null || _b === void 0 ? void 0 : _b.forEach((line => {
2028
+ const linePoints = [];
2029
+ line.points.forEach((point => {
2030
+ const screenPoint = this._worldTransformer.worldToScreen(point);
2031
+ linePoints.push(screenPoint.x);
2032
+ linePoints.push(screenPoint.y);
2033
+ }));
2034
+ this.addLine(linePoints, line.color, line.type, line.width, line.id);
2035
+ }));
2036
+ (_c = viewpoint.texts) === null || _c === void 0 ? void 0 : _c.forEach((text => {
2037
+ const screenPoint = this._worldTransformer.worldToScreen(text.position);
2038
+ this.addText(text.text, screenPoint, text.angle, text.color, text.text_size, text.font_size, text.id);
2039
+ }));
2040
+ (_d = viewpoint.rectangles) === null || _d === void 0 ? void 0 : _d.forEach((rect => {
2041
+ const screenPoint = this._worldTransformer.worldToScreen(rect.position);
2042
+ this.addRectangle(screenPoint, rect.width, rect.height, rect.line_width, rect.color, rect.id);
2043
+ }));
2044
+ (_e = viewpoint.ellipses) === null || _e === void 0 ? void 0 : _e.forEach((ellipse => {
2045
+ const screenPoint = this._worldTransformer.worldToScreen(ellipse.position);
2046
+ this.addEllipse(screenPoint, ellipse.radius, ellipse.line_width, ellipse.color, ellipse.id);
2047
+ }));
2048
+ (_f = viewpoint.arrows) === null || _f === void 0 ? void 0 : _f.forEach((arrow => {
2049
+ const startPoint = this._worldTransformer.worldToScreen(arrow.start);
2050
+ const endPoint = this._worldTransformer.worldToScreen(arrow.end);
2051
+ this.addArrow(startPoint, endPoint, arrow.color, arrow.id);
2052
+ }));
2053
+ (_g = viewpoint.clouds) === null || _g === void 0 ? void 0 : _g.forEach((cloud => {
2054
+ const screenPoint = this._worldTransformer.worldToScreen(cloud.position);
2055
+ this.addCloud(screenPoint, cloud.width, cloud.height, cloud.line_width, cloud.color, cloud.id);
2056
+ }));
2057
+ (_h = viewpoint.images) === null || _h === void 0 ? void 0 : _h.forEach((image => {
2058
+ const screenPoint = this._worldTransformer.worldToScreen(image.position);
2059
+ this.addImage(screenPoint, image.src, image.width, image.height, image.id);
2060
+ }));
2061
+ }
2062
+ getViewpoint(viewpoint) {
2063
+ if (!viewpoint) viewpoint = {};
2064
+ viewpoint.lines = this.getMarkupLines();
2065
+ viewpoint.texts = this.getMarkupTexts();
2066
+ viewpoint.arrows = this.getMarkupArrows();
2067
+ viewpoint.clouds = this.getMarkupClouds();
2068
+ viewpoint.ellipses = this.getMarkupEllipses();
2069
+ viewpoint.images = this.getMarkupImages();
2070
+ viewpoint.rectangles = this.getMarkupRectangles();
2071
+ viewpoint.custom_fields = {
2072
+ markup_color: this.getMarkupColor()
2073
+ };
2074
+ viewpoint.snapshot = {
2075
+ data: this.combineMarkupWithDrawing()
2076
+ };
2077
+ return viewpoint;
2078
+ }
2079
+ enableEditMode(mode) {
2080
+ if (!mode || !MarkupMode2Konva[mode]) {
2081
+ this.clearSelected();
2082
+ this.removeTextInput();
2083
+ this.removeImageInput();
2084
+ this._markupContainer.style.pointerEvents = "none";
2085
+ this._markupIsActive = false;
2086
+ } else {
2087
+ this._markupMode = mode;
2088
+ this._markupContainer.style.pointerEvents = "all";
2089
+ this._markupIsActive = true;
2090
+ }
2091
+ return this;
2092
+ }
2093
+ createObject(type, params) {
2094
+ const konvaShape = MarkupMode2Konva[type];
2095
+ if (!konvaShape || !konvaShape.initializer) throw new Error(`Markup CreateObject - unsupported markup type ${type}`);
2096
+ const object = konvaShape.initializer(null, params);
2097
+ this.addObject(object);
2098
+ return object;
2099
+ }
2100
+ getObjects() {
2101
+ const objects = [];
2102
+ Object.keys(MarkupMode2Konva).forEach((type => {
2103
+ const konvaShape = MarkupMode2Konva[type];
2104
+ this.konvaLayerFind(type).forEach((ref => objects.push(konvaShape.initializer(ref))));
2105
+ }));
2106
+ return objects;
2107
+ }
2108
+ getSelectedObjects() {
2109
+ if (!this._konvaTransformer) return [];
2110
+ return this._konvaTransformer.nodes().map((ref => {
2111
+ const name = ref.className;
2112
+ const konvaShape = Object.values(MarkupMode2Konva).find((shape => shape.name === name));
2113
+ return konvaShape ? konvaShape.initializer(ref) : null;
2114
+ })).filter((x => x));
2115
+ }
2116
+ selectObjects(objects) {
2117
+ if (!this._konvaTransformer) return;
2118
+ const selectedObjs = this._konvaTransformer.nodes().concat(objects.map((x => x.ref())));
2119
+ this._konvaTransformer.nodes(selectedObjs);
2120
+ }
2121
+ clearSelected() {
2122
+ if (this._konvaTransformer) this._konvaTransformer.nodes([]);
2123
+ }
2124
+ addObject(object) {
2125
+ if (object.type() === "Image") this._groupImages.add(object.ref()); else if (object.type() === "Text") this._groupTexts.add(object.ref()); else this._groupGeometry.add(object.ref());
2126
+ }
2127
+ konvaLayerFind(type) {
2128
+ if (!this._konvaLayer) return [];
2129
+ const konvaShape = MarkupMode2Konva[type];
2130
+ if (!konvaShape || !konvaShape.initializer) return [];
2131
+ return this._konvaLayer.find(konvaShape.name).filter((ref => ref.parent === this._konvaLayer || ref.parent === this._groupImages || ref.parent === this._groupGeometry || ref.parent === this._groupTexts));
2132
+ }
2133
+ initializeKonva() {
2134
+ const stage = new Konva.Stage({
2135
+ container: this._markupContainer,
2136
+ width: this._container.clientWidth,
2137
+ height: this._container.clientHeight
2138
+ });
2139
+ this._konvaStage = stage;
2140
+ const layer = new Konva.Layer({
2141
+ pixelRation: window.devicePixelRatio
2142
+ });
2143
+ stage.add(layer);
2144
+ this._groupImages = new Konva.Group;
2145
+ layer.add(this._groupImages);
2146
+ this._groupGeometry = new Konva.Group;
2147
+ layer.add(this._groupGeometry);
2148
+ this._groupTexts = new Konva.Group;
2149
+ layer.add(this._groupTexts);
2150
+ this._konvaLayer = layer;
2151
+ const transformer = new Konva.Transformer({
2152
+ shouldOverdrawWholeArea: false,
2153
+ keepRatio: false,
2154
+ flipEnabled: false
2155
+ });
2156
+ layer.add(transformer);
2157
+ this._konvaTransformer = transformer;
2158
+ let isPaint = false;
2159
+ let lastLine;
2160
+ let mouseDownPos;
2161
+ let lastObj;
2162
+ stage.on("mousedown touchstart", (e => {
2163
+ if (!this._markupIsActive || e.target !== stage || this._markupMode === "Text" || this._markupMode === "Image") return;
2164
+ if (e.target === stage && transformer.nodes().length > 0) {
2165
+ transformer.nodes([]);
2166
+ return;
2167
+ }
2168
+ const pos = this.getRelativePointerPosition(stage);
2169
+ mouseDownPos = pos;
2170
+ isPaint = [ "Arrow", "Cloud", "Ellipse", "Line", "Rectangle" ].some((m => m === this._markupMode));
2171
+ if (this._markupMode === "Line") {
2172
+ lastLine = this.addLine([ pos.x, pos.y, pos.x, pos.y ]);
2173
+ }
2174
+ }));
2175
+ stage.on("mouseup touchend", (e => {
2176
+ if (!this._markupIsActive) return;
2177
+ if (isPaint) {
2178
+ const pos = this.getRelativePointerPosition(stage);
2179
+ const defParams = mouseDownPos && pos.x === mouseDownPos.x && pos.y === mouseDownPos.y;
2180
+ const startX = defParams ? mouseDownPos.x : Math.min(mouseDownPos.x, pos.x);
2181
+ const startY = defParams ? mouseDownPos.y : Math.min(mouseDownPos.y, pos.y);
2182
+ const dX = defParams ? 200 : Math.abs(mouseDownPos.x - pos.x);
2183
+ const dY = defParams ? 200 : Math.abs(mouseDownPos.y - pos.y);
2184
+ if (defParams) {
2185
+ if (this._markupMode === "Rectangle") {
2186
+ this.addRectangle({
2187
+ x: startX,
2188
+ y: startY
2189
+ }, dX, dY);
2190
+ } else if (this._markupMode === "Ellipse") {
2191
+ this.addEllipse({
2192
+ x: startX,
2193
+ y: startY
2194
+ }, {
2195
+ x: dX / 2,
2196
+ y: dY / 2
2197
+ });
2198
+ } else if (this._markupMode === "Arrow") {
2199
+ this.addArrow({
2200
+ x: mouseDownPos.x,
2201
+ y: mouseDownPos.y
2202
+ }, {
2203
+ x: defParams ? mouseDownPos.x + 200 : pos.x,
2204
+ y: defParams ? startY : pos.y
2205
+ });
2206
+ } else if (this._markupMode === "Cloud") {
2207
+ this.addCloud({
2208
+ x: startX,
2209
+ y: startY
2210
+ }, Math.max(100, dX), Math.max(100, dY));
2211
+ }
2212
+ }
2213
+ }
2214
+ lastObj = undefined;
2215
+ isPaint = false;
2216
+ }));
2217
+ stage.on("mousemove touchmove", (e => {
2218
+ if (!this._markupIsActive) return;
2219
+ if (!isPaint) {
2220
+ return;
2221
+ }
2222
+ const pos = this.getRelativePointerPosition(stage);
2223
+ const defParams = mouseDownPos && pos.x === mouseDownPos.x && pos.y === mouseDownPos.y;
2224
+ const startX = defParams ? mouseDownPos.x : Math.min(mouseDownPos.x, pos.x);
2225
+ const startY = defParams ? mouseDownPos.y : Math.min(mouseDownPos.y, pos.y);
2226
+ const dX = defParams ? 200 : Math.abs(mouseDownPos.x - pos.x);
2227
+ const dY = defParams ? 200 : Math.abs(mouseDownPos.y - pos.y);
2228
+ if (this._markupMode === "Line") {
2229
+ lastLine.addPoints([ {
2230
+ x: pos.x,
2231
+ y: pos.y
2232
+ } ]);
2233
+ } else if (this._markupMode === "Arrow") {
2234
+ if (lastObj) lastObj.setEndPoint(pos.x, pos.y); else lastObj = this.addArrow({
2235
+ x: mouseDownPos.x,
2236
+ y: mouseDownPos.y
2237
+ }, {
2238
+ x: pos.x,
2239
+ y: pos.y
2240
+ });
2241
+ } else if (this._markupMode === "Rectangle") {
2242
+ if (lastObj) {
2243
+ lastObj.setPosition(startX, startY);
2244
+ lastObj.setWidth(dX);
2245
+ lastObj.setHeight(dY);
2246
+ } else lastObj = this.addRectangle({
2247
+ x: startX,
2248
+ y: startY
2249
+ }, dX, dY);
2250
+ } else if (this._markupMode === "Ellipse") {
2251
+ if (lastObj) {
2252
+ lastObj.setPosition(startX, startY);
2253
+ lastObj.setRadiusX(dX);
2254
+ lastObj.setRadiusY(dY);
2255
+ } else lastObj = this.addEllipse({
2256
+ x: startX,
2257
+ y: startY
2258
+ }, {
2259
+ x: dX,
2260
+ y: dY
2261
+ });
2262
+ } else if (this._markupMode === "Cloud") {
2263
+ if (lastObj) {
2264
+ lastObj.setPosition(startX, startY);
2265
+ lastObj.setWidth(Math.max(100, dX));
2266
+ lastObj.setHeight(Math.max(100, dY));
2267
+ } else lastObj = this.addCloud({
2268
+ x: startX,
2269
+ y: startY
2270
+ }, dX, dY);
2271
+ }
2272
+ }));
2273
+ stage.on("click tap", (e => {
2274
+ if (!this._markupIsActive) return;
2275
+ if (e.target === stage) {
2276
+ if (this._markupMode === "Text") {
2277
+ if (this._textInputRef && this._textInputRef.value) this.addText(this._textInputRef.value, this._textInputPos, this._textInputAngle); else if (transformer.nodes().length === 0) {
2278
+ const pos = this.getRelativePointerPosition(stage);
2279
+ this.createTextInput(pos, e.evt.pageX, e.evt.pageY, 0, null);
2280
+ }
2281
+ } else if (this._markupMode === "Image") {
2282
+ if (this._imageInputRef && this._imageInputRef.value) this.addImage({
2283
+ x: this._imageInputPos.x,
2284
+ y: this._imageInputPos.y
2285
+ }, this._imageInputRef.value, 0, 0, this._imageInputRef.value); else if (transformer.nodes().length === 0) {
2286
+ const pos = this.getRelativePointerPosition(stage);
2287
+ this.createImageInput(pos);
2288
+ }
2289
+ }
2290
+ transformer.nodes([]);
2291
+ return;
2292
+ }
2293
+ if (this._markupMode === "Text" || this._markupMode === "SelectMarkup") {
2294
+ if (e.target.className === "Text" && transformer.nodes().length === 1 && transformer.nodes()[0] === e.target) {
2295
+ if (this._textInputRef && this._textInputRef.value) this.addText(this._textInputRef.value, this._textInputPos, this._textInputAngle); else this.createTextInput({
2296
+ x: e.target.attrs.x,
2297
+ y: e.target.attrs.y
2298
+ }, e.evt.pageX, e.evt.pageY, e.target.attrs.rotation, e.target.attrs.text);
2299
+ return;
2300
+ } else {
2301
+ this.removeTextInput();
2302
+ }
2303
+ }
2304
+ if (this._markupMode === "Image" || this._markupMode === "SelectMarkup") {
2305
+ if (e.target.className === "Image" && transformer.nodes().length === 1 && transformer.nodes()[0] === e.target) {
2306
+ if (this._imageInputRef && this._imageInputRef.value) this.addImage(this._imageInputPos, this._imageInputRef.value, 0, 0); else this.createImageInput({
2307
+ x: e.target.attrs.x,
2308
+ y: e.target.attrs.y
2309
+ });
2310
+ return;
2311
+ } else {
2312
+ this.removeImageInput();
2313
+ }
2314
+ }
2315
+ if (transformer.nodes().filter((x => x.className === "Cloud" || x.className === "Image")).length > 0 || e.target.className === "Cloud" || e.target.className === "Image") {
2316
+ transformer.rotateEnabled(false);
2317
+ } else {
2318
+ transformer.rotateEnabled(true);
2319
+ }
2320
+ const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
2321
+ const isSelected = transformer.nodes().indexOf(e.target) >= 0;
2322
+ if (!metaPressed && !isSelected) {
2323
+ transformer.nodes([ e.target ]);
2324
+ } else if (metaPressed && isSelected) {
2325
+ const nodes = transformer.nodes().slice();
2326
+ nodes.splice(nodes.indexOf(e.target), 1);
2327
+ transformer.nodes(nodes);
2328
+ } else if (metaPressed && !isSelected) {
2329
+ const nodes = transformer.nodes().concat([ e.target ]);
2330
+ transformer.nodes(nodes);
2331
+ }
2332
+ }));
2333
+ const container = stage.container();
2334
+ container.tabIndex = 1;
2335
+ container.focus();
2336
+ container.addEventListener("keydown", (e => {
2337
+ if (!this._markupIsActive) return;
2338
+ if (e.code === "Delete") {
2339
+ this.getSelectedObjects().forEach((obj => obj.delete()));
2340
+ this.clearSelected();
2341
+ return;
2342
+ }
2343
+ e.preventDefault();
2344
+ }));
2345
+ }
2346
+ destroyKonva() {
2347
+ var _a;
2348
+ this.removeTextInput();
2349
+ this.removeImageInput();
2350
+ this.clearOverlay();
2351
+ (_a = this._konvaStage) === null || _a === void 0 ? void 0 : _a.destroy();
2352
+ this._groupImages = undefined;
2353
+ this._groupGeometry = undefined;
2354
+ this._groupTexts = undefined;
2355
+ this._konvaLayer = undefined;
2356
+ this._konvaTransformer = undefined;
2357
+ this._konvaStage = undefined;
2358
+ }
2359
+ getMarkupLines() {
2360
+ const lines = [];
2361
+ this.konvaLayerFind("Line").forEach((ref => {
2362
+ const linePoints = ref.points();
2363
+ if (!linePoints) return;
2364
+ const worldPoints = [];
2365
+ const absoluteTransform = ref.getAbsoluteTransform();
2366
+ for (let i = 0; i < linePoints.length; i += 2) {
2367
+ const atPoint = absoluteTransform.point({
2368
+ x: linePoints[i],
2369
+ y: linePoints[i + 1]
2370
+ });
2371
+ const worldPoint = this._worldTransformer.screenToWorld(atPoint);
2372
+ worldPoints.push(worldPoint);
2373
+ }
2374
+ const konvaLine = new KonvaLine(null, ref);
2375
+ const line = {
2376
+ id: konvaLine.id(),
2377
+ points: worldPoints,
2378
+ color: konvaLine.getColor() || "#ff0000",
2379
+ type: konvaLine.getLineType() || this.lineType,
2380
+ width: konvaLine.getLineWidth() || this.lineWidth
2381
+ };
2382
+ lines.push(line);
2383
+ }));
2384
+ return lines;
2385
+ }
2386
+ getMarkupTexts() {
2387
+ const texts = [];
2388
+ this.konvaLayerFind("Text").forEach((ref => {
2389
+ const textSize = .02;
2390
+ const textScale = this._worldTransformer.getScale();
2391
+ const position = ref.position();
2392
+ const stageAbsoluteTransform = this._konvaStage.getAbsoluteTransform();
2393
+ const atPoint = stageAbsoluteTransform.point({
2394
+ x: position.x,
2395
+ y: position.y
2396
+ });
2397
+ const worldPoint = this._worldTransformer.screenToWorld(atPoint);
2398
+ const shape = new KonvaText(null, ref);
2399
+ const text = {
2400
+ id: shape.id(),
2401
+ position: worldPoint,
2402
+ text: shape.getText(),
2403
+ text_size: textSize * textScale.y,
2404
+ angle: shape.getRotation(),
2405
+ color: shape.getColor(),
2406
+ font_size: shape.getFontSize() * stageAbsoluteTransform.getMatrix()[0]
2407
+ };
2408
+ texts.push(text);
2409
+ }));
2410
+ return texts;
2411
+ }
2412
+ getMarkupRectangles() {
2413
+ const rectangles = [];
2414
+ this.konvaLayerFind("Rectangle").forEach((ref => {
2415
+ const position = ref.position();
2416
+ const stageAbsoluteTransform = this._konvaStage.getAbsoluteTransform();
2417
+ const atPoint = stageAbsoluteTransform.point({
2418
+ x: position.x,
2419
+ y: position.y
2420
+ });
2421
+ const worldPoint = this._worldTransformer.screenToWorld(atPoint);
2422
+ const scale = stageAbsoluteTransform.getMatrix()[0];
2423
+ const shape = new KonvaRectangle(null, ref);
2424
+ const rectangle = {
2425
+ id: shape.id(),
2426
+ position: worldPoint,
2427
+ width: shape.getWidth() * scale,
2428
+ height: shape.getHeigth() * scale,
2429
+ line_width: shape.getLineWidth(),
2430
+ color: shape.getColor()
2431
+ };
2432
+ rectangles.push(rectangle);
2433
+ }));
2434
+ return rectangles;
2435
+ }
2436
+ getMarkupEllipses() {
2437
+ const ellipses = [];
2438
+ this.konvaLayerFind("Ellipse").forEach((ref => {
2439
+ const position = ref.position();
2440
+ const stageAbsoluteTransform = this._konvaStage.getAbsoluteTransform();
2441
+ const atPoint = stageAbsoluteTransform.point({
2442
+ x: position.x,
2443
+ y: position.y
2444
+ });
2445
+ const worldPoint = this._worldTransformer.screenToWorld(atPoint);
2446
+ const scale = stageAbsoluteTransform.getMatrix()[0];
2447
+ const shape = new KonvaEllipse(null, ref);
2448
+ const ellipse = {
2449
+ id: shape.id(),
2450
+ position: worldPoint,
2451
+ radius: {
2452
+ x: ref.getRadiusX() * scale,
2453
+ y: ref.getRadiusY() * scale
2454
+ },
2455
+ line_width: shape.getLineWidth(),
2456
+ color: shape.getColor()
2457
+ };
2458
+ ellipses.push(ellipse);
2459
+ }));
2460
+ return ellipses;
2461
+ }
2462
+ getMarkupArrows() {
2463
+ const arrows = [];
2464
+ this.konvaLayerFind("Arrow").forEach((ref => {
2465
+ const absoluteTransform = ref.getAbsoluteTransform();
2466
+ const atStartPoint = absoluteTransform.point({
2467
+ x: ref.points()[0],
2468
+ y: ref.points()[1]
2469
+ });
2470
+ const worldStartPoint = this._worldTransformer.screenToWorld(atStartPoint);
2471
+ const atEndPoint = absoluteTransform.point({
2472
+ x: ref.points()[2],
2473
+ y: ref.points()[3]
2474
+ });
2475
+ const worldEndPoint = this._worldTransformer.screenToWorld(atEndPoint);
2476
+ const shape = new KonvaArrow(null, ref);
2477
+ const arrow = {
2478
+ id: shape.id(),
2479
+ start: worldStartPoint,
2480
+ end: worldEndPoint,
2481
+ color: shape.getColor()
2482
+ };
2483
+ arrows.push(arrow);
2484
+ }));
2485
+ return arrows;
2486
+ }
2487
+ getMarkupImages() {
2488
+ const images = [];
2489
+ this.konvaLayerFind("Image").forEach((ref => {
2490
+ const position = ref.position();
2491
+ const stageAbsoluteTransform = this._konvaStage.getAbsoluteTransform();
2492
+ const atPoint = stageAbsoluteTransform.point({
2493
+ x: position.x,
2494
+ y: position.y
2495
+ });
2496
+ const worldPoint = this._worldTransformer.screenToWorld(atPoint);
2497
+ const scale = stageAbsoluteTransform.getMatrix()[0];
2498
+ const shape = new KonvaImage(null, ref);
2499
+ const image = {
2500
+ id: shape.id(),
2501
+ position: worldPoint,
2502
+ src: shape.getSrc(),
2503
+ width: shape.getWidth() * scale,
2504
+ height: shape.getHeight() * scale
2505
+ };
2506
+ images.push(image);
2507
+ }));
2508
+ return images;
2509
+ }
2510
+ getMarkupClouds() {
2511
+ const clouds = [];
2512
+ this.konvaLayerFind("Cloud").forEach((ref => {
2513
+ const position = ref.position();
2514
+ const stageAbsoluteTransform = this._konvaStage.getAbsoluteTransform();
2515
+ const atPoint = stageAbsoluteTransform.point({
2516
+ x: position.x,
2517
+ y: position.y
2518
+ });
2519
+ const worldPoint = this._worldTransformer.screenToWorld(atPoint);
2520
+ const scale = stageAbsoluteTransform.getMatrix()[0];
2521
+ const shape = new KonvaCloud(null, ref);
2522
+ const cloud = {
2523
+ id: shape.id(),
2524
+ position: worldPoint,
2525
+ width: shape.getWidth() * scale,
2526
+ height: shape.getHeigth() * scale,
2527
+ line_width: shape.getLineWidth(),
2528
+ color: shape.getColor()
2529
+ };
2530
+ clouds.push(cloud);
2531
+ }));
2532
+ return clouds;
2533
+ }
2534
+ combineMarkupWithDrawing() {
2535
+ this.clearSelected();
2536
+ const tempCanvas = document.createElement("canvas");
2537
+ if (this._konvaStage) {
2538
+ tempCanvas.width = this._konvaStage.width();
2539
+ tempCanvas.height = this._konvaStage.height();
2540
+ const ctx = tempCanvas.getContext("2d");
2541
+ if (this._container instanceof HTMLCanvasElement) ctx.drawImage(this._container, 0, 0);
2542
+ ctx.drawImage(this._konvaStage.toCanvas({
2543
+ pixelRatio: window.devicePixelRatio
2544
+ }), 0, 0);
2545
+ }
2546
+ return tempCanvas.toDataURL("image/jpeg", .25);
2547
+ }
2548
+ addLine(linePoints, color, type, width, id) {
2549
+ if (!linePoints || linePoints.length === 0) return;
2550
+ const points = [];
2551
+ for (let i = 0; i < linePoints.length; i += 2) {
2552
+ points.push({
2553
+ x: linePoints[i],
2554
+ y: linePoints[i + 1]
2555
+ });
2556
+ }
2557
+ const konvaLine = new KonvaLine({
2558
+ points: points,
2559
+ type: type || this.lineType,
2560
+ width: width || this.lineWidth,
2561
+ color: color || this._markupColor.asHex(),
2562
+ id: id
2563
+ });
2564
+ this.addObject(konvaLine);
2565
+ return konvaLine;
2566
+ }
2567
+ createTextInput(pos, inputX, inputY, angle, text) {
2568
+ if (!this._textInputRef) {
2569
+ this._textInputPos = pos;
2570
+ this._textInputAngle = angle;
2571
+ this._textInputRef = document.createElement("textarea");
2572
+ this._textInputRef.style.zIndex = "9999";
2573
+ this._textInputRef.style.position = "absolute";
2574
+ this._textInputRef.style.display = "block";
2575
+ this._textInputRef.style.top = inputY + "px";
2576
+ this._textInputRef.style.left = inputX + "px";
2577
+ this._textInputRef.style.fontSize = `${this.fontSize}px`;
2578
+ this._textInputRef.style.color = `${this._markupColor.asHex()}`;
2579
+ this._textInputRef.style.fontFamily = "Calibri";
2580
+ this._textInputRef.onkeydown = event => {
2581
+ if (event.key === "Enter" && !event.shiftKey) {
2582
+ event.preventDefault();
2583
+ this.addText(this._textInputRef.value, this._textInputPos, this._textInputAngle);
2584
+ }
2585
+ if (event.key === "Escape") {
2586
+ event.preventDefault();
2587
+ this.removeTextInput();
2588
+ }
2589
+ };
2590
+ if (text) this._textInputRef.value = text;
2591
+ document.body.appendChild(this._textInputRef);
2592
+ setTimeout((() => {
2593
+ this._textInputRef.focus();
2594
+ }), 50);
2595
+ } else {
2596
+ this.removeTextInput();
2597
+ }
2598
+ }
2599
+ removeTextInput() {
2600
+ var _a;
2601
+ (_a = this._textInputRef) === null || _a === void 0 ? void 0 : _a.remove();
2602
+ this._textInputRef = null;
2603
+ this._textInputPos = null;
2604
+ this._textInputAngle = 0;
2605
+ }
2606
+ createImageInput(pos) {
2607
+ if (!this._imageInputRef) {
2608
+ const convertBase64 = file => new Promise(((resolve, reject) => {
2609
+ const fileReader = new FileReader;
2610
+ fileReader.readAsDataURL(file);
2611
+ fileReader.onload = () => {
2612
+ resolve(fileReader.result);
2613
+ };
2614
+ fileReader.onerror = error => {
2615
+ reject(error);
2616
+ };
2617
+ }));
2618
+ this._imageInputPos = pos;
2619
+ this._imageInputRef = document.createElement("input");
2620
+ this._imageInputRef.style.display = "none";
2621
+ this._imageInputRef.type = "file";
2622
+ this._imageInputRef.accept = "image/png, image/jpeg";
2623
+ this._imageInputRef.onchange = async event => {
2624
+ const file = event.target.files[0];
2625
+ const base64 = await convertBase64(file);
2626
+ this.addImage({
2627
+ x: this._imageInputPos.x,
2628
+ y: this._imageInputPos.y
2629
+ }, base64.toString(), 0, 0);
2630
+ };
2631
+ this._imageInputRef.oncancel = event => {
2632
+ this.removeImageInput();
2633
+ };
2634
+ document.body.appendChild(this._imageInputRef);
2635
+ setTimeout((() => {
2636
+ this._imageInputRef.click();
2637
+ }), 50);
2638
+ } else {
2639
+ this.removeImageInput();
2640
+ }
2641
+ }
2642
+ removeImageInput() {
2643
+ var _a;
2644
+ (_a = this._imageInputRef) === null || _a === void 0 ? void 0 : _a.remove();
2645
+ this._imageInputRef = null;
2646
+ this._imageInputPos = null;
2647
+ }
2648
+ addText(text, position, angle, color, textSize, fontSize, id) {
2649
+ var _a;
2650
+ if (!text) return;
2651
+ (_a = this.getSelectedObjects().at(0)) === null || _a === void 0 ? void 0 : _a.delete();
2652
+ this.clearSelected();
2653
+ this.removeTextInput();
2654
+ const tolerance = 1e-6;
2655
+ if (textSize && textSize > tolerance && (!fontSize || fontSize < tolerance)) {
2656
+ const size = .02;
2657
+ const scale = this._worldTransformer.getScale();
2658
+ fontSize = textSize / (scale.y / size) / 34;
2659
+ }
2660
+ const konvaText = new KonvaText({
2661
+ position: {
2662
+ x: position.x,
2663
+ y: position.y
2664
+ },
2665
+ text: text,
2666
+ rotation: angle,
2667
+ fontSize: fontSize || this.fontSize,
2668
+ color: color || this._markupColor.asHex(),
2669
+ id: id
2670
+ });
2671
+ this.addObject(konvaText);
2672
+ return konvaText;
2673
+ }
2674
+ addRectangle(position, width, height, lineWidth, color, id) {
2675
+ if (!position) return;
2676
+ const konvaRectangle = new KonvaRectangle({
2677
+ position: position,
2678
+ width: width,
2679
+ height: height,
2680
+ lineWidth: lineWidth || this.lineWidth,
2681
+ color: color || this._markupColor.asHex(),
2682
+ id: id
2683
+ });
2684
+ this.addObject(konvaRectangle);
2685
+ return konvaRectangle;
2686
+ }
2687
+ addEllipse(position, radius, lineWidth, color, id) {
2688
+ if (!position) return;
2689
+ const konvaEllipse = new KonvaEllipse({
2690
+ position: position,
2691
+ radius: radius,
2692
+ lineWidth: lineWidth,
2693
+ color: color || this._markupColor.asHex(),
2694
+ id: id
2695
+ });
2696
+ this.addObject(konvaEllipse);
2697
+ return konvaEllipse;
2698
+ }
2699
+ addArrow(start, end, color, id) {
2700
+ if (!start || !end) return;
2701
+ const konvaArrow = new KonvaArrow({
2702
+ start: start,
2703
+ end: end,
2704
+ color: color || this._markupColor.asHex(),
2705
+ id: id
2706
+ });
2707
+ this.addObject(konvaArrow);
2708
+ return konvaArrow;
2709
+ }
2710
+ addCloud(position, width, height, lineWidth, color, id) {
2711
+ if (!position || !width || !height) return;
2712
+ const konvaCloud = new KonvaCloud({
2713
+ position: position,
2714
+ width: width,
2715
+ height: height,
2716
+ color: color || this._markupColor.asHex(),
2717
+ lineWidth: lineWidth || this.lineWidth,
2718
+ id: id
2719
+ });
2720
+ this.addObject(konvaCloud);
2721
+ return konvaCloud;
2722
+ }
2723
+ addImage(position, src, width, height, id) {
2724
+ var _a;
2725
+ if (!position || !src) return;
2726
+ (_a = this.getSelectedObjects().at(0)) === null || _a === void 0 ? void 0 : _a.delete();
2727
+ this.clearSelected();
2728
+ this.removeImageInput();
2729
+ const konvaImage = new KonvaImage({
2730
+ position: position,
2731
+ src: src,
2732
+ width: width,
2733
+ height: height,
2734
+ maxWidth: this._konvaStage.width() - position.x,
2735
+ maxHeight: this._konvaStage.height() - position.y,
2736
+ id: id
2737
+ });
2738
+ this.addObject(konvaImage);
2739
+ return konvaImage;
2740
+ }
2741
+ }
2742
+
2743
+ const _changeEvent$2 = {
2744
+ type: "change"
2745
+ };
2746
+
2747
+ const _startEvent = {
2748
+ type: "start"
2749
+ };
2750
+
2751
+ const _endEvent = {
2752
+ type: "end"
2753
+ };
2754
+
2755
+ const STATE = {
2756
+ NONE: -1,
2757
+ ROTATE: 0,
2758
+ DOLLY: 1,
2759
+ PAN: 2,
2760
+ TOUCH_ROTATE: 3,
2761
+ TOUCH_PAN: 4,
2762
+ TOUCH_DOLLY_PAN: 5,
2763
+ TOUCH_DOLLY_ROTATE: 6
2764
+ };
2765
+
2766
+ class OrbitControls extends EventDispatcher {
2767
+ constructor(object, domElement) {
2768
+ super();
2769
+ this.object = object;
2770
+ this.domElement = domElement;
2771
+ this.domElement.style.touchAction = "none";
2772
+ this.enabled = true;
2773
+ this.target = new Vector3;
2774
+ this.minDistance = 0;
2775
+ this.maxDistance = Infinity;
2776
+ this.minZoom = 0;
2777
+ this.maxZoom = Infinity;
2778
+ this.minPolarAngle = 0;
2779
+ this.maxPolarAngle = Math.PI;
2780
+ this.minAzimuthAngle = -Infinity;
2781
+ this.maxAzimuthAngle = Infinity;
2782
+ this.enableDamping = false;
2783
+ this.dampingFactor = .05;
2784
+ this.enableZoom = true;
2785
+ this.zoomSpeed = 1;
2786
+ this.enableRotate = true;
2787
+ this.rotateSpeed = 1;
2788
+ this.enablePan = true;
2789
+ this.panSpeed = 1;
2790
+ this.screenSpacePanning = true;
2791
+ this.keyPanSpeed = 7;
2792
+ this.autoRotate = false;
2793
+ this.autoRotateSpeed = 2;
2794
+ this.keys = {
2795
+ LEFT: "ArrowLeft",
2796
+ UP: "ArrowUp",
2797
+ RIGHT: "ArrowRight",
2798
+ BOTTOM: "ArrowDown"
2799
+ };
2800
+ this.mouseButtons = {
2801
+ LEFT: MOUSE.ROTATE,
2802
+ MIDDLE: MOUSE.DOLLY,
2803
+ RIGHT: MOUSE.PAN
2804
+ };
2805
+ this.touches = {
2806
+ ONE: TOUCH.ROTATE,
2807
+ TWO: TOUCH.DOLLY_PAN
2808
+ };
2809
+ this.target0 = this.target.clone();
2810
+ this.position0 = this.object.position.clone();
2811
+ this.zoom0 = this.object.zoom;
2812
+ this._domElementKeyEvents = null;
2813
+ this.getPolarAngle = function() {
2814
+ return spherical.phi;
2815
+ };
2816
+ this.getAzimuthalAngle = function() {
2817
+ return spherical.theta;
2818
+ };
2819
+ this.getDistance = function() {
2820
+ return this.object.position.distanceTo(this.target);
2821
+ };
2822
+ this.listenToKeyEvents = function(domElement) {
2823
+ domElement.addEventListener("keydown", onKeyDown);
2824
+ this._domElementKeyEvents = domElement;
2825
+ };
2826
+ this.stopListenToKeyEvents = function() {
2827
+ this._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
2828
+ this._domElementKeyEvents = null;
2829
+ };
2830
+ this.saveState = function() {
2831
+ scope.target0.copy(scope.target);
2832
+ scope.position0.copy(scope.object.position);
2833
+ scope.zoom0 = scope.object.zoom;
2834
+ };
2835
+ this.reset = function() {
2836
+ scope.target.copy(scope.target0);
2837
+ scope.object.position.copy(scope.position0);
2838
+ scope.object.zoom = scope.zoom0;
2839
+ scope.object.updateProjectionMatrix();
2840
+ scope.dispatchEvent(_changeEvent$2);
2841
+ scope.update();
2842
+ scope.state = STATE.NONE;
2843
+ };
2844
+ this.update = function() {
2845
+ const offset = new Vector3;
2846
+ const quat = (new Quaternion).setFromUnitVectors(object.up, new Vector3(0, 1, 0));
2847
+ const quatInverse = quat.clone().invert();
2848
+ const lastPosition = new Vector3;
2849
+ const lastQuaternion = new Quaternion;
2850
+ const lastTargetPosition = new Vector3;
2851
+ const twoPI = 2 * Math.PI;
2852
+ return function update() {
2853
+ const position = scope.object.position;
2854
+ offset.copy(position).sub(scope.target);
2855
+ offset.applyQuaternion(quat);
2856
+ spherical.setFromVector3(offset);
2857
+ if (scope.autoRotate && scope.state === STATE.NONE) {
2858
+ rotateLeft(getAutoRotationAngle());
2859
+ }
2860
+ if (scope.enableDamping) {
2861
+ spherical.theta += sphericalDelta.theta * scope.dampingFactor;
2862
+ spherical.phi += sphericalDelta.phi * scope.dampingFactor;
2863
+ } else {
2864
+ spherical.theta += sphericalDelta.theta;
2865
+ spherical.phi += sphericalDelta.phi;
2866
+ }
2867
+ let min = scope.minAzimuthAngle;
2868
+ let max = scope.maxAzimuthAngle;
2869
+ if (isFinite(min) && isFinite(max)) {
2870
+ if (min < -Math.PI) min += twoPI; else if (min > Math.PI) min -= twoPI;
2871
+ if (max < -Math.PI) max += twoPI; else if (max > Math.PI) max -= twoPI;
2872
+ if (min <= max) {
2873
+ spherical.theta = Math.max(min, Math.min(max, spherical.theta));
2874
+ } else {
2875
+ spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
2876
+ }
2877
+ }
2878
+ spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
2879
+ spherical.makeSafe();
2880
+ spherical.radius *= scope.scale;
2881
+ spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
2882
+ if (scope.enableDamping === true) {
2883
+ scope.target.addScaledVector(scope.panOffset, scope.dampingFactor);
2884
+ } else {
2885
+ scope.target.add(scope.panOffset);
2886
+ }
2887
+ offset.setFromSpherical(spherical);
2888
+ offset.applyQuaternion(quatInverse);
2889
+ position.copy(scope.target).add(offset);
2890
+ scope.object.lookAt(scope.target);
2891
+ if (scope.enableDamping === true) {
2892
+ sphericalDelta.theta *= 1 - scope.dampingFactor;
2893
+ sphericalDelta.phi *= 1 - scope.dampingFactor;
2894
+ scope.panOffset.multiplyScalar(1 - scope.dampingFactor);
2895
+ } else {
2896
+ sphericalDelta.set(0, 0, 0);
2897
+ scope.panOffset.set(0, 0, 0);
2898
+ }
2899
+ scope.scale = 1;
2900
+ if (scope.zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS || lastTargetPosition.distanceToSquared(scope.target) > 0) {
2901
+ scope.dispatchEvent(_changeEvent$2);
2902
+ lastPosition.copy(scope.object.position);
2903
+ lastQuaternion.copy(scope.object.quaternion);
2904
+ lastTargetPosition.copy(scope.target);
2905
+ scope.zoomChanged = false;
2906
+ return true;
2907
+ }
2908
+ return false;
2909
+ };
2910
+ }();
2911
+ this.dispose = function() {
2912
+ scope.domElement.removeEventListener("contextmenu", onContextMenu);
2913
+ scope.domElement.removeEventListener("pointerdown", onPointerDown);
2914
+ scope.domElement.removeEventListener("pointercancel", onPointerUp);
2915
+ scope.domElement.removeEventListener("wheel", onMouseWheel);
2916
+ scope.domElement.removeEventListener("pointermove", onPointerMove);
2917
+ scope.domElement.removeEventListener("pointerup", onPointerUp);
2918
+ if (scope._domElementKeyEvents !== null) {
2919
+ scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
2920
+ scope._domElementKeyEvents = null;
2921
+ }
2922
+ };
2923
+ const scope = this;
2924
+ scope.state = STATE.NONE;
2925
+ const EPS = 1e-6;
2926
+ const spherical = new Spherical;
2927
+ const sphericalDelta = new Spherical;
2928
+ scope.scale = 1;
2929
+ scope.panOffset = new Vector3;
2930
+ scope.zoomChanged = false;
2931
+ scope.rotateStart = new Vector2;
2932
+ scope.rotateEnd = new Vector2;
2933
+ scope.rotateDelta = new Vector2;
2934
+ scope.panStart = new Vector2;
2935
+ scope.panEnd = new Vector2;
2936
+ scope.panDelta = new Vector2;
2937
+ scope.dollyStart = new Vector2;
2938
+ scope.dollyEnd = new Vector2;
2939
+ scope.dollyDelta = new Vector2;
2940
+ scope.dollyScale = 0;
2941
+ scope.pointers = [];
2942
+ scope.pointerPositions = {};
2943
+ function getAutoRotationAngle() {
2944
+ return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
2945
+ }
2946
+ function getZoomScale() {
2947
+ return Math.pow(.95, scope.zoomSpeed);
2948
+ }
2949
+ function rotateLeft(angle) {
2950
+ sphericalDelta.theta -= angle;
2951
+ }
2952
+ function rotateUp(angle) {
2953
+ sphericalDelta.phi -= angle;
2954
+ }
2955
+ const panLeft = function() {
2956
+ const v = new Vector3;
2957
+ return function panLeft(distance, objectMatrix) {
2958
+ v.setFromMatrixColumn(objectMatrix, 0);
2959
+ v.multiplyScalar(-distance);
2960
+ scope.panOffset.add(v);
2961
+ };
2962
+ }();
2963
+ const panUp = function() {
2964
+ const v = new Vector3;
2965
+ return function panUp(distance, objectMatrix) {
2966
+ if (scope.screenSpacePanning === true) {
2967
+ v.setFromMatrixColumn(objectMatrix, 1);
2968
+ } else {
2969
+ v.setFromMatrixColumn(objectMatrix, 0);
2970
+ v.crossVectors(scope.object.up, v);
2971
+ }
2972
+ v.multiplyScalar(distance);
2973
+ scope.panOffset.add(v);
2974
+ };
2975
+ }();
2976
+ const pan = function() {
2977
+ const offset = new Vector3;
2978
+ return function pan(deltaX, deltaY) {
2979
+ const element = scope.domElement;
2980
+ if (scope.object.isPerspectiveCamera) {
2981
+ const position = scope.object.position;
2982
+ offset.copy(position).sub(scope.target);
2983
+ let targetDistance = offset.length();
2984
+ targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180);
2985
+ panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
2986
+ panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
2987
+ } else if (scope.object.isOrthographicCamera) {
2988
+ panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix);
2989
+ panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix);
2990
+ } else {
2991
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");
2992
+ scope.enablePan = false;
2993
+ }
2994
+ };
2995
+ }();
2996
+ function dollyOut(dollyScale) {
2997
+ if (scope.object.isPerspectiveCamera) {
2998
+ scope.scale /= dollyScale;
2999
+ } else if (scope.object.isOrthographicCamera) {
3000
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
3001
+ scope.object.updateProjectionMatrix();
3002
+ scope.zoomChanged = true;
3003
+ } else {
3004
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
3005
+ scope.enableZoom = false;
3006
+ }
3007
+ }
3008
+ function dollyIn(dollyScale) {
3009
+ if (scope.object.isPerspectiveCamera) {
3010
+ scope.scale *= dollyScale;
3011
+ } else if (scope.object.isOrthographicCamera) {
3012
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
3013
+ scope.object.updateProjectionMatrix();
3014
+ scope.zoomChanged = true;
3015
+ } else {
3016
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
3017
+ scope.enableZoom = false;
3018
+ }
3019
+ }
3020
+ function handleMouseDownRotate(event) {
3021
+ scope.rotateStart.set(event.clientX, event.clientY);
3022
+ }
3023
+ function handleMouseDownDolly(event) {
3024
+ scope.dollyStart.set(event.clientX, event.clientY);
3025
+ }
3026
+ function handleMouseDownPan(event) {
3027
+ scope.panStart.set(event.clientX, event.clientY);
3028
+ }
3029
+ function handleMouseMoveRotate(event) {
3030
+ scope.rotateEnd.set(event.clientX, event.clientY);
3031
+ scope.rotateDelta.subVectors(scope.rotateEnd, scope.rotateStart).multiplyScalar(scope.rotateSpeed);
3032
+ const element = scope.domElement;
3033
+ rotateLeft(2 * Math.PI * scope.rotateDelta.x / element.clientHeight);
3034
+ rotateUp(2 * Math.PI * scope.rotateDelta.y / element.clientHeight);
3035
+ scope.rotateStart.copy(scope.rotateEnd);
3036
+ scope.update();
3037
+ }
3038
+ function handleMouseMoveDolly(event) {
3039
+ scope.dollyEnd.set(event.clientX, event.clientY);
3040
+ scope.dollyDelta.subVectors(scope.dollyEnd, scope.dollyStart);
3041
+ if (scope.dollyDelta.y < 0) {
3042
+ scope.dollyScale = 1 / getZoomScale();
3043
+ dollyOut(getZoomScale());
3044
+ } else if (scope.dollyDelta.y > 0) {
3045
+ scope.dollyScale = getZoomScale();
3046
+ dollyIn(getZoomScale());
3047
+ }
3048
+ scope.dollyStart.copy(scope.dollyEnd);
3049
+ scope.update();
3050
+ }
3051
+ function handleMouseMovePan(event) {
3052
+ scope.panEnd.set(event.clientX, event.clientY);
3053
+ scope.panDelta.subVectors(scope.panEnd, scope.panStart).multiplyScalar(scope.panSpeed);
3054
+ pan(scope.panDelta.x, scope.panDelta.y);
3055
+ scope.panStart.copy(scope.panEnd);
3056
+ scope.update();
3057
+ }
3058
+ function handleMouseWheel(event) {
3059
+ scope.dollyEnd.set(scope.domElement.clientWidth / 2, scope.domElement.clientHeight / 2);
3060
+ scope.dollyDelta.set(event.deltaX, event.deltaY);
3061
+ if (event.deltaY < 0) {
3062
+ scope.dollyScale = 1 / getZoomScale();
3063
+ dollyIn(getZoomScale());
3064
+ } else if (event.deltaY > 0) {
3065
+ scope.dollyScale = getZoomScale();
3066
+ dollyOut(getZoomScale());
3067
+ }
3068
+ scope.dollyStart.copy(scope.dollyEnd);
3069
+ scope.update();
3070
+ if (event.deltaY !== 0) {
3071
+ scope.state = STATE.DOLLY;
3072
+ scope.dispatchEvent(_changeEvent$2);
3073
+ scope.state = STATE.NONE;
3074
+ }
3075
+ }
3076
+ function handleKeyDown(event) {
3077
+ let needsUpdate = false;
3078
+ switch (event.code) {
3079
+ case scope.keys.UP:
3080
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
3081
+ rotateUp(2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight);
3082
+ } else {
3083
+ pan(0, scope.keyPanSpeed);
3084
+ }
3085
+ needsUpdate = true;
3086
+ break;
3087
+
3088
+ case scope.keys.BOTTOM:
3089
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
3090
+ rotateUp(-2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight);
3091
+ } else {
3092
+ pan(0, -scope.keyPanSpeed);
3093
+ }
3094
+ needsUpdate = true;
3095
+ break;
3096
+
3097
+ case scope.keys.LEFT:
3098
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
3099
+ rotateLeft(2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight);
3100
+ } else {
3101
+ pan(scope.keyPanSpeed, 0);
3102
+ }
3103
+ needsUpdate = true;
3104
+ break;
3105
+
3106
+ case scope.keys.RIGHT:
3107
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
3108
+ rotateLeft(-2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight);
3109
+ } else {
3110
+ pan(-scope.keyPanSpeed, 0);
3111
+ }
3112
+ needsUpdate = true;
3113
+ break;
3114
+ }
3115
+ if (needsUpdate) {
3116
+ event.preventDefault();
3117
+ scope.update();
3118
+ }
3119
+ }
3120
+ function handleTouchStartRotate() {
3121
+ if (scope.pointers.length === 1) {
3122
+ scope.rotateStart.set(scope.pointers[0].pageX, scope.pointers[0].pageY);
3123
+ } else {
3124
+ const x = .5 * (scope.pointers[0].pageX + scope.pointers[1].pageX);
3125
+ const y = .5 * (scope.pointers[0].pageY + scope.pointers[1].pageY);
3126
+ scope.rotateStart.set(x, y);
3127
+ }
3128
+ }
3129
+ function handleTouchStartPan() {
3130
+ if (scope.pointers.length === 1) {
3131
+ scope.panStart.set(scope.pointers[0].pageX, scope.pointers[0].pageY);
3132
+ } else {
3133
+ const x = .5 * (scope.pointers[0].pageX + scope.pointers[1].pageX);
3134
+ const y = .5 * (scope.pointers[0].pageY + scope.pointers[1].pageY);
3135
+ scope.panStart.set(x, y);
3136
+ }
3137
+ }
3138
+ function handleTouchStartDolly() {
3139
+ const dx = scope.pointers[0].pageX - scope.pointers[1].pageX;
3140
+ const dy = scope.pointers[0].pageY - scope.pointers[1].pageY;
3141
+ const distance = Math.sqrt(dx * dx + dy * dy);
3142
+ scope.dollyStart.set(0, distance);
3143
+ }
3144
+ function handleTouchStartDollyPan() {
3145
+ if (scope.enableZoom) handleTouchStartDolly();
3146
+ if (scope.enablePan) handleTouchStartPan();
3147
+ }
3148
+ function handleTouchStartDollyRotate() {
3149
+ if (scope.enableZoom) handleTouchStartDolly();
3150
+ if (scope.enableRotate) handleTouchStartRotate();
3151
+ }
3152
+ function handleTouchMoveRotate(event) {
3153
+ if (scope.pointers.length == 1) {
3154
+ scope.rotateEnd.set(event.pageX, event.pageY);
3155
+ } else {
3156
+ const position = getSecondPointerPosition(event);
3157
+ const x = .5 * (event.pageX + position.x);
3158
+ const y = .5 * (event.pageY + position.y);
3159
+ scope.rotateEnd.set(x, y);
3160
+ }
3161
+ scope.rotateDelta.subVectors(scope.rotateEnd, scope.rotateStart).multiplyScalar(scope.rotateSpeed);
3162
+ const element = scope.domElement;
3163
+ rotateLeft(2 * Math.PI * scope.rotateDelta.x / element.clientHeight);
3164
+ rotateUp(2 * Math.PI * scope.rotateDelta.y / element.clientHeight);
3165
+ scope.rotateStart.copy(scope.rotateEnd);
3166
+ }
3167
+ function handleTouchMovePan(event) {
3168
+ if (scope.pointers.length === 1) {
3169
+ scope.panEnd.set(event.pageX, event.pageY);
3170
+ } else {
3171
+ const position = getSecondPointerPosition(event);
3172
+ const x = .5 * (event.pageX + position.x);
3173
+ const y = .5 * (event.pageY + position.y);
3174
+ scope.panEnd.set(x, y);
3175
+ }
3176
+ scope.panDelta.subVectors(scope.panEnd, scope.panStart).multiplyScalar(scope.panSpeed);
3177
+ pan(scope.panDelta.x, scope.panDelta.y);
3178
+ scope.panStart.copy(scope.panEnd);
3179
+ }
3180
+ function handleTouchMoveDolly(event) {
3181
+ const position = getSecondPointerPosition(event);
3182
+ const dx = event.pageX - position.x;
3183
+ const dy = event.pageY - position.y;
3184
+ const distance = Math.sqrt(dx * dx + dy * dy);
3185
+ scope.dollyEnd.set(0, distance);
3186
+ scope.dollyDelta.set(0, Math.pow(scope.dollyEnd.y / scope.dollyStart.y, scope.zoomSpeed));
3187
+ dollyOut(scope.dollyDelta.y);
3188
+ scope.dollyStart.copy(scope.dollyEnd);
3189
+ }
3190
+ function handleTouchMoveDollyPan(event) {
3191
+ if (scope.enableZoom) handleTouchMoveDolly(event);
3192
+ if (scope.enablePan) handleTouchMovePan(event);
3193
+ }
3194
+ function handleTouchMoveDollyRotate(event) {
3195
+ if (scope.enableZoom) handleTouchMoveDolly(event);
3196
+ if (scope.enableRotate) handleTouchMoveRotate(event);
3197
+ }
3198
+ function onPointerDown(event) {
3199
+ if (scope.enabled === false) return;
3200
+ if (scope.pointers.length === 0) {
3201
+ scope.domElement.setPointerCapture(event.pointerId);
3202
+ scope.domElement.addEventListener("pointermove", onPointerMove);
3203
+ scope.domElement.addEventListener("pointerup", onPointerUp);
3204
+ }
3205
+ addPointer(event);
3206
+ if (event.pointerType === "touch") {
3207
+ onTouchStart(event);
3208
+ } else {
3209
+ onMouseDown(event);
3210
+ }
3211
+ }
3212
+ function onPointerMove(event) {
3213
+ if (scope.enabled === false) return;
3214
+ if (event.pointerType === "touch") {
3215
+ onTouchMove(event);
3216
+ } else {
3217
+ onMouseMove(event);
3218
+ }
3219
+ }
3220
+ function onPointerUp(event) {
3221
+ removePointer(event);
3222
+ if (scope.pointers.length === 0) {
3223
+ scope.domElement.releasePointerCapture(event.pointerId);
3224
+ scope.domElement.removeEventListener("pointermove", onPointerMove);
3225
+ scope.domElement.removeEventListener("pointerup", onPointerUp);
3226
+ }
3227
+ scope.dispatchEvent(_endEvent);
3228
+ scope.state = STATE.NONE;
3229
+ }
3230
+ function onMouseDown(event) {
3231
+ let mouseAction;
3232
+ switch (event.button) {
3233
+ case 0:
3234
+ mouseAction = scope.mouseButtons.LEFT;
3235
+ break;
3236
+
3237
+ case 1:
3238
+ mouseAction = scope.mouseButtons.MIDDLE;
3239
+ break;
3240
+
3241
+ case 2:
3242
+ mouseAction = scope.mouseButtons.RIGHT;
3243
+ break;
3244
+
3245
+ default:
3246
+ mouseAction = -1;
3247
+ }
3248
+ switch (mouseAction) {
3249
+ case MOUSE.DOLLY:
3250
+ if (scope.enableZoom === false) return;
3251
+ handleMouseDownDolly(event);
3252
+ scope.state = STATE.DOLLY;
3253
+ break;
743
3254
 
744
- function unselect(viewer) {
745
- const selection = new SelectionComponent(viewer);
746
- selection.clearSelection();
747
- selection.dispose();
748
- viewer.update();
749
- viewer.emit({
750
- type: "select",
751
- data: undefined,
752
- handles: []
753
- });
754
- }
3255
+ case MOUSE.ROTATE:
3256
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
3257
+ if (scope.enablePan === false) return;
3258
+ handleMouseDownPan(event);
3259
+ scope.state = STATE.PAN;
3260
+ } else {
3261
+ if (scope.enableRotate === false) return;
3262
+ handleMouseDownRotate(event);
3263
+ scope.state = STATE.ROTATE;
3264
+ }
3265
+ break;
755
3266
 
756
- commands("ThreeJS").registerCommand("unselect", unselect);
3267
+ case MOUSE.PAN:
3268
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
3269
+ if (scope.enableRotate === false) return;
3270
+ handleMouseDownRotate(event);
3271
+ scope.state = STATE.ROTATE;
3272
+ } else {
3273
+ if (scope.enablePan === false) return;
3274
+ handleMouseDownPan(event);
3275
+ scope.state = STATE.PAN;
3276
+ }
3277
+ break;
757
3278
 
758
- function zoomToExtents(viewer) {
759
- if (viewer.extents.isEmpty()) return;
760
- const center = viewer.extents.getCenter(new Vector3);
761
- const distance = viewer.extents.getBoundingSphere(new Sphere).radius;
762
- const delta = new Vector3(0, 0, 1);
763
- delta.applyQuaternion(viewer.camera.quaternion);
764
- delta.multiplyScalar(distance * 3);
765
- viewer.camera.position.copy(center).add(delta);
766
- viewer.target.copy(center);
767
- viewer.update();
768
- viewer.emitEvent({
769
- type: "zoom"
770
- });
771
- }
3279
+ default:
3280
+ scope.state = STATE.NONE;
3281
+ }
3282
+ if (scope.state !== STATE.NONE) {
3283
+ scope.dispatchEvent(_startEvent);
3284
+ }
3285
+ }
3286
+ function onMouseMove(event) {
3287
+ switch (scope.state) {
3288
+ case STATE.ROTATE:
3289
+ if (scope.enableRotate === false) return;
3290
+ handleMouseMoveRotate(event);
3291
+ break;
772
3292
 
773
- commands("ThreeJS").registerCommand("zoomToExtents", zoomToExtents);
3293
+ case STATE.DOLLY:
3294
+ if (scope.enableZoom === false) return;
3295
+ handleMouseMoveDolly(event);
3296
+ break;
774
3297
 
775
- commands("ThreeJS").registerCommandAlias("zoomToExtents", "zoomExtents");
3298
+ case STATE.PAN:
3299
+ if (scope.enablePan === false) return;
3300
+ handleMouseMovePan(event);
3301
+ break;
3302
+ }
3303
+ }
3304
+ function onMouseWheel(event) {
3305
+ if (scope.enabled === false || scope.enableZoom === false || scope.state !== STATE.NONE) return;
3306
+ event.preventDefault();
3307
+ scope.dispatchEvent(_startEvent);
3308
+ handleMouseWheel(event);
3309
+ scope.dispatchEvent(_endEvent);
3310
+ }
3311
+ function onKeyDown(event) {
3312
+ if (scope.enabled === false || scope.enablePan === false) return;
3313
+ handleKeyDown(event);
3314
+ }
3315
+ function onTouchStart(event) {
3316
+ trackPointer(event);
3317
+ switch (scope.pointers.length) {
3318
+ case 1:
3319
+ switch (scope.touches.ONE) {
3320
+ case TOUCH.ROTATE:
3321
+ if (scope.enableRotate === false) return;
3322
+ handleTouchStartRotate();
3323
+ scope.state = STATE.TOUCH_ROTATE;
3324
+ break;
3325
+
3326
+ case TOUCH.PAN:
3327
+ if (scope.enablePan === false) return;
3328
+ handleTouchStartPan();
3329
+ scope.state = STATE.TOUCH_PAN;
3330
+ break;
3331
+
3332
+ default:
3333
+ scope.state = STATE.NONE;
3334
+ }
3335
+ break;
776
3336
 
777
- function zoomToObjects(viewer, handles = []) {
778
- const handleSet = new Set(handles);
779
- const objects = [];
780
- viewer.scene.traverseVisible((child => {
781
- var _a;
782
- if (handleSet.has((_a = child.userData) === null || _a === void 0 ? void 0 : _a.handle)) objects.push(child);
783
- }));
784
- const extents = objects.reduce(((result, object) => {
785
- const objectExtents = (new Box3).setFromObject(object);
786
- return result.isEmpty() ? result.copy(objectExtents) : result.union(objectExtents);
787
- }), new Box3);
788
- const center = extents.getCenter(new Vector3);
789
- const distance = extents.getBoundingSphere(new Sphere).radius;
790
- const delta = new Vector3(0, 0, 1);
791
- delta.applyQuaternion(viewer.camera.quaternion);
792
- delta.multiplyScalar(distance * 3);
793
- viewer.camera.position.copy(center).add(delta);
794
- viewer.target.copy(center);
795
- viewer.update();
796
- viewer.emitEvent({
797
- type: "zoom"
798
- });
799
- }
3337
+ case 2:
3338
+ switch (scope.touches.TWO) {
3339
+ case TOUCH.DOLLY_PAN:
3340
+ if (scope.enableZoom === false && scope.enablePan === false) return;
3341
+ handleTouchStartDollyPan();
3342
+ scope.state = STATE.TOUCH_DOLLY_PAN;
3343
+ break;
3344
+
3345
+ case TOUCH.DOLLY_ROTATE:
3346
+ if (scope.enableZoom === false && scope.enableRotate === false) return;
3347
+ handleTouchStartDollyRotate();
3348
+ scope.state = STATE.TOUCH_DOLLY_ROTATE;
3349
+ break;
3350
+
3351
+ default:
3352
+ scope.state = STATE.NONE;
3353
+ }
3354
+ break;
800
3355
 
801
- commands("ThreeJS").registerCommand("zoomToObjects", zoomToObjects);
3356
+ default:
3357
+ scope.state = STATE.NONE;
3358
+ }
3359
+ if (scope.state !== STATE.NONE) {
3360
+ scope.dispatchEvent(_startEvent);
3361
+ }
3362
+ }
3363
+ function onTouchMove(event) {
3364
+ trackPointer(event);
3365
+ switch (scope.state) {
3366
+ case STATE.TOUCH_ROTATE:
3367
+ if (scope.enableRotate === false) return;
3368
+ handleTouchMoveRotate(event);
3369
+ scope.update();
3370
+ break;
802
3371
 
803
- function zoomToSelected(viewer) {
804
- const extents = viewer.selected.reduce(((result, object) => {
805
- const objectExtents = (new Box3).setFromObject(object);
806
- return result.isEmpty() ? result.copy(objectExtents) : result.union(objectExtents);
807
- }), new Box3);
808
- if (extents.isEmpty()) extents.copy(viewer.extents);
809
- const center = extents.getCenter(new Vector3);
810
- const distance = extents.getBoundingSphere(new Sphere).radius;
811
- const delta = new Vector3(0, 0, 1);
812
- delta.applyQuaternion(viewer.camera.quaternion);
813
- delta.multiplyScalar(distance * 3);
814
- viewer.camera.position.copy(center).add(delta);
815
- viewer.target.copy(center);
816
- viewer.update();
817
- viewer.emitEvent({
818
- type: "zoom"
819
- });
820
- }
3372
+ case STATE.TOUCH_PAN:
3373
+ if (scope.enablePan === false) return;
3374
+ handleTouchMovePan(event);
3375
+ scope.update();
3376
+ break;
821
3377
 
822
- commands("ThreeJS").registerCommand("zoomToSelected", zoomToSelected);
3378
+ case STATE.TOUCH_DOLLY_PAN:
3379
+ if (scope.enableZoom === false && scope.enablePan === false) return;
3380
+ handleTouchMoveDollyPan(event);
3381
+ scope.update();
3382
+ break;
823
3383
 
824
- class GLTFLoadingManager extends LoadingManager {
825
- constructor(file, externalData = new Map, params = {}) {
826
- super();
827
- this.path = "";
828
- this.resourcePath = "";
829
- this.fileURL = "";
830
- this.dataURLs = new Map;
831
- this.path = params.path || "";
832
- if (typeof file === "string") {
833
- this.fileURL = file;
834
- this.resourcePath = LoaderUtils.extractUrlBase(file);
835
- } else {
836
- externalData.forEach(((value, key) => this.fileURL = value === file ? key : this.fileURL));
837
- externalData.set(this.fileURL, file);
838
- }
839
- externalData.forEach(((value, key) => {
840
- let dataURL;
841
- if (typeof value === "string") dataURL = value; else dataURL = URL.createObjectURL(new Blob([ value ]));
842
- this.dataURLs.set(key, dataURL);
843
- }));
844
- this.setURLModifier((url => {
845
- const key = decodeURI(url).replace(this.path, "").replace(this.resourcePath, "").replace(/^(\.?\/)/, "");
846
- const dataURL = this.dataURLs.get(key);
847
- return dataURL !== null && dataURL !== void 0 ? dataURL : url;
848
- }));
849
- }
850
- dispose() {
851
- this.dataURLs.forEach(URL.revokeObjectURL);
852
- }
853
- }
3384
+ case STATE.TOUCH_DOLLY_ROTATE:
3385
+ if (scope.enableZoom === false && scope.enableRotate === false) return;
3386
+ handleTouchMoveDollyRotate(event);
3387
+ scope.update();
3388
+ break;
854
3389
 
855
- class EventEmitter2 {
856
- constructor() {
857
- this._listeners = {};
858
- }
859
- addEventListener(type, listener) {
860
- if (this._listeners[type] === undefined) this._listeners[type] = [];
861
- this._listeners[type].push(listener);
862
- return this;
863
- }
864
- removeEventListener(type, listener) {
865
- if (this._listeners[type] === undefined) return this;
866
- const listeners = this._listeners[type].filter((x => x !== listener));
867
- if (listeners.length !== 0) this._listeners[type] = listeners; else delete this._listeners[type];
868
- return this;
869
- }
870
- removeAllListeners(type) {
871
- if (type) delete this._listeners[type]; else this._listeners = {};
872
- return this;
873
- }
874
- emitEvent(event) {
875
- if (this._listeners[event.type] === undefined) return false;
876
- const invoke = this._listeners[event.type].slice();
877
- invoke.forEach((listener => listener.call(this, event)));
878
- return true;
879
- }
880
- on(type, listener) {
881
- return this.addEventListener(type, listener);
882
- }
883
- off(type, listener) {
884
- return this.removeEventListener(type, listener);
885
- }
886
- emit(type, ...args) {
887
- if (typeof type === "string") return this.emitEvent({
888
- type: type,
889
- args: args
890
- }); else if (typeof type === "object") return this.emitEvent(type); else return false;
3390
+ default:
3391
+ scope.state = STATE.NONE;
3392
+ }
3393
+ }
3394
+ function onContextMenu(event) {
3395
+ if (scope.enabled === false) return;
3396
+ event.preventDefault();
3397
+ }
3398
+ function addPointer(event) {
3399
+ scope.pointers.push(event);
3400
+ }
3401
+ function removePointer(event) {
3402
+ delete scope.pointerPositions[event.pointerId];
3403
+ for (let i = 0; i < scope.pointers.length; i++) {
3404
+ if (scope.pointers[i].pointerId == event.pointerId) {
3405
+ scope.pointers.splice(i, 1);
3406
+ return;
3407
+ }
3408
+ }
3409
+ }
3410
+ function trackPointer(event) {
3411
+ let position = scope.pointerPositions[event.pointerId];
3412
+ if (position === undefined) {
3413
+ position = new Vector2;
3414
+ scope.pointerPositions[event.pointerId] = position;
3415
+ }
3416
+ position.set(event.pageX, event.pageY);
3417
+ }
3418
+ function getSecondPointerPosition(event) {
3419
+ const pointer = event.pointerId === scope.pointers[0].pointerId ? scope.pointers[1] : scope.pointers[0];
3420
+ return scope.pointerPositions[pointer.pointerId];
3421
+ }
3422
+ scope.domElement.addEventListener("contextmenu", onContextMenu);
3423
+ scope.domElement.addEventListener("pointerdown", onPointerDown);
3424
+ scope.domElement.addEventListener("pointercancel", onPointerUp);
3425
+ scope.domElement.addEventListener("wheel", onMouseWheel, {
3426
+ passive: false
3427
+ });
3428
+ this.update();
891
3429
  }
892
3430
  }
893
3431
 
@@ -905,6 +3443,27 @@ class OrbitDragger {
905
3443
  this.controlsChange = () => {
906
3444
  this.viewer.target.copy(this.orbit.target);
907
3445
  this.viewer.update();
3446
+ switch (this.orbit.state) {
3447
+ case STATE.PAN:
3448
+ case STATE.TOUCH_PAN:
3449
+ this.viewer.emitEvent({
3450
+ type: "pan",
3451
+ x: this.orbit.panEnd.x,
3452
+ y: this.orbit.panEnd.y,
3453
+ dX: this.orbit.panDelta.x,
3454
+ dY: this.orbit.panDelta.y
3455
+ });
3456
+ break;
3457
+
3458
+ case STATE.DOLLY:
3459
+ this.viewer.emitEvent({
3460
+ type: "zoomat",
3461
+ data: this.orbit.dollyScale,
3462
+ x: this.orbit.dollyEnd.x,
3463
+ y: this.orbit.dollyEnd.y
3464
+ });
3465
+ break;
3466
+ }
908
3467
  this.changed = true;
909
3468
  };
910
3469
  this.stopContextMenu = event => {
@@ -932,14 +3491,16 @@ class OrbitDragger {
932
3491
  this.viewer.on("geometryend", this.updateControls);
933
3492
  this.viewer.on("viewposition", this.updateControls);
934
3493
  this.viewer.on("zoom", this.updateControls);
3494
+ this.viewer.on("drawviewpoint", this.updateControls);
935
3495
  this.viewer.on("contextmenu", this.stopContextMenu);
936
3496
  this.updateControls();
937
3497
  }
938
3498
  dispose() {
939
- this.viewer.off("contextmenu", this.stopContextMenu);
940
- this.viewer.off("zoom", this.updateControls);
941
- this.viewer.off("viewposition", this.updateControls);
942
3499
  this.viewer.off("geometryend", this.updateControls);
3500
+ this.viewer.off("viewposition", this.updateControls);
3501
+ this.viewer.off("zoom", this.updateControls);
3502
+ this.viewer.off("drawviewpoint", this.updateControls);
3503
+ this.viewer.off("contextmenu", this.stopContextMenu);
943
3504
  this.orbit.removeEventListener("change", this.controlsChange);
944
3505
  this.orbit.dispose();
945
3506
  }
@@ -2240,6 +4801,7 @@ class DefaultPositionComponent {
2240
4801
  this.viewer.camera.far = size * 100;
2241
4802
  this.viewer.camera.updateMatrixWorld();
2242
4803
  this.viewer.camera.updateProjectionMatrix();
4804
+ this.viewer.executeCommand("setDefaultViewPosition", "sw");
2243
4805
  this.viewer.executeCommand("zoomToExtents");
2244
4806
  };
2245
4807
  this.viewer = viewer;
@@ -2409,6 +4971,7 @@ class Viewer extends EventEmitter2 {
2409
4971
  this.renderTime = 0;
2410
4972
  this.render = this.render.bind(this);
2411
4973
  this.update = this.update.bind(this);
4974
+ this._markup = new KonvaMarkup;
2412
4975
  }
2413
4976
  get options() {
2414
4977
  return this._options;
@@ -2416,6 +4979,9 @@ class Viewer extends EventEmitter2 {
2416
4979
  get draggers() {
2417
4980
  return Object.keys(this.draggerFactory);
2418
4981
  }
4982
+ get markup() {
4983
+ return this._markup;
4984
+ }
2419
4985
  initialize(canvas, onProgress) {
2420
4986
  this.addEventListener("optionschange", (event => this.syncOptions(event.data)));
2421
4987
  this.scene = new Scene;
@@ -2435,6 +5001,7 @@ class Viewer extends EventEmitter2 {
2435
5001
  this.renderer.toneMapping = LinearToneMapping;
2436
5002
  this.canvas = canvas;
2437
5003
  this.canvasEvents.forEach((x => canvas.addEventListener(x, this.canvaseventlistener)));
5004
+ this._markup.initialize(this.canvas, this.canvasEvents, this, this);
2438
5005
  this.components.push(new ExtentsComponent(this));
2439
5006
  this.components.push(new LightComponent(this));
2440
5007
  this.components.push(new BackgroundComponent(this));
@@ -2444,6 +5011,7 @@ class Viewer extends EventEmitter2 {
2444
5011
  this.components.push(new SelectionComponent(this));
2445
5012
  this.components.push(new WCSHelperComponent(this));
2446
5013
  this.syncOptions();
5014
+ this.syncOverlay();
2447
5015
  this.renderTime = performance.now();
2448
5016
  this.render(this.renderTime);
2449
5017
  if (typeof onProgress === "function") onProgress(new ProgressEvent("progress", {
@@ -2469,9 +5037,10 @@ class Viewer extends EventEmitter2 {
2469
5037
  });
2470
5038
  this.components.forEach((component => component.dispose()));
2471
5039
  this.components = [];
2472
- this.setActiveDragger("");
5040
+ this.setActiveDragger();
2473
5041
  this.removeAllListeners();
2474
5042
  this.clear();
5043
+ this._markup.dispose();
2475
5044
  if (this.canvas) {
2476
5045
  this.canvasEvents.forEach((x => this.canvas.removeEventListener(x, this.canvaseventlistener)));
2477
5046
  this.canvas = undefined;
@@ -2489,12 +5058,15 @@ class Viewer extends EventEmitter2 {
2489
5058
  render(time) {
2490
5059
  if (!this.renderNeeded) return;
2491
5060
  if (!this.renderer) return;
2492
- const clippingPlanes = this.renderer.clippingPlanes;
5061
+ this.renderNeeded = false;
2493
5062
  this.renderer.setViewport(0, 0, this.canvas.offsetWidth, this.canvas.offsetHeight);
5063
+ this.renderer.autoClear = true;
2494
5064
  this.renderer.render(this.scene, this.camera);
5065
+ const clippingPlanes = this.renderer.clippingPlanes;
2495
5066
  this.renderer.clippingPlanes = [];
2496
5067
  this.renderer.autoClear = false;
2497
5068
  this.renderer.render(this.helpers, this.camera);
5069
+ this.renderer.clippingPlanes = clippingPlanes;
2498
5070
  const deltaTime = (time - this.renderTime) / 1e3;
2499
5071
  this.renderTime = time;
2500
5072
  this.emitEvent({
@@ -2502,9 +5074,6 @@ class Viewer extends EventEmitter2 {
2502
5074
  time: time,
2503
5075
  deltaTime: deltaTime
2504
5076
  });
2505
- this.renderer.autoClear = true;
2506
- this.renderer.clippingPlanes = clippingPlanes;
2507
- this.renderNeeded = false;
2508
5077
  }
2509
5078
  update(force = false) {
2510
5079
  this.renderNeeded = true;
@@ -2581,8 +5150,9 @@ class Viewer extends EventEmitter2 {
2581
5150
  if (!gltf.scene) throw new Error("No glTF scene found");
2582
5151
  this.models.push(gltf);
2583
5152
  this.scene.add(gltf.scene);
5153
+ this.syncOptions();
5154
+ this.syncOverlay();
2584
5155
  this.update();
2585
- this.resetActiveDragger();
2586
5156
  this.emitEvent({
2587
5157
  type: "databasechunk"
2588
5158
  });
@@ -2614,20 +5184,61 @@ class Viewer extends EventEmitter2 {
2614
5184
  if (object.material) disposeMaterial(object.material);
2615
5185
  }
2616
5186
  this.setActiveDragger();
2617
- this.selected = [];
2618
- this.renderer.clippingPlanes = [];
5187
+ this.clearSlices();
5188
+ this.clearOverlay();
2619
5189
  this.helpers.traverse(disposeObject);
2620
5190
  this.helpers.clear();
2621
5191
  this.models.forEach((gltf => gltf.scene.traverse(disposeObject)));
2622
5192
  this.models.forEach((gltf => gltf.scene.removeFromParent()));
2623
5193
  this.models = [];
2624
5194
  this.scene.clear();
5195
+ this.syncOptions();
5196
+ this.syncOverlay();
5197
+ this.update(true);
2625
5198
  this.emitEvent({
2626
5199
  type: "clear"
2627
5200
  });
2628
- this.update(true);
2629
5201
  return this;
2630
5202
  }
5203
+ syncOverlay() {
5204
+ if (!this.renderer) return;
5205
+ this._markup.syncOverlay();
5206
+ this.update();
5207
+ }
5208
+ clearOverlay() {
5209
+ if (!this.renderer) return;
5210
+ this._markup.clearOverlay();
5211
+ this.update();
5212
+ }
5213
+ clearSlices() {
5214
+ if (!this.renderer) return;
5215
+ this.renderer.clippingPlanes = [];
5216
+ this.update();
5217
+ }
5218
+ getSelected() {
5219
+ return this.executeCommand("getSelected");
5220
+ }
5221
+ setSelected(handles) {
5222
+ this.executeCommand("setSelected", handles);
5223
+ }
5224
+ clearSelected() {
5225
+ this.executeCommand("clearSelected");
5226
+ }
5227
+ hideSelected() {
5228
+ this.executeCommand("hideSelected");
5229
+ }
5230
+ isolateSelected() {
5231
+ this.executeCommand("isolateSelected");
5232
+ }
5233
+ showAll() {
5234
+ this.executeCommand("showAll");
5235
+ }
5236
+ explode(index = 0) {
5237
+ this.executeCommand("explode", index);
5238
+ }
5239
+ collect() {
5240
+ this.executeCommand("collect");
5241
+ }
2631
5242
  activeDragger() {
2632
5243
  return this._activeDragger;
2633
5244
  }
@@ -2652,6 +5263,7 @@ class Viewer extends EventEmitter2 {
2652
5263
  type: "changeactivedragger",
2653
5264
  data: name
2654
5265
  });
5266
+ this.update();
2655
5267
  }
2656
5268
  return this._activeDragger;
2657
5269
  }
@@ -2665,11 +5277,44 @@ class Viewer extends EventEmitter2 {
2665
5277
  is3D() {
2666
5278
  return true;
2667
5279
  }
2668
- getSelected() {
2669
- return this.executeCommand("getSelected");
5280
+ screenToWorld(position) {
5281
+ if (!this.renderer) return {
5282
+ x: position.x,
5283
+ y: position.y,
5284
+ z: 0
5285
+ };
5286
+ const rect = this.canvas.getBoundingClientRect();
5287
+ const x = position.x / (rect.width / 2) - 1;
5288
+ const y = -position.y / (rect.height / 2) + 1;
5289
+ const point = new Vector3(x, y, -1);
5290
+ point.unproject(this.camera);
5291
+ return {
5292
+ x: point.x,
5293
+ y: point.y,
5294
+ z: point.z
5295
+ };
2670
5296
  }
2671
- setSelected(handles) {
2672
- this.executeCommand("setSelected", handles);
5297
+ worldToScreen(position) {
5298
+ if (!this.renderer) return {
5299
+ x: position.x,
5300
+ y: position.y
5301
+ };
5302
+ const point = new Vector3(position.x, position.y, position.z);
5303
+ point.project(this.camera);
5304
+ const rect = this.canvas.getBoundingClientRect();
5305
+ const x = (point.x + 1) * (rect.width / 2);
5306
+ const y = (-point.y + 1) * (rect.height / 2);
5307
+ return {
5308
+ x: x,
5309
+ y: y
5310
+ };
5311
+ }
5312
+ getScale() {
5313
+ return {
5314
+ x: 1,
5315
+ y: 1,
5316
+ z: 1
5317
+ };
2673
5318
  }
2674
5319
  executeCommand(id, ...args) {
2675
5320
  return commands("ThreeJS").executeCommand(id, this, ...args);
@@ -2677,14 +5322,89 @@ class Viewer extends EventEmitter2 {
2677
5322
  getComponent(type) {
2678
5323
  return this.components.find((component => component instanceof type));
2679
5324
  }
2680
- drawViewpoint(viewpoint) {}
5325
+ drawViewpoint(viewpoint) {
5326
+ var _a, _b, _c;
5327
+ if (!this.renderer) return;
5328
+ const getVector3FromPoint3d = ({x: x, y: y, z: z}) => new Vector3(x, y, z);
5329
+ const setPerspectiveCamera = camera => {
5330
+ if (camera) {
5331
+ this.camera.up.copy(getVector3FromPoint3d(camera.up_vector));
5332
+ this.camera.fov = camera.field_of_view;
5333
+ this.camera.position.copy(getVector3FromPoint3d(camera.view_point));
5334
+ this.camera.lookAt(getVector3FromPoint3d(camera.direction).add(this.camera.position));
5335
+ this.camera.updateMatrixWorld();
5336
+ this.camera.updateProjectionMatrix();
5337
+ }
5338
+ };
5339
+ const setClippingPlanes = clipping_planes => {
5340
+ clipping_planes === null || clipping_planes === void 0 ? void 0 : clipping_planes.forEach((clipping_plane => {
5341
+ const plane = new Plane;
5342
+ plane.setFromNormalAndCoplanarPoint(getVector3FromPoint3d(clipping_plane.direction), getVector3FromPoint3d(clipping_plane.location));
5343
+ this.renderer.clippingPlanes.push(plane);
5344
+ }));
5345
+ };
5346
+ const setSelection = selection => {
5347
+ this.setSelected(selection === null || selection === void 0 ? void 0 : selection.map((component => component.handle)));
5348
+ };
5349
+ const draggerName = (_a = this._activeDragger) === null || _a === void 0 ? void 0 : _a.name;
5350
+ this.setActiveDragger();
5351
+ this.clearSlices();
5352
+ this.clearOverlay();
5353
+ this.clearSelected();
5354
+ this.showAll();
5355
+ this.explode();
5356
+ setPerspectiveCamera(viewpoint.perspective_camera);
5357
+ setClippingPlanes(viewpoint.clipping_planes);
5358
+ setSelection(viewpoint.selection);
5359
+ this._markup.setViewpoint(viewpoint);
5360
+ this.target = getVector3FromPoint3d((_c = (_b = viewpoint.custom_fields) === null || _b === void 0 ? void 0 : _b.camera_target) !== null && _c !== void 0 ? _c : this.target);
5361
+ this.setActiveDragger(draggerName);
5362
+ this.emitEvent({
5363
+ type: "drawviewpoint",
5364
+ data: viewpoint
5365
+ });
5366
+ this.update();
5367
+ }
2681
5368
  createViewpoint() {
2682
- var _a;
2683
- const viewpoint = {};
2684
- viewpoint.snapshot = {
2685
- data: (_a = this.canvas) === null || _a === void 0 ? void 0 : _a.toDataURL("image/jpeg", .25)
5369
+ if (!this.renderer) return {};
5370
+ const getPoint3dFromVector3 = ({x: x, y: y, z: z}) => ({
5371
+ x: x,
5372
+ y: y,
5373
+ z: z
5374
+ });
5375
+ const getPerspectiveCamera = () => ({
5376
+ view_point: getPoint3dFromVector3(this.camera.position),
5377
+ direction: getPoint3dFromVector3(this.camera.getWorldDirection(new Vector3)),
5378
+ up_vector: getPoint3dFromVector3(this.camera.up),
5379
+ field_of_view: this.camera.fov
5380
+ });
5381
+ const getClippingPlanes = () => {
5382
+ const clipping_planes = [];
5383
+ this.renderer.clippingPlanes.forEach((plane => {
5384
+ const clipping_plane = {
5385
+ location: getPoint3dFromVector3(plane.coplanarPoint(new Vector3)),
5386
+ direction: getPoint3dFromVector3(plane.normal)
5387
+ };
5388
+ clipping_planes.push(clipping_plane);
5389
+ }));
5390
+ return clipping_planes;
5391
+ };
5392
+ const getSelection = () => this.getSelected().map((handle => ({
5393
+ handle: handle
5394
+ })));
5395
+ const viewpoint = {
5396
+ custom_fields: {}
2686
5397
  };
5398
+ viewpoint.perspective_camera = getPerspectiveCamera();
5399
+ viewpoint.clipping_planes = getClippingPlanes();
5400
+ viewpoint.selection = getSelection();
2687
5401
  viewpoint.description = (new Date).toDateString();
5402
+ this._markup.getViewpoint(viewpoint);
5403
+ viewpoint.custom_fields.camera_target = getPoint3dFromVector3(this.target);
5404
+ this.emitEvent({
5405
+ type: "createviewpoint",
5406
+ data: viewpoint
5407
+ });
2688
5408
  return viewpoint;
2689
5409
  }
2690
5410
  }