@abi-software/scaffoldvuer 1.2.1 → 1.3.0

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.
@@ -14,9 +14,10 @@
14
14
  :visible="tData.visible"
15
15
  :x="tData.x"
16
16
  :y="tData.y"
17
- :annotationDisplay="viewingMode === 'Annotation' && tData.active === true"
17
+ :annotationDisplay="annotationDisplay"
18
18
  @confirm-create="confirmCreate($event)"
19
19
  @cancel-create="cancelCreate()"
20
+ @confirm-delete="confirmDelete($event)"
20
21
  />
21
22
  <div
22
23
  id="organsDisplayArea"
@@ -26,78 +27,21 @@
26
27
  @keydown.66="backgroundChangeCallback"
27
28
  />
28
29
  <div v-show="displayUI && !isTransitioning">
29
- <div
30
- class="bottom-draw-control"
31
- v-if="viewingMode === 'Annotation' && userInformation"
32
- >
33
- <el-popover
34
- content="Comment"
35
- placement="top"
36
- :teleported="false"
37
- trigger="manual"
38
- width="80"
39
- popper-class="flatmap-popper"
40
- ref="commentPopover"
41
- :visible="hoverVisibilities[9].value"
42
- >
43
- <template #reference>
44
- <map-svg-icon
45
- icon="comment"
46
- class="icon-button shape"
47
- :class="[createData.shape === '' ? 'active' : '']"
48
- @click="toggleDrawing('')"
49
- @mouseover="showHelpText(9)"
50
- @mouseout="hideHelpText(9)"
51
- />
52
- </template>
53
- </el-popover>
54
- <el-popover
55
- content="Draw Point"
56
- placement="top"
57
- :teleported="false"
58
- trigger="manual"
59
- width="80"
60
- popper-class="flatmap-popper"
61
- ref="drawPointPopover"
62
- :visible="hoverVisibilities[10].value"
63
- >
64
- <template #reference>
65
- <map-svg-icon
66
- icon="drawPoint"
67
- class="icon-button shape"
68
- :class="[createData.shape === 'Point' ? 'active' : '']"
69
- @click="toggleDrawing('Point')"
70
- @mouseover="showHelpText(10)"
71
- @mouseout="hideHelpText(10)"
72
- />
73
- </template>
74
- </el-popover>
75
- <el-popover
76
- content="Draw Line"
77
- placement="top"
78
- :teleported="false"
79
- trigger="manual"
80
- width="80"
81
- popper-class="flatmap-popper"
82
- ref="drawLinePopover"
83
- :visible="hoverVisibilities[11].value"
84
- >
85
- <template #reference>
86
- <map-svg-icon
87
- icon="drawLine"
88
- class="icon-button shape"
89
- :class="[createData.shape === 'Line' ? 'active' : '']"
90
- @click="toggleDrawing('Line')"
91
- @mouseover="showHelpText(11)"
92
- @mouseout="hideHelpText(11)"
93
- />
94
- </template>
95
- </el-popover>
96
- </div>
30
+ <DrawToolbar
31
+ v-if="viewingMode === 'Annotation' && (userInformation || enableLocalAnnotations)"
32
+ :toolbarOptions="toolbarOptions"
33
+ :activeDrawTool="activeDrawTool"
34
+ :activeDrawMode="activeDrawMode"
35
+ :hoverVisibilities=hoverVisibilities
36
+ @clickToolbar="toggleDrawing"
37
+ @showTooltip="showHelpText"
38
+ @hideTooltip="hideHelpText"
39
+ ref="toolbarPopover"
40
+ />
97
41
  <el-popover
98
42
  v-if="displayWarning"
99
43
  ref="warningPopover"
100
- :visible="hoverVisibilities[6].value"
44
+ :visible="hoverVisibilities[7].value"
101
45
  :content="warningMessage"
102
46
  placement="right"
103
47
  width="max-content"
@@ -108,8 +52,8 @@
108
52
  <div
109
53
  v-if="displayWarning"
110
54
  class="message-icon warning-icon"
111
- @mouseover="showHelpText(6)"
112
- @mouseout="hideHelpText(6)"
55
+ @mouseover="showHelpText(7)"
56
+ @mouseout="hideHelpText(7)"
113
57
  >
114
58
  <el-icon><el-icon-warning-filled /></el-icon>
115
59
  <span class="message-text">Beta</span>
@@ -118,7 +62,7 @@
118
62
  </el-popover>
119
63
  <el-popover
120
64
  v-if="displayLatestChanges"
121
- :visible="hoverVisibilities[7].value"
65
+ :visible="hoverVisibilities[8].value"
122
66
  :content="latestChangesMessage"
123
67
  placement="right"
124
68
  :teleported="false"
@@ -130,8 +74,8 @@
130
74
  <div
131
75
  v-if="displayLatestChanges && latestChangesMessage"
132
76
  class="el-icon-warning message-icon latest-changesicon"
133
- @mouseover="showHelpText(7)"
134
- @mouseout="hideHelpText(7)"
77
+ @mouseover="showHelpText(8)"
78
+ @mouseout="hideHelpText(8)"
135
79
  >
136
80
  <el-icon><el-icon-warning-filled /></el-icon>
137
81
  <span class="message-text">What's new?</span>
@@ -139,7 +83,7 @@
139
83
  </template>
140
84
  </el-popover>
141
85
  <el-popover
142
- :visible="hoverVisibilities[5].value"
86
+ :visible="hoverVisibilities[6].value"
143
87
  content="Change region visibility"
144
88
  placement="right"
145
89
  width="max-content"
@@ -149,9 +93,8 @@
149
93
  ref="regionVisibilityPopover"
150
94
  >
151
95
  <template #reference>
152
- <tree-controls
153
- ref="treeControls"
154
- :help-mode="helpMode"
96
+ <ScaffoldTreeControls
97
+ ref="scaffoldTreeControls"
155
98
  :isReady="isReady"
