@inweb/viewer-three 25.11.0 → 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.
@@ -2,6 +2,8 @@ import { Vector2, Raycaster, MeshBasicMaterial, Box3, Vector3, Sphere, LoadingMa
2
2
 
3
3
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
4
4
 
5
+ import Konva from "konva";
6
+
5
7
  import { RoomEnvironment } from "three/examples/jsm/environments/RoomEnvironment.js";
6
8
 
7
9
  class Commands {
@@ -392,7 +394,7 @@ function applyModelTransform(viewer, model) {
392
394
 
393
395
  commands("ThreeJS").registerCommand("applyModelTransform", applyModelTransform);
394
396
 
395
- commands("ThreeJS").registerCommand("clearMarkup", (viewer => console.warn("clearMarkup not implemented")));
397
+ commands("ThreeJS").registerCommand("clearMarkup", (viewer => viewer.clearOverlay()));
396
398
 
397
399
  commands("ThreeJS").registerCommandAlias("clearMarkup", "clearOverlay");
398
400
 
@@ -446,15 +448,15 @@ class SelectionComponent {
446
448
  this.viewer.removeEventListener("dblclick", this.onDoubleClick);
447
449
  this.viewer.removeEventListener("optionschange", this.optionsChange);
448
450
  }
449
- getMousePosition(event, position) {
450
- const rect = this.viewer.canvas.getBoundingClientRect();
451
- position.setX((event.clientX - rect.left) / rect.width);
452
- position.setY((event.clientY - rect.top) / rect.height);
453
- return position;
451
+ getMousePosition(event, target) {
452
+ return target.set(event.clientX, event.clientY);
454
453
  }
455
- getPointerIntersects(position) {
456
- const mouse = new Vector2(position.x * 2 - 1, -(position.y * 2) + 1);
457
- this.raycaster.setFromCamera(mouse, this.viewer.camera);
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);
458
460
  const objects = [];
459
461
  this.viewer.scene.traverseVisible((child => objects.push(child)));
460
462
  return this.raycaster.intersectObjects(objects, false);
@@ -491,12 +493,7 @@ commands("ThreeJS").registerCommand("clearSelected", clearSelected);
491
493
 
492
494
  commands("ThreeJS").registerCommandAlias("clearSelected", "unselect");
493
495
 
494
- function clearSlices(viewer) {
495
- viewer.renderer.clippingPlanes = [];
496
- viewer.update();
497
- }
498
-
499
- commands("ThreeJS").registerCommand("clearSlices", clearSlices);
496
+ commands("ThreeJS").registerCommand("clearSlices", (viewer => viewer.clearSlices()));
500
497
 
501
498
  function createPreview(viewer, type = "image/jpeg", encoderOptions = .25) {
502
499
  viewer.update(true);
@@ -560,8 +557,8 @@ const defaultViewPositions = {
560
557
  bottom: new Vector3(0, 0, -1),
561
558
  left: new Vector3(-1, 0, 0),
562
559
  right: new Vector3(1, 0, 0),
563
- front: new Vector3(0, 1, 0),
564
- back: new Vector3(0, -1, 0),
560
+ front: new Vector3(0, -1, 0),
561
+ back: new Vector3(0, 1, 0),
565
562
  sw: new Vector3(-.5, -.5, 1).normalize(),
566
563
  se: new Vector3(.5, -.5, 1).normalize(),
567
564
  ne: new Vector3(.5, .5, 1).normalize(),
@@ -570,15 +567,15 @@ const defaultViewPositions = {
570
567
 
571
568
  function setDefaultViewPosition(viewer, position) {
572
569
  const direction = defaultViewPositions[position] || defaultViewPositions["sw"];
573
- const camera = viewer.camera;
574
570
  const center = viewer.extents.getCenter(new Vector3);
575
571
  const sphere = viewer.extents.getBoundingSphere(new Sphere);
576
- const offset = (new Vector3).copy(direction).multiplyScalar(sphere.radius);
577
- camera.position.copy(center);
578
- camera.position.add(offset);
579
- 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);
580
575
  camera.lookAt(center);
581
576
  camera.updateProjectionMatrix();
577
+ camera.updateMatrixWorld();
578
+ viewer.target.copy(center);
582
579
  viewer.update();
583
580
  viewer.emit({
584
581
  type: "viewposition",
@@ -698,7 +695,7 @@ function regenerateAll(viewer) {
698
695
  commands("ThreeJS").registerCommand("regenerateAll", regenerateAll);
699
696
 
700
697
  function resetView(viewer) {
701
- viewer.executeCommand("setActiveDragger", "");
698
+ viewer.executeCommand("setActiveDragger");
702
699
  viewer.executeCommand("clearSlices");
703
700
  viewer.executeCommand("clearOverlay");
704
701
  viewer.executeCommand("setMarkupColor");
@@ -899,6 +896,1850 @@ class EventEmitter2 {
899
896
  }
900
897
  }
901
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
+
902
2743
  const _changeEvent$2 = {
903
2744
  type: "change"
904
2745
  };
@@ -1650,6 +3491,7 @@ class OrbitDragger {
1650
3491
  this.viewer.on("geometryend", this.updateControls);
1651
3492
  this.viewer.on("viewposition", this.updateControls);
1652
3493
  this.viewer.on("zoom", this.updateControls);
3494
+ this.viewer.on("drawviewpoint", this.updateControls);
1653
3495
  this.viewer.on("contextmenu", this.stopContextMenu);
1654
3496
  this.updateControls();
1655
3497
  }
@@ -1657,6 +3499,7 @@ class OrbitDragger {
1657
3499
  this.viewer.off("geometryend", this.updateControls);
1658
3500
  this.viewer.off("viewposition", this.updateControls);
1659
3501
  this.viewer.off("zoom", this.updateControls);
3502
+ this.viewer.off("drawviewpoint", this.updateControls);
1660
3503
  this.viewer.off("contextmenu", this.stopContextMenu);
1661
3504
  this.orbit.removeEventListener("change", this.controlsChange);
1662
3505
  this.orbit.dispose();
@@ -2958,6 +4801,7 @@ class DefaultPositionComponent {
2958
4801
  this.viewer.camera.far = size * 100;
2959
4802
  this.viewer.camera.updateMatrixWorld();
2960
4803
  this.viewer.camera.updateProjectionMatrix();
4804
+ this.viewer.executeCommand("setDefaultViewPosition", "sw");
2961
4805
  this.viewer.executeCommand("zoomToExtents");
2962
4806
  };
2963
4807
  this.viewer = viewer;
@@ -3127,6 +4971,7 @@ class Viewer extends EventEmitter2 {
3127
4971
  this.renderTime = 0;
3128
4972
  this.render = this.render.bind(this);
3129
4973
  this.update = this.update.bind(this);
4974
+ this._markup = new KonvaMarkup;
3130
4975
  }
3131
4976
  get options() {
3132
4977
  return this._options;
@@ -3134,6 +4979,9 @@ class Viewer extends EventEmitter2 {
3134
4979
  get draggers() {
3135
4980
  return Object.keys(this.draggerFactory);
3136
4981
  }
4982
+ get markup() {
4983
+ return this._markup;
4984
+ }
3137
4985
  initialize(canvas, onProgress) {
3138
4986
  this.addEventListener("optionschange", (event => this.syncOptions(event.data)));
3139
4987
  this.scene = new Scene;
@@ -3153,6 +5001,7 @@ class Viewer extends EventEmitter2 {
3153
5001
  this.renderer.toneMapping = LinearToneMapping;
3154
5002
  this.canvas = canvas;
3155
5003
  this.canvasEvents.forEach((x => canvas.addEventListener(x, this.canvaseventlistener)));
5004
+ this._markup.initialize(this.canvas, this.canvasEvents, this, this);
3156
5005
  this.components.push(new ExtentsComponent(this));
3157
5006
  this.components.push(new LightComponent(this));
3158
5007
  this.components.push(new BackgroundComponent(this));
@@ -3162,6 +5011,7 @@ class Viewer extends EventEmitter2 {
3162
5011
  this.components.push(new SelectionComponent(this));
3163
5012
  this.components.push(new WCSHelperComponent(this));
3164
5013
  this.syncOptions();
5014
+ this.syncOverlay();
3165
5015
  this.renderTime = performance.now();
3166
5016
  this.render(this.renderTime);
3167
5017
  if (typeof onProgress === "function") onProgress(new ProgressEvent("progress", {
@@ -3187,9 +5037,10 @@ class Viewer extends EventEmitter2 {
3187
5037
  });
3188
5038
  this.components.forEach((component => component.dispose()));
3189
5039
  this.components = [];
3190
- this.setActiveDragger("");
5040
+ this.setActiveDragger();
3191
5041
  this.removeAllListeners();
3192
5042
  this.clear();
5043
+ this._markup.dispose();
3193
5044
  if (this.canvas) {
3194
5045
  this.canvasEvents.forEach((x => this.canvas.removeEventListener(x, this.canvaseventlistener)));
3195
5046
  this.canvas = undefined;
@@ -3299,8 +5150,9 @@ class Viewer extends EventEmitter2 {
3299
5150
  if (!gltf.scene) throw new Error("No glTF scene found");
3300
5151
  this.models.push(gltf);
3301
5152
  this.scene.add(gltf.scene);
5153
+ this.syncOptions();
5154
+ this.syncOverlay();
3302
5155
  this.update();
3303
- this.resetActiveDragger();
3304
5156
  this.emitEvent({
3305
5157
  type: "databasechunk"
3306
5158
  });
@@ -3332,20 +5184,37 @@ class Viewer extends EventEmitter2 {
3332
5184
  if (object.material) disposeMaterial(object.material);
3333
5185
  }
3334
5186
  this.setActiveDragger();
3335
- this.selected = [];
3336
- this.renderer.clippingPlanes = [];
5187
+ this.clearSlices();
5188
+ this.clearOverlay();
3337
5189
  this.helpers.traverse(disposeObject);
3338
5190
  this.helpers.clear();
3339
5191
  this.models.forEach((gltf => gltf.scene.traverse(disposeObject)));
3340
5192
  this.models.forEach((gltf => gltf.scene.removeFromParent()));
3341
5193
  this.models = [];
3342
5194
  this.scene.clear();
5195
+ this.syncOptions();
5196
+ this.syncOverlay();
5197
+ this.update(true);
3343
5198
  this.emitEvent({
3344
5199
  type: "clear"
3345
5200
  });
3346
- this.update(true);
3347
5201
  return this;
3348
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
+ }
3349
5218
  getSelected() {
3350
5219
  return this.executeCommand("getSelected");
3351
5220
  }
@@ -3394,6 +5263,7 @@ class Viewer extends EventEmitter2 {
3394
5263
  type: "changeactivedragger",
3395
5264
  data: name
3396
5265
  });
5266
+ this.update();
3397
5267
  }
3398
5268
  return this._activeDragger;
3399
5269
  }
@@ -3407,20 +5277,134 @@ class Viewer extends EventEmitter2 {
3407
5277
  is3D() {
3408
5278
  return true;
3409
5279
  }
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
+ };
5296
+ }
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
+ };
5318
+ }
3410
5319
  executeCommand(id, ...args) {
3411
5320
  return commands("ThreeJS").executeCommand(id, this, ...args);
3412
5321
  }
3413
5322
  getComponent(type) {
3414
5323
  return this.components.find((component => component instanceof type));
3415
5324
  }
3416
- 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
+ }
3417
5368
  createViewpoint() {
3418
- var _a;
3419
- const viewpoint = {};
3420
- viewpoint.snapshot = {
3421
- 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;
3422
5391
  };
5392
+ const getSelection = () => this.getSelected().map((handle => ({
5393
+ handle: handle
5394
+ })));
5395
+ const viewpoint = {
5396
+ custom_fields: {}
5397
+ };
5398
+ viewpoint.perspective_camera = getPerspectiveCamera();
5399
+ viewpoint.clipping_planes = getClippingPlanes();
5400
+ viewpoint.selection = getSelection();
3423
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
+ });
3424
5408
  return viewpoint;
3425
5409
  }
3426
5410
  }