156
99
  :show-colour-picker="showColourPicker"
157
100
  @object-selected="objectSelected"
@@ -161,13 +104,17 @@
161
104
  </template>
162
105
  </el-popover>
163
106
  <div class="primitive-controls-box">
164
- <primitive-controls ref="primitiveControls" :createData="createData"/>
107
+ <primitive-controls
108
+ ref="primitiveControls"
109
+ :createData="createData"
110
+ @primitivesUpdated="primitivesUpdated"
111
+ />
165
112
  </div>
166
113
  <el-popover
167
114
  v-if="timeVarying"
168
115
  ref="sliderPopover"
169
116
  width="max-content"
170
- :visible="hoverVisibilities[4].value"
117
+ :visible="hoverVisibilities[5].value"
171
118
  content="Move the slider to animate the region"
172
119
  placement="top"
173
120
  :teleported="false"
@@ -383,7 +330,7 @@
383
330
  >
384
331
  <el-row>
385
332
  <el-popover
386
- :visible="hoverVisibilities[8].value"
333
+ :visible="hoverVisibilities[3].value"
387
334
  content="Open new map"
388
335
  placement="right"
389
336
  :teleported="false"
@@ -398,15 +345,15 @@
398
345
  ref="openMapRef"
399
346
  icon="openMap"
400
347
  class="icon-button open-map-button"
401
- @mouseover="showHelpText(8)"
402
- @mouseout="hideHelpText(8)"
348
+ @mouseover="showHelpText(3)"
349
+ @mouseout="hideHelpText(3)"
403
350
  />
404
351
  </template>
405
352
  </el-popover>
406
353
  </el-row>
407
354
  <el-row>
408
355
  <el-popover
409
- :visible="hoverVisibilities[3].value"
356
+ :visible="hoverVisibilities[4].value"
410
357
  content="Change background color"
411
358
  placement="right"
412
359
  width="max-content"
@@ -420,8 +367,8 @@
420
367
  ref="backgroundIconRef"
421
368
  icon="changeBckgd"
422
369
  class="icon-button"
423
- @mouseover="showHelpText(3)"
424
- @mouseout="hideHelpText(3)"
370
+ @mouseover="showHelpText(4)"
371
+ @mouseout="hideHelpText(4)"
425
372
  />
426
373
  </template>
427
374
  </el-popover>
@@ -441,11 +388,14 @@ import {
441
388
  } from '@element-plus/icons-vue'
442
389
  import PrimitiveControls from "./PrimitiveControls.vue";
443
390
  import ScaffoldTooltip from "./ScaffoldTooltip.vue";
444
- import TreeControls from "./TreeControls.vue";
391
+ import ScaffoldTreeControls from "./ScaffoldTreeControls.vue";
445
392
  import { MapSvgIcon, MapSvgSpriteColor } from "@abi-software/svg-sprite";
393
+ import { DrawToolbar } from '@abi-software/map-utilities'
394
+ import '@abi-software/map-utilities/dist/style.css'
446
395
  import {
447
396
  addUserAnnotationWithFeature,
448
397
  annotationFeaturesToPrimitives,
398
+ getDeletableObjects,
449
399
  getDrawnAnnotations,
450
400
  getEditableLines,
451
401
  getObjectsFromAnnotations,
@@ -495,10 +445,11 @@ export default {
495
445
  MapSvgSpriteColor,
496
446
  PrimitiveControls,
497
447
  ScaffoldTooltip,
498
- TreeControls,
499
448
  ElIconWarningFilled,
500
449
  ElIconArrowDown,
501
450
  ElIconArrowLeft,
451
+ DrawToolbar,
452
+ ScaffoldTreeControls
502
453
  },
503
454
  setup(props) {
504
455
  const annotator = markRaw(new AnnotationService(`${props.flatmapAPI}annotator`));
@@ -719,12 +670,20 @@ export default {
719
670
  type: String,
720
671
  default: "https://mapcore-demo.org/current/flatmap/v3/"
721
672
  },
673
+ /**
674
+ * Enable local annotations
675
+ */
676
+ enableLocalAnnotations: {
677
+ type: Boolean,
678
+ default: false
679
+ },
722
680
  },
723
681
  provide() {
724
682
  return {
725
683
  flatmapAPI: this.flatmapAPI,
726
684
  scaffoldUrl: this.url,
727
685
  $annotator: this.annotator,
686
+ boundingDims: this.boundingDims,
728
687
  };
729
688
  },
730
689
  data: function () {
@@ -739,6 +698,7 @@ export default {
739
698
  y: 0,
740
699
  editingIndex: -1,
741
700
  faceIndex: -1,
701
+ toBeDeleted: false,
742
702
  },
743
703
  currentTime: 0.0,
744
704
  timeVarying: false,
@@ -753,15 +713,16 @@ export default {
753
713
  { value: false, ref: 'zoomInPopover' }, // 0
754
714
  { value: false, ref: 'zoomOutPopover' }, // 1
755
715
  { value: false, ref: 'zoomFitPopover' }, // 2
756
- { value: false, ref: 'settingsPopover' }, // 3
757
- { value: false, ref: 'sliderPopover' }, // 4
758
- { value: false, ref: 'regionVisibilityPopover' }, // 5
759
- { value: false, ref: 'warningPopover' }, // 6
760
- { value: false, ref: 'whatsNewPopover' }, // 7
761
- { value: false, ref: 'openMapPopover' }, // 8
762
- { value: false, ref: 'commentPopover' }, //9
763
- { value: false, ref: 'drawPointPopover' }, //10
764
- { value: false, ref: 'drawLinePopover' }, //11
716
+ { value: false, ref: 'openMapPopover' }, // 3
717
+ { value: false, ref: 'settingsPopover' }, // 4
718
+ { value: false, ref: 'sliderPopover' }, // 5
719
+ { value: false, ref: 'regionVisibilityPopover' }, // 6
720
+ { value: false, ref: 'warningPopover' }, // 7
721
+ { value: false, ref: 'whatsNewPopover' }, // 8
722
+ { value: false, refs: 'toolbarPopover', ref: 'editPopover' }, // 9
723
+ { value: false, refs: 'toolbarPopover', ref: 'pointPopover' }, // 10
724
+ { value: false, refs: 'toolbarPopover', ref: 'lineStringPopover' }, // 11
725
+ { value: false, refs: 'toolbarPopover', ref: 'deletePopover' }, // 11
765
726
  ],
766
727
  inHelp: false,
767
728
  helpModeActiveIndex: this.helpModeInitialIndex,
@@ -822,6 +783,19 @@ export default {
822
783
  openMapRef: undefined,
823
784
  backgroundIconRef: undefined,
824
785
  userInformation: undefined,
786
+ toolbarOptions: [
787
+ "Delete",
788
+ "Edit",
789
+ "Point",
790
+ "LineString",
791
+ ],
792
+ activeDrawTool: undefined,
793
+ activeDrawMode: undefined,
794
+ localAnnotationsList: markRaw([]),
795
+ boundingDims: {
796
+ centre: [0, 0, 0],
797
+ size:[1, 1, 1],
798
+ },
825
799
  };
826
800
  },
827
801
  watch: {
@@ -923,11 +897,12 @@ export default {
923
897
  mounted: function () {
924
898
  this.openMapRef = shallowRef(this.$refs.openMapRef);
925
899
  this.backgroundIconRef = shallowRef(this.$refs.backgroundIconRef);
926
- this.$refs.treeControls.setModule(this.$module);
900
+ this.$refs.scaffoldTreeControls.setModule(this.$module);
927
901
  let eventNotifier = new EventNotifier();
928
902
  eventNotifier.subscribe(this, this.eventNotifierCallback);
929
903
  this.$module.addNotifier(eventNotifier);
930
904
  this.$module.addOrganPartAddedCallback(this.zincObjectAdded);
905
+ this.$module.addOrganPartRemovedCallback(this.zincObjectRemoved);
931
906
  this.$module.initialiseRenderer(this.$refs.display);
932
907
  this.toggleRendering(this.render);
933
908
  this.ro = new ResizeObserver(this.adjustLayout).observe(
@@ -947,6 +922,10 @@ export default {
947
922
  },
948
923
  computed: {
949
924
  ...mapState(useMainStore, ['userToken']),
925
+ annotationDisplay: function() {
926
+ return this.viewingMode === 'Annotation' && this.tData.active === true &&
927
+ (this.activeDrawMode === 'Edit' || this.activeDrawMode === 'Delete');
928
+ }
950
929
  },
951
930
  methods: {
952
931
  /**
@@ -975,6 +954,38 @@ export default {
975
954
  //@arg The object added to the sceene
976
955
  this.$emit("zinc-object-added", zincObject);
977
956
  },
957
+ /**
958
+ * Internal only.
959
+ * Remove an entry matching region and group from
960
+ * local annotation list.
961
+ */
962
+ removeFromLocalAnnotationList: function(regionPath, groupName) {
963
+ for (let i = 0; i < this.localAnnotationsList.length; i++) {
964
+ const annotation = this.localAnnotationsList[i];
965
+ if (annotation.region === regionPath &&
966
+ annotation.group === groupName) {
967
+ this.localAnnotationsList.splice(i, 1);
968
+ return;
969
+ }
970
+ }
971
+ },
972
+ /**
973
+ * Internal only.
974
+ * This is called when a zinc object is removed.
975
+ */
976
+ zincObjectRemoved: function (zincObject) {
977
+ if (this.$module.scene) {
978
+ // zincObjectAdded will be alled in sequential callback
979
+ const regionPath = zincObject.region.getFullPath();
980
+ const groupName = zincObject.groupName;
981
+ const objects = zincObject.region.findObjectsWithGroupName(groupName, false);
982
+ //Remove relevant objects from the rest of the app.
983
+ if (objects.length === 0) {
984
+ this.$_searchIndex.removeZincObject(zincObject, zincObject.uuid);
985
+ this.removeFromLocalAnnotationList(regionPath, groupName);
986
+ }
987
+ }
988
+ },
978
989
  /**
979
990
  * Internal only.
980
991
  * Add regions to search index.
@@ -1037,10 +1048,42 @@ export default {
1037
1048
  * Function to clear current scene, the tree controls and the search index.
1038
1049
  */
1039
1050
  clearScene: function () {
1040
- if (this.$refs.treeControls) this.$refs.treeControls.clear();
1051
+ if (this.$refs.scaffoldTreeControls) this.$refs.scaffoldTreeControls.clear();
1041
1052
  if (this.$_searchIndex) this.$_searchIndex.removeAll();
1042
1053
  if (this.$module.scene) this.$module.scene.clearAll();
1043
1054
  },
1055
+ /**
1056
+ * @vuese
1057
+ * Add and edit local annotations
1058
+ */
1059
+ addAndEditAnnotations: function (region, group, zincObject, comment) {
1060
+ const annotation = addUserAnnotationWithFeature(this.annotator, this.userToken, zincObject,
1061
+ region, group, this.url, comment);
1062
+ if (this.enableLocalAnnotations) {
1063
+ annotation.group = group;
1064
+ let regionPath = region;
1065
+ if (regionPath.slice(-1) === "/") {
1066
+ regionPath = regionPath.slice(0, -1);
1067
+ }
1068
+ annotation.region = regionPath;
1069
+ //Remove previous entry if there is matching region and group
1070
+ this.removeFromLocalAnnotationList(regionPath, group);
1071
+ this.localAnnotationsList.push(annotation);
1072
+ }
1073
+ this.$emit('userPrimitivesUpdated', {region, group, zincObject});
1074
+ },
1075
+ /**
1076
+ * @vuese
1077
+ * Callback for when primitives have been update using primitive controls.
1078
+ * This is only called from callback.
1079
+ */
1080
+ primitivesUpdated: function(object) {
1081
+ if (object.isZincObject && object.isEditable) {
1082
+ const group = object.groupName;
1083
+ const region = object.region.getFullPath();
1084
+ this.addAndEditAnnotations(region, group, object, "Position Updated");
1085
+ }
1086
+ },
1044
1087
  /**
1045
1088
  * @vuese
1046
1089
  * Confirm creation of new primitive. This is only called from callback.
@@ -1053,10 +1096,10 @@ export default {
1053
1096
  payload.region,
1054
1097
  payload.group,
1055
1098
  this.createData.points,
1056
- undefined,
1099
+ payload.group,
1057
1100
  0x0022ee,
1058
1101
  );
1059
- } else if (payload.shape === "Line") {
1102
+ } else if (payload.shape === "LineString") {
1060
1103
  object = this.$module.scene.createLines(
1061
1104
  payload.region,
1062
1105
  payload.group,
@@ -1065,17 +1108,15 @@ export default {
1065
1108
  );
1066
1109
  } else if (payload.editingIndex > -1) {
1067
1110
  if (this._editingZincObject) {
1068
- this._editingZincObject.editVertice([this.createData.points[1]],
1111
+ this._editingZincObject.editVertices([this.createData.points[1]],
1069
1112
  payload.editingIndex);
1070
1113
  const region = this._editingZincObject.region.getFullPath() + "/";
1071
1114
  const group = this._editingZincObject.groupName;
1072
- addUserAnnotationWithFeature(this.annotator, this.userToken, this._editingZincObject,
1073
- region, group, this.url, "Position Updated");
1115
+ this.addAndEditAnnotations(region, group, this._editingZincObject, "Position Updated");
1074
1116
  }
1075
1117
  }
1076
1118
  if (object) {
1077
- addUserAnnotationWithFeature(this.annotator, this.userToken, object.zincObject,
1078
- payload.region, payload.group, this.url, "Create");
1119
+ this.addAndEditAnnotations(payload.region, payload.group, object.zincObject, "Create");
1079
1120
  object.zincObject.isEditable = true;
1080
1121
  this.tData.region = payload.region;
1081
1122
  this.tData.label = payload.group;
@@ -1084,6 +1125,10 @@ export default {
1084
1125
  }
1085
1126
  this.cancelCreate();
1086
1127
  },
1128
+ /**
1129
+ * Internal only.
1130
+ * Cancel create workflows. Reset all relevant UIs and data.
1131
+ */
1087
1132
  cancelCreate: function() {
1088
1133
  this.createData.points.length = 0;
1089
1134
  this.createData.toBeConfirmed = false;
@@ -1091,6 +1136,7 @@ export default {
1091
1136
  this.createData.editingIndex = -1;
1092
1137
  this.createData.faceIndex = -1;
1093
1138
  this.tData.visible = false;
1139
+ this.createData.toBeDeleted = false;
1094
1140
  if (this._tempLine) {
1095
1141
  this.$module.scene.removeTemporaryPrimitive(this._tempLine);
1096
1142
  this._tempLine = undefined;
@@ -1100,6 +1146,25 @@ export default {
1100
1146
  this._tempPoint = undefined;
1101
1147
  }
1102
1148
  },
1149
+ /**
1150
+ * Internal only.
1151
+ * Confirm delete of user created primitive.
1152
+ * This is only called from callback.
1153
+ */
1154
+ confirmDelete: function() {
1155
+ if (this._editingZincObject?.isEditable) {
1156
+ const regionPath = this._editingZincObject.region.getFullPath() + "/";
1157
+ const group = this._editingZincObject.groupName;
1158
+ const annotation = addUserAnnotationWithFeature(this.annotator, this.userToken,
1159
+ this._editingZincObject, regionPath, group, this.url, "Deleted");
1160
+ if (annotation) {
1161
+ const childRegion = this.$module.scene.getRootRegion().
1162
+ findChildFromPath(regionPath);
1163
+ childRegion.removeZincObject(this._editingZincObject);
1164
+ }
1165
+ }
1166
+ this.cancelCreate();
1167
+ },
1103
1168
  formatTooltip(val) {
1104
1169
  if (this.timeMax >= 1000) {
1105
1170
  if (val) {
@@ -1191,12 +1256,15 @@ export default {
1191
1256
  *
1192
1257
  * @vuese
1193
1258
  */
1194
- toggleDrawing: function (shapeName) {
1195
- if (shapeName === this.createData.shape) {
1196
- this.createData.shape = "";
1259
+ toggleDrawing: function (type, icon) {
1260
+ this.createData.toBeDeleted = false;
1261
+ if (type === 'mode') {
1262
+ this.activeDrawMode = icon;
1263
+ this.createData.shape = '';
1197
1264
  this.$module.selectObjectOnPick = true;
1198
- } else {
1199
- this.createData.shape = shapeName;
1265
+ } else if (type === 'tool') {
1266
+ this.activeDrawTool = icon;
1267
+ this.createData.shape = this.activeDrawTool;
1200
1268
  this.$module.selectObjectOnPick = false;
1201
1269
  }
1202
1270
  },
@@ -1258,7 +1326,7 @@ export default {
1258
1326
  },
1259
1327
  createEditTemporaryLines: function(worldCoords) {
1260
1328
  if (worldCoords) {
1261
- if (this.createData.shape === "Line" || this.createData.editingIndex > -1) {
1329
+ if (this.createData.shape === "LineString" || this.createData.editingIndex > -1) {
1262
1330
  if (this.createData.points.length === 1) {
1263
1331
  if (this._tempLine) {
1264
1332
  const positionAttribute = this._tempLine.geometry.getAttribute( 'position' );
@@ -1277,7 +1345,7 @@ export default {
1277
1345
  if (data[0].extraData.worldCoords) {
1278
1346
  if (this.createData.shape === "Point") {
1279
1347
  this.drawPoint(data[0].extraData.worldCoords, data);
1280
- } else if (this.createData.shape === "Line" ||
1348
+ } else if (this.createData.shape === "LineString" ||
1281
1349
  this.createData.editingIndex > -1) {
1282
1350
  this.drawLine(data[0].extraData.worldCoords, data);
1283
1351
  }
@@ -1285,19 +1353,28 @@ export default {
1285
1353
  }
1286
1354
  },
1287
1355
  drawPoint: function(coords, data) {
1288
- this.createData.points.length = 0;
1289
- this.createData.points.push(coords);
1290
- this.showRegionTooltipWithAnnotations(data, true, true);
1291
- this.createData.toBeConfirmed = true;
1292
- },
1293
- drawLine: function(coords, data) {
1294
- if (this.createData.points.length === 1) {
1356
+ if (this.createData.toBeConfirmed === false) {
1357
+ this.createData.points.length = 0;
1295
1358
  this.createData.points.push(coords);
1296
- this.showRegionTooltipWithAnnotations(data, true, true);
1297
- this.createData.toBeConfirmed = true;
1298
- } else {
1359
+ this.showRegionTooltipWithAnnotations(data, true, false);
1360
+ this.tData.x = 50;
1361
+ this.tData.y = 200;
1299
1362
  this._tempPoint = this.$module.scene.addTemporaryPoints([coords], 0xffff00);
1300
- this.createData.points.push(coords);
1363
+ this.createData.toBeConfirmed = true;
1364
+ }
1365
+ },
1366
+ drawLine: function(coords, data) {
1367
+ if (this.createData.toBeConfirmed === false) {
1368
+ if (this.createData.points.length === 1) {
1369
+ this.createData.points.push(coords);
1370
+ this.showRegionTooltipWithAnnotations(data, true, false);
1371
+ this.tData.x = 50;
1372
+ this.tData.y = 200;
1373
+ this.createData.toBeConfirmed = true;
1374
+ } else {
1375
+ this._tempPoint = this.$module.scene.addTemporaryPoints([coords], 0xffff00);
1376
+ this.createData.points.push(coords);
1377
+ }
1301
1378
  }
1302
1379
  },
1303
1380
  /**
@@ -1327,7 +1404,8 @@ export default {
1327
1404
  }
1328
1405
  },
1329
1406
  activateAnnotationMode: function(names, event) {
1330
- if (this.userInformation) {
1407
+ if (this.userInformation || this.enableLocalAnnotations) {
1408
+ this.createData.toBeDeleted = false;
1331
1409
  if ((this.createData.shape !== "") || (this.createData.editingIndex > -1)) {
1332
1410
  // Create new shape bsaed on current settings
1333
1411
  if (names.length > 0) {
@@ -1338,13 +1416,27 @@ export default {
1338
1416
  }
1339
1417
  }
1340
1418
  } else {
1341
- //Make sure the tooltip is displayed with annotation mode
1342
- const editing = getEditableLines(event);
1343
- if (editing) {
1344
- this.activateEditingMode(editing.zincObject, editing.faceIndex,
1345
- editing.vertexIndex, editing.point);
1419
+ //Make sure the tooltip is displayed with annotaion mode
1420
+ if (this.activeDrawMode === "Edit") {
1421
+ const editing = getEditableLines(event);
1422
+ if (editing) {
1423
+ this.activateEditingMode(editing.zincObject, editing.faceIndex,
1424
+ editing.vertexIndex, editing.point);
1425
+ }
1426
+ } else if (this.activeDrawMode === "Delete") {
1427
+ const zincObject = getDeletableObjects(event);
1428
+ if (zincObject) {
1429
+ this.createData.toBeDeleted = true;
1430
+ this._editingZincObject = zincObject;
1431
+ }
1432
+ }
1433
+ if (this.activeDrawMode === "Edit" || this.activeDrawMode === "Delete") {
1434
+ this.showRegionTooltipWithAnnotations(event.identifiers, true, false);
1435
+ this.tData.x = 50;
1436
+ this.tData.y = 200;
1437
+ } else {
1438
+ this.showRegionTooltipWithAnnotations(event.identifiers, true, true);
1346
1439
  }
1347
- this.showRegionTooltipWithAnnotations(event.identifiers, true, true);
1348
1440
  }
1349
1441
  } else {
1350
1442
  this.showRegionTooltipWithAnnotations(event.identifiers, true, true);
@@ -1362,89 +1454,90 @@ export default {
1362
1454
  *
1363
1455
  */
1364
1456
  eventNotifierCallback: function (event) {
1365
- const names = [];
1366
- let zincObjects = [];
1367
- if (event.eventType == 1 || event.eventType == 2) {
1368
- event.identifiers.forEach((identifier) => {
1369
- if (identifier) {
1370
- let id = identifier.data.id
1371
- ? identifier.data.id
1372
- : identifier.data.group;
1373
- names.push(id);
1374
- }
1375
- });
1376
- zincObjects = event.zincObjects;
1377
- }
1378
- /*
1379
- * Event Type 1: Selected
1380
- * Event Type 2: Highlighted
1381
- * Event Type 3: Move
1382
- */
1383
- if (event.eventType == 1) {
1384
- if (this.viewingMode === 'Annotation') {
1385
- this.activateAnnotationMode(names, event);
1386
-
1387
- } else {
1388
- if (this.$refs.treeControls) {
1389
- if (names.length > 0) {
1390
- //this.$refs.treeControls.changeActiveByNames(names, region, false);
1391
- this.$refs.treeControls.updateActiveUI(zincObjects);
1392
- this.updatePrimitiveControls(zincObjects);
1393
- } else {
1394
- this.hideRegionTooltip();
1395
- this.$refs.treeControls.removeActive(false);
1457
+ if (!(this.createData.toBeConfirmed || this.createData.toBeDeleted)) {
1458
+ const names = [];
1459
+ let zincObjects = [];
1460
+ if (event.eventType == 1 || event.eventType == 2) {
1461
+ event.identifiers.forEach((identifier) => {
1462
+ if (identifier) {
1463
+ let id = identifier.data.id
1464
+ ? identifier.data.id
1465
+ : identifier.data.group;
1466
+ names.push(id);
1396
1467
  }
1397
- }
1398
- //Emit when an object is selected
1399
- //@arg Identifier of selected objects
1400
- this.$emit("scaffold-selected", event.identifiers);
1468
+ });
1469
+ zincObjects = event.zincObjects;
1401
1470
  }
1402
- } else if (event.eventType == 2) {
1403
- if (this.selectedObjects.length === 0) {
1404
- this.hideRegionTooltip();
1405
- // const offsets = this.$refs.scaffoldContainer.getBoundingClientRect();
1406
- if (this.$refs.treeControls) {
1407
- if (names.length > 0) {
1408
- //this.$refs.treeControls.changeHoverByNames(names, region, false);
1409
- this.$refs.treeControls.updateHoverUI(zincObjects);
1410
- } else {
1411
- this.$refs.treeControls.removeHover(true);
1471
+ /*
1472
+ * Event Type 1: Selected
1473
+ * Event Type 2: Highlighted
1474
+ * Event Type 3: Move
1475
+ */
1476
+ if (event.eventType == 1) {
1477
+ if (this.viewingMode === 'Annotation') {
1478
+ this.activateAnnotationMode(names, event);
1479
+ } else {
1480
+ if (this.$refs.scaffoldTreeControls) {
1481
+ if (names.length > 0) {
1482
+ //this.$refs.scaffoldTreeControls.changeActiveByNames(names, region, false);
1483
+ this.$refs.scaffoldTreeControls.updateActiveUI(zincObjects);
1484
+ this.updatePrimitiveControls(zincObjects);
1485
+ } else {
1486
+ this.hideRegionTooltip();
1487
+ this.$refs.scaffoldTreeControls.removeActive(false);
1488
+ }
1412
1489
  }
1490
+ //Emit when an object is selected
1491
+ //@arg Identifier of selected objects
1492
+ this.$emit("scaffold-selected", event.identifiers);
1413
1493
  }
1414
- if (event.identifiers.length > 0 && event.identifiers[0]) {
1415
- let id = event.identifiers[0].data.id
1416
- ? event.identifiers[0].data.id
1417
- : event.identifiers[0].data.group;
1418
- if (event.identifiers[0].coords) {
1419
- this.tData.active = false;
1420
- this.tData.visible = true;
1421
- this.tData.label = id;
1422
- if (event.identifiers[0].data.region) {
1423
- this.tData.region = event.identifiers[0].data.region;
1494
+ } else if (event.eventType == 2) {
1495
+ if (this.selectedObjects.length === 0) {
1496
+ this.hideRegionTooltip();
1497
+ // const offsets = this.$refs.scaffoldContainer.getBoundingClientRect();
1498
+ if (this.$refs.scaffoldTreeControls) {
1499
+ if (names.length > 0) {
1500
+ //this.$refs.scaffoldTreeControls.changeHoverByNames(names, region, false);
1501
+ this.$refs.scaffoldTreeControls.updateHoverUI(zincObjects);
1502
+ } else {
1503
+ this.$refs.scaffoldTreeControls.removeHover(true);
1424
1504
  }
1425
- else {
1426
- this.tData.region = undefined;
1505
+ }
1506
+ if (event.identifiers.length > 0 && event.identifiers[0]) {
1507
+ let id = event.identifiers[0].data.id
1508
+ ? event.identifiers[0].data.id
1509
+ : event.identifiers[0].data.group;
1510
+ if (event.identifiers[0].coords) {
1511
+ this.tData.active = false;
1512
+ this.tData.visible = true;
1513
+ this.tData.label = id;
1514
+ if (event.identifiers[0].data.region) {
1515
+ this.tData.region = event.identifiers[0].data.region;
1516
+ }
1517
+ else {
1518
+ this.tData.region = undefined;
1519
+ }
1520
+ this.tData.x = event.identifiers[0].coords.x;
1521
+ this.tData.y = event.identifiers[0].coords.y;
1522
+ this.createEditTemporaryLines(event.identifiers[0].extraData.worldCoords);
1427
1523
  }
1428
- this.tData.x = event.identifiers[0].coords.x;
1429
- this.tData.y = event.identifiers[0].coords.y;
1430
- this.createEditTemporaryLines(event.identifiers[0].extraData.worldCoords);
1431
1524
  }
1525
+ //Emit when an object is highlighted
1526
+ //@arg Identifier of selected objects
1527
+ this.$emit("scaffold-highlighted", event.identifiers);
1432
1528
  }
1433
- //Emit when an object is highlighted
1434
- //@arg Identifier of selected objects
1435
- this.$emit("scaffold-highlighted", event.identifiers);
1436
- }
1437
- } else if (event.eventType == 3) {
1438
- //MOVE
1439
- if (event.identifiers.length > 0 && event.identifiers[0]) {
1440
- if (event.identifiers[0].coords) {
1441
- const offsets =
1442
- this.$refs.scaffoldContainer.getBoundingClientRect();
1443
- this.tData.x = event.identifiers[0].coords.x - offsets.left;
1444
- this.tData.y = event.identifiers[0].coords.y - offsets.top;
1529
+ } else if (event.eventType == 3) {
1530
+ //MOVE
1531
+ if (event.identifiers.length > 0 && event.identifiers[0]) {
1532
+ if (event.identifiers[0].coords) {
1533
+ const offsets =
1534
+ this.$refs.scaffoldContainer.getBoundingClientRect();
1535
+ this.tData.x = event.identifiers[0].coords.x - offsets.left;
1536
+ this.tData.y = event.identifiers[0].coords.y - offsets.top;
1537
+ this.createEditTemporaryLines(event.identifiers[0].extraData.worldCoords);
1538
+ }
1445
1539
  this.createEditTemporaryLines(event.identifiers[0].extraData.worldCoords);
1446
1540
  }
1447
- this.createEditTemporaryLines(event.identifiers[0].extraData.worldCoords);
1448
1541
  }
1449
1542
  }
1450
1543
  },
@@ -1521,11 +1614,11 @@ export default {
1521
1614
  changeActiveByName: function (names, region, propagate) {
1522
1615
  const isArray = Array.isArray(names);
1523
1616
  if (names === undefined || (isArray && names.length === 0)) {
1524
- this.$refs.treeControls.removeActive(propagate);
1617
+ this.$refs.scaffoldTreeControls.removeActive(propagate);
1525
1618
  } else {
1526
1619
  let array = names;
1527
1620
  if (!isArray) array = [array];
1528
- this.$refs.treeControls.changeActiveByNames(array, region, propagate);
1621
+ this.$refs.scaffoldTreeControls.changeActiveByNames(array, region, propagate);
1529
1622
  }
1530
1623
  },
1531
1624
  /**
@@ -1536,11 +1629,11 @@ export default {
1536
1629
  changeHighlightedByName: function (names, region, propagate) {
1537
1630
  const isArray = Array.isArray(names);
1538
1631
  if (names === undefined || (isArray && names.length === 0)) {
1539
- this.$refs.treeControls.removeHover(propagate);
1632
+ this.$refs.scaffoldTreeControls.removeHover(propagate);
1540
1633
  } else {
1541
1634
  let array = names;
1542
1635
  if (!isArray) array = [array];
1543
- this.$refs.treeControls.changeHoverByNames(array, region, propagate);
1636
+ this.$refs.scaffoldTreeControls.changeHoverByNames(array, region, propagate);
1544
1637
  }
1545
1638
  },
1546
1639
  /**
@@ -1565,26 +1658,11 @@ export default {
1565
1658
  const activePopoverObj = this.hoverVisibilities[this.helpModeActiveIndex];
1566
1659
 
1567
1660
  if (activePopoverObj) {
1661
+ const popoverRefsId = activePopoverObj?.refs;
1568
1662
  const popoverRefId = activePopoverObj?.ref;
1569
- const popoverRef = this.$refs[popoverRefId];
1570
-
1571
- if (popoverRef) {
1572
- // Open pathway drawer if the tooltip is inside or beside
1573
- const { parentElement, nextElementSibling } = popoverRef.$el;
1574
- const isPathwayContainer = (element) => {
1575
- return element && (
1576
- element.classList.contains('pathway-container') ||
1577
- element.classList.contains('pathway-location')
1578
- );
1579
- };
1580
-
1581
- if (
1582
- isPathwayContainer(parentElement) ||
1583
- isPathwayContainer(nextElementSibling)
1584
- ) {
1585
- this.drawerOpen = true;
1586
- }
1587
- } else {
1663
+ const popoverRef = this.$refs[popoverRefsId ? popoverRefsId : popoverRefId];
1664
+
1665
+ if (!popoverRef) {
1588
1666
  // skip the unavailable tooltips
1589
1667
  this.helpModeActiveIndex += 1;
1590
1668
  }
@@ -1807,6 +1885,10 @@ export default {
1807
1885
  }
1808
1886
  }
1809
1887
  });
1888
+ } else if (this.viewingMode === "Exploration") {
1889
+ this.activeDrawTool = undefined;
1890
+ this.activeDrawMode = undefined;
1891
+ this.createData.shape = "";
1810
1892
  }
1811
1893
  if ((this.viewingMode === "Exploration") ||
1812
1894
  (this.viewingMode === "Annotation") &&
@@ -1974,10 +2056,11 @@ export default {
1974
2056
  if (options.visibility) {
1975
2057
  // Some UIs may not be ready at this time.
1976
2058
  this.$nextTick(() => {
1977
- this.$refs.treeControls.setState(options.visibility);
2059
+ this.$refs.scaffoldTreeControls.setState(options.visibility);
1978
2060
  });
1979
2061
  }
1980
2062
  }
2063
+ this.localAnnotationsList.length = 0;
1981
2064
  this.updateSettingsfromScene();
1982
2065
  this.$module.updateTime(0.01);
1983
2066
  this.$module.updateTime(0);
@@ -1986,8 +2069,16 @@ export default {
1986
2069
  //Emit when all objects have been loaded
1987
2070
  this.$emit("on-ready");
1988
2071
  this.setMarkers();
2072
+ //Create a bounding box.
1989
2073
  this._boundingBoxGeo = this.$module.scene.addBoundingBoxPrimitive(
1990
2074
  "_helper", "boundingBox", 0x40E0D0, 0.15);
2075
+ //Create planes.
2076
+ this._slides = this.$module.scene.addSlicesPrimitive(
2077
+ "_helper", ["x-plane", "y-plane", "z-plane"], [0xFF5555, 0x55FF55, 0x5555FF],
2078
+ 0.5);
2079
+ const {centre, size} = this.$module.getCentreAndSize();
2080
+ this.boundingDims.centre = centre;
2081
+ this.boundingDims.size = size;
1991
2082
  this.isReady = true;
1992
2083
  };
1993
2084
  },
@@ -2004,8 +2095,8 @@ export default {
2004
2095
  viewport: undefined,
2005
2096
  visibility: undefined,
2006
2097
  };
2007
- if (this.$refs.treeControls)
2008
- state.visibility = this.$refs.treeControls.getState();
2098
+ if (this.$refs.scaffoldTreeControls)
2099
+ state.visibility = this.$refs.scaffoldTreeControls.getState();
2009
2100
  if (this.$module.scene) {
2010
2101
  let zincCameraControls = this.$module.scene.getZincCameraControls();
2011
2102
  state.viewport = zincCameraControls.getCurrentViewport();
@@ -2034,7 +2125,7 @@ export default {
2034
2125
  .getZincCameraControls()
2035
2126
  .setCurrentCameraSettings(state.viewport);
2036
2127
  if (state.visibility)
2037
- this.$refs.treeControls.setState(state.visibility);
2128
+ this.$refs.scaffoldTreeControls.setState(state.visibility);
2038
2129
  } else {
2039
2130
  this.$module.setFinishDownloadCallback(
2040
2131
  this.setURLFinishCallback({
@@ -2056,6 +2147,45 @@ export default {
2056
2147
  exportGLTF: function (binary) {
2057
2148
  return this.$module.scene.exportGLTF(binary);
2058
2149
  },
2150
+ /**
2151
+ * Return a copy of the local annotations list.
2152
+ * This list is used for storing user created annotation
2153
+ * when enableLocalAnnotations is set to true.
2154
+ *
2155
+ * @vuese
2156
+ */
2157
+ getLocalAnnotations: function () {
2158
+ return [...this.localAnnotationsList];
2159
+ },
2160
+ /**
2161
+ * Import local annotations. The annotations will only
2162
+ * be imported when enableLocalAnnotations is set to
2163
+ * true;
2164
+ *
2165
+ * @vuese
2166
+ */
2167
+ importLocalAnnotations: function (annotationsList) {
2168
+ if (this.enableLocalAnnotations) {
2169
+ //Make sure the annotations are encoded correctly
2170
+ annotationsList.forEach(annotation => {
2171
+ const group = annotation.group;
2172
+ const region = annotation.region;
2173
+ let fullName = region.slice(-1) === "/" ? region : region + "/";
2174
+ const noSlash = fullName.slice(0, -1);
2175
+ annotation.region = noSlash;
2176
+ fullName = fullName + group;
2177
+ const featureID = encodeURIComponent(fullName);
2178
+ annotation.item.id = featureID;
2179
+ annotation.feature.id = featureID;
2180
+ });
2181
+ const featuresList = annotationsList.map((annotation) => annotation.feature);
2182
+ annotationFeaturesToPrimitives(this.$module.scene, featuresList);
2183
+ //Make a local non-reactive copy.
2184
+ annotationsList.forEach((annotation) => {
2185
+ this.localAnnotationsList.push({...annotation});
2186
+ });
2187
+ }
2188
+ },
2059
2189
  /**
2060
2190
  * Function used for reading in new scaffold metadata and a custom
2061
2191
  * viewport. This function will ignore the state prop and
@@ -2070,7 +2200,7 @@ export default {
2070
2200
  let visibility =
2071
2201
  state && state.visibility ? state.visibility : undefined;
2072
2202
  this._currentURL = newValue;
2073
- if (this.$refs.treeControls) this.$refs.treeControls.clear();
2203
+ if (this.$refs.scaffoldTreeControls) this.$refs.scaffoldTreeControls.clear();
2074
2204
  this.loading = true;
2075
2205
  this.timeVarying = false;
2076
2206
  this.isReady = false;
@@ -2124,12 +2254,14 @@ export default {
2124
2254
  * Callback using ResizeObserver.
2125
2255
  */
2126
2256
  adjustLayout: function () {
2127
- let width = this.$refs.scaffoldContainer.clientWidth;
2128
- this.minimisedSlider = width < 812;
2129
- if (this.minimisedSlider) {
2130
- this.sliderPosition = this.drawerOpen ? "right" : "left";
2131
- } else {
2132
- this.sliderPosition = "";
2257
+ if (this.$refs.scaffoldContainer) {
2258
+ let width = this.$refs.scaffoldContainer.clientWidth;
2259
+ this.minimisedSlider = width < 812;
2260
+ if (this.minimisedSlider) {
2261
+ this.sliderPosition = this.drawerOpen ? "right" : "left";
2262
+ } else {
2263
+ this.sliderPosition = "";
2264
+ }
2133
2265
  }
2134
2266
  },
2135
2267
  toggleRendering: function (flag) {
@@ -2328,17 +2460,6 @@ export default {
2328
2460
  padding-left: 8px;
2329
2461
  }
2330
2462
 
2331
- .bottom-draw-control {
2332
- background-color: var(--el-color-primary-light-9);
2333
- padding: 4px 4px 2px 4px;
2334
- border-style: solid;
2335
- border-color: var(--el-color-primary-light-5);
2336
- border-radius: 1rem;
2337
- position: absolute;
2338
- right: calc(50vw - 100px);;
2339
- bottom: 16px;
2340
- }
2341
-
2342
2463
  :deep(.non-selectable) {
2343
2464
  user-select: none;
2344
2465
  }
@@ -2452,15 +2573,6 @@ export default {
2452
2573
  border: none;
2453
2574
  outline: none;
2454
2575
  }
2455
-
2456
- &.shape {
2457
- margin-left: 4px;
2458
- margin-right: 4px;
2459
- color: var(--el-color-primary-light-5)!important;
2460
- &.active {
2461
- color: var(--el-color-primary)!important;
2462
- }
2463
- }
2464
2576
  }
2465
2577
 
2466
2578
  .bottom-right-control {