@abi-software/flatmapvuer 0.6.1-annotator.0 → 0.6.1-annotator.2

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.
@@ -20,6 +20,11 @@
20
20
  :visible="hoverVisibilities[6].value"
21
21
  ref="warningPopover"
22
22
  >
23
+ <!--
24
+ What magic meaning do the numbers 6, 7, etc have?
25
+
26
+ Please use `const` to assign meaningful names to them...
27
+ -->
23
28
  <p
24
29
  v-if="isLegacy"
25
30
  @mouseover="showToolitip(6)"
@@ -137,10 +142,10 @@
137
142
  </el-icon>
138
143
 
139
144
  <div class="bottom-draw-control"
140
- v-if="viewingMode === 'Annotation' && userInformation"
141
- v-show="!disableUI">
145
+ v-show="viewingMode === 'Annotation' && userInformation && !disableUI"
146
+ >
142
147
  <el-popover
143
- content="Relevance"
148
+ content="Draw Connection"
144
149
  placement="top"
145
150
  :teleported="false"
146
151
  trigger="manual"
@@ -151,11 +156,10 @@
151
156
  <template #reference>
152
157
  <map-svg-icon
153
158
  icon="connection"
154
- class="icon-button connection"
155
- @click="displayRelevanceDialog(true)"
159
+ class="icon-button drawConnection inactive"
160
+ @click="connectionDialogPopup"
156
161
  @mouseover="showToolitip(10)"
157
162
  @mouseout="hideToolitip(10)"
158
- v-show="hasRelevance && !inDrawing"
159
163
  />
160
164
  </template>
161
165
  </el-popover>
@@ -167,13 +171,13 @@
167
171
  width="80"
168
172
  popper-class="flatmap-popper"
169
173
  :visible="hoverVisibilities[11].value"
170
- v-if="drawingType !== 'LineString' && drawingType !== 'Polygon'"
174
+ v-if="drawnType !== 'LineString' && drawnType !== 'Polygon'"
171
175
  >
172
176
  <template #reference>
173
177
  <map-svg-icon
174
178
  icon="drawPoint"
175
179
  class="icon-button drawPoint"
176
- @click="drawnEvent('Point')"
180
+ @click="drawingEvent('Point')"
177
181
  @mouseover="showToolitip(11)"
178
182
  @mouseout="hideToolitip(11)"
179
183
  />
@@ -187,13 +191,13 @@
187
191
  width="80"
188
192
  popper-class="flatmap-popper"
189
193
  :visible="hoverVisibilities[12].value"
190
- v-if="drawingType !== 'Point' && drawingType !== 'Polygon'"
194
+ v-if="drawnType !== 'Point' && drawnType !== 'Polygon'"
191
195
  >
192
196
  <template #reference>
193
197
  <map-svg-icon
194
198
  icon="drawLine"
195
199
  class="icon-button drawLineString"
196
- @click="drawnEvent('LineString')"
200
+ @click="drawingEvent('LineString')"
197
201
  @mouseover="showToolitip(12)"
198
202
  @mouseout="hideToolitip(12)"
199
203
  />
@@ -207,13 +211,13 @@
207
211
  width="80"
208
212
  popper-class="flatmap-popper"
209
213
  :visible="hoverVisibilities[13].value"
210
- v-if="drawingType !== 'Point' && drawingType !== 'LineString'"
214
+ v-if="drawnType !== 'Point' && drawnType !== 'LineString'"
211
215
  >
212
216
  <template #reference>
213
217
  <map-svg-icon
214
218
  icon="drawPolygon"
215
219
  class="icon-button drawPolygon"
216
- @click="drawnEvent('Polygon')"
220
+ @click="drawingEvent('Polygon')"
217
221
  @mouseover="showToolitip(13)"
218
222
  @mouseout="hideToolitip(13)"
219
223
  />
@@ -231,8 +235,8 @@
231
235
  <template #reference>
232
236
  <map-svg-icon
233
237
  icon="drawTrash"
234
- class="icon-button drawTrash"
235
- @click="drawnEvent('Delete')"
238
+ class="icon-button drawDelete"
239
+ @click="drawingEvent('Delete')"
236
240
  @mouseover="showToolitip(14)"
237
241
  @mouseout="hideToolitip(14)"
238
242
  />
@@ -250,8 +254,8 @@
250
254
  <template #reference>
251
255
  <map-svg-icon
252
256
  icon="comment"
253
- class="icon-button comment"
254
- @click="drawnEvent('Edit')"
257
+ class="icon-button drawEdit"
258
+ @click="drawingEvent('Edit')"
255
259
  @mouseover="showToolitip(15)"
256
260
  @mouseout="hideToolitip(15)"
257
261
  />
@@ -342,7 +346,6 @@
342
346
  class="pathway-container"
343
347
  :class="{ open: drawerOpen, close: !drawerOpen }"
344
348
  :style="{ 'max-height': pathwaysMaxHeight + 'px' }"
345
- v-if="pathControls"
346
349
  v-popover:checkBoxPopover
347
350
  >
348
351
  <svg-legends v-if="!isFC" class="svg-legends-container" />
@@ -473,7 +476,14 @@
473
476
  virtual-triggering
474
477
  >
475
478
  <el-row v-for="item in openMapOptions" :key="item.key">
476
- <el-button type="primary" plain @click="$emit('open-map', item.key)">
479
+ <el-button type="primary" plain
480
+ @click="/**
481
+ * This event is emitted when the user chooses a different map option
482
+ * from ``openMapOptions`` props.
483
+ * @arg mapOption.key
484
+ * */
485
+ $emit('open-map', item.key)"
486
+ >
477
487
  {{ item.display }}
478
488
  </el-button>
479
489
  </el-row>
@@ -485,7 +495,7 @@
485
495
  width="200"
486
496
  :teleported="false"
487
497
  trigger="click"
488
- popper-class="background-popper"
498
+ popper-class="background-popper h-auto"
489
499
  virtual-triggering
490
500
  >
491
501
  <div>
@@ -499,8 +509,8 @@
499
509
  popper-class="flatmap_dropdown"
500
510
  >
501
511
  <el-option
502
- v-for="item in viewingModes"
503
- :key="item"
512
+ v-for="(item, i) in viewingModes"
513
+ :key="item + i"
504
514
  :label="item"
505
515
  :value="item"
506
516
  >
@@ -511,18 +521,18 @@
511
521
  </el-select>
512
522
  </el-row>
513
523
  <template v-if="viewingMode === 'Annotation' && userInformation">
514
- <el-row class="backgroundText">Drawing Type*</el-row>
524
+ <el-row class="backgroundText">Drawn By*</el-row>
515
525
  <el-row class="backgroundControl">
516
526
  <el-select
517
527
  :teleported="false"
518
- v-model="drawingType"
528
+ v-model="drawnType"
519
529
  placeholder="Select"
520
530
  class="select-box"
521
531
  popper-class="flatmap_dropdown"
522
- @change="setDrawingType"
532
+ @change="setDrawnType"
523
533
  >
524
534
  <el-option
525
- v-for="item in drawingTypes"
535
+ v-for="item in drawnTypes"
526
536
  :key="item"
527
537
  :label="item"
528
538
  :value="item"
@@ -533,18 +543,18 @@
533
543
  </el-option>
534
544
  </el-select>
535
545
  </el-row>
536
- <el-row class="backgroundText">Participation Type*</el-row>
546
+ <el-row class="backgroundText">Annotated By*</el-row>
537
547
  <el-row class="backgroundControl">
538
548
  <el-select
539
549
  :teleported="false"
540
- v-model="participationType"
550
+ v-model="annotatedType"
541
551
  placeholder="Select"
542
552
  class="select-box"
543
553
  popper-class="flatmap_dropdown"
544
- @change="setParticipationType"
554
+ @change="setAnnotatedType"
545
555
  >
546
556
  <el-option
547
- v-for="item in participationTypes"
557
+ v-for="item in annotatedTypes"
548
558
  :key="item"
549
559
  :label="item"
550
560
  :value="item"
@@ -556,13 +566,13 @@
556
566
  </el-select>
557
567
  </el-row>
558
568
  </template>
559
- <el-row class="backgroundSpacer"></el-row>
560
- <el-row class="backgroundText">Dimension display</el-row>
561
- <el-row class="backgroundControl">
569
+ <el-row class="backgroundSpacer" v-if="displayFlightPathOption"></el-row>
570
+ <el-row class="backgroundText" v-if="displayFlightPathOption">Flight path display</el-row>
571
+ <el-row class="backgroundControl" v-if="displayFlightPathOption">
562
572
  <el-radio-group
563
- v-model="dimensionRadio"
573
+ v-model="flightPath3DRadio"
564
574
  class="flatmap-radio"
565
- @change="setDimension"
575
+ @change="setFlightPath3D"
566
576
  >
567
577
  <el-radio :label="false">2D</el-radio>
568
578
  <el-radio :label="true">3D</el-radio>
@@ -663,53 +673,18 @@
663
673
  :annotationDisplay="viewingMode === 'Annotation'"
664
674
  @annotation="commitAnnotationEvent"
665
675
  />
666
- <el-dialog
667
- v-model="relevanceDisplay"
668
- width="200"
669
- :modal="false"
670
- :show-close="false"
671
- :lock-scroll="false"
672
- :close-on-click-modal="false"
673
- :close-on-press-escape="false"
674
- draggable
675
- >
676
- <template #header v-if="inDrawing">
677
- <span class="dialog-title">Finalise drawing</span>
678
- </template>
679
- <template #header v-else>
680
- <el-button type="primary" plain @click="displayRelevanceDialog(false)">
681
- Close
682
- </el-button>
683
- </template>
684
- <el-row v-if="inDrawing">
685
- <el-col :span="13">
686
- <el-button type="primary" plain @click="confirmDrawnFeature">
687
- Confirm
688
- </el-button>
689
- </el-col>
690
- <el-col :span="11">
691
- <el-button type="primary" plain @click="cancelDrawnFeature">
692
- Cancel
693
- </el-button>
694
- </el-col>
695
- </el-row>
696
- <el-row v-if="hasRelevance">
697
- <el-col :span="20">
698
- <b><span>Related Features</span></b>
699
- </el-col>
700
- <el-col :span="4">
701
- <el-icon><el-icon-circle-close @click="closePopup()"/></el-icon>
702
- </el-col>
703
- <el-card
704
- shadow="hover"
705
- v-for="(value, key) in relevanceEntry"
706
- :key="key"
707
- @click="displayRelevanceTooltip(value)"
708
- >
709
- <span>{{ key }}</span>
710
- </el-card>
711
- </el-row>
712
- </el-dialog>
676
+ <ConnectionDialog
677
+ class="connection-dialog"
678
+ v-show="connectionDisplay"
679
+ :entry="connectionEntry"
680
+ :drawing="inDrawing"
681
+ :connection="connection"
682
+ @display="connectionDialogPopup"
683
+ @confirm="confirmDrawnFeature"
684
+ @cancel="cancelDrawnFeature"
685
+ @popup="closePopup"
686
+ @tooltip="displayConnectedFeatureTooltip"
687
+ />
713
688
  </div>
714
689
  </div>
715
690
  </template>
@@ -721,7 +696,6 @@ import {
721
696
  WarningFilled as ElIconWarningFilled,
722
697
  ArrowDown as ElIconArrowDown,
723
698
  ArrowLeft as ElIconArrowLeft,
724
- CircleClose as ElIconCircleClose,
725
699
  } from '@element-plus/icons-vue'
726
700
  import Tooltip from './Tooltip.vue'
727
701
  import SelectionsGroup from './SelectionsGroup.vue'
@@ -746,14 +720,64 @@ import {
746
720
  } from '../services/flatmapQueries.js'
747
721
  import yellowstar from '../icons/yellowstar'
748
722
  import ResizeSensor from 'css-element-queries/src/ResizeSensor'
749
- import * as flatmap from 'customised-viewer'
723
+ import * as flatmap from '@abi-software/flatmap-viewer'
750
724
  import { AnnotationService } from '@abi-software/sparc-annotation'
725
+ import ConnectionDialog from './ConnectionDialog.vue'
726
+ import { mapState } from 'pinia'
727
+ import { useMainStore } from '@/store/index'
728
+
729
+ /**
730
+ * @param scopeElement Draggable scope area (Optional)
731
+ * @param dragElement Draggable element
732
+ */
733
+ const draggable = (scopeElement, dragElement) => {
734
+ let startX, startY, clickX, clickY, posX, posY
735
+ // reset position in case previous pupped up dialog is dragged
736
+ dragElement.style.left = ''
737
+ dragElement.style.top = ''
738
+ // const scopeRect = scopeElement.getBoundingClientRect()
739
+ // const dragRect = dragElement.getBoundingClientRect()
740
+
741
+ dragElement.addEventListener('mousedown', (e) => {
742
+ e.preventDefault();
743
+ startX = dragElement.offsetLeft
744
+ startY = dragElement.offsetTop
745
+ clickX = e.clientX
746
+ clickY = e.clientY
747
+
748
+ dragElement.addEventListener('mousemove', drag, false);
749
+ document.addEventListener('mouseup', () => {
750
+ dragElement.removeEventListener('mousemove', drag, false);
751
+ }, false);
752
+ }, false);
753
+
754
+ function drag(e) {
755
+ e.preventDefault();
756
+ posX = startX - (clickX - e.clientX)
757
+ posY = startY - (clickY - e.clientY)
758
+ // if (
759
+ // (posX > scopeRect.left && ((posX + dragRect.width) < scopeRect.right)) &&
760
+ // (posY > scopeRect.top && ((posY + dragRect.height) < scopeRect.bottom))
761
+ // ) {
762
+ dragElement.style.left = `${posX}px`;
763
+ dragElement.style.top = `${posY}px`;
764
+ // } else {
765
+ // if (posX <= scopeRect.left) {
766
+ // dragElement.style.left = '0px';
767
+ // } else if (posX + dragRect.width >= scopeRect.right) {
768
+ // dragElement.style.left = `${scopeRect.right - dragRect.width}px`;
769
+ // }
770
+ // if (posY <= scopeRect.top) {
771
+ // dragElement.style.top = '0px';
772
+ // } else if (posY + dragRect.height >= scopeRect.bottom) {
773
+ // dragElement.style.top = `${scopeRect.bottom - dragRect.height}px`;
774
+ // }
775
+ // }
776
+ }
777
+ }
751
778
 
752
779
  const centroid = (geometry) => {
753
- let featureGeometry = {
754
- lng: 0,
755
- lat: 0,
756
- }
780
+ let featureGeometry = { lng: 0, lat: 0, }
757
781
  let coordinates
758
782
  if (geometry.type === "Polygon") {
759
783
  coordinates = geometry.coordinates[0]
@@ -834,6 +858,9 @@ const createUnfilledTooltipData = function () {
834
858
  }
835
859
  }
836
860
 
861
+ /**
862
+ * A vue component of the flatmap viewer.
863
+ */
837
864
  export default {
838
865
  name: 'FlatmapVuer',
839
866
  components: {
@@ -868,125 +895,96 @@ export default {
868
895
  return { annotator }
869
896
  },
870
897
  methods: {
871
- displayRelevanceTooltip: function (value) {
872
- if (this.mapImp) {
873
- this.checkAndCreatePopups(value)
874
- }
875
- },
876
898
  // This should be called when create is confirmed or cancelled
877
- initialiseDraw: function () {
899
+ initialiseDrawing: function () {
878
900
  this.inDrawing = false
879
- this.relevanceDisplay = false
880
- this.relevanceEntry = {}
901
+ this.initialiseDialog()
881
902
  this.activeDrawTool = undefined
882
903
  this.createdEvent = undefined
883
- this.setActiveDrawIcon()
884
904
  },
885
905
  cancelDrawnFeature: function () {
886
906
  if (this.createdEvent) {
887
- // For 'created' callback
888
907
  this.closePopup()
889
908
  this.annotationEntry = {
890
909
  ...this.createdEvent.feature,
891
- resourceId: this.serverUUID,
910
+ resourceId: this.serverURL,
892
911
  }
893
912
  this.rollbackAnnotationEvent()
894
- this.initialiseDraw()
913
+ this.initialiseDrawing()
914
+ }
915
+ },
916
+ displayConnectedFeatureTooltip: function (id) {
917
+ if (this.mapImp) {
918
+ const data = this.mapImp.featureProperties(id)
919
+ this.checkAndCreatePopups({ feature: data })
895
920
  }
896
921
  },
897
922
  confirmDrawnFeature: function () {
898
923
  if (this.createdEvent) {
899
924
  this.checkAndCreatePopups(this.createdEvent)
900
- // Add relevance if exist to annotationEntry
901
- // Relevance will only be added in creating draw annotation
902
- // And will not be updated if move drawn annotation
903
- if (Object.keys(this.relevanceEntry).length > 0) {
904
- this.annotationEntry.feature.relevance = this.relevanceEntry
925
+ // Add connection if exist to annotationEntry
926
+ // Connection will only be added in creating new drawn feature annotation
927
+ // And will not be updated if move drawn features
928
+ if (Object.keys(this.connectionEntry).length > 0) {
929
+ this.annotationEntry.feature.connection = this.connectionEntry
905
930
  }
906
- this.initialiseDraw()
931
+ this.initialiseDrawing()
907
932
  }
908
933
  },
909
- displayRelevanceDialog: function (display) {
910
- // Change back to the initial window size
911
- // For a better view of the relevance popup
912
- if (display) this.resetView()
913
- this.closePopup()
914
- // Used when check exist drawn annotation relevance
915
- if (
916
- !this.createdEvent && !this.currentDrawnFeature &&
917
- Object.keys(this.relevanceEntry).length === 0
918
- ) {
919
- // Reset drawn event
920
- this.drawnEvent()
921
- } else if (this.createdEvent || Object.keys(this.relevanceEntry).length > 0) {
922
- this.relevanceDisplay = display
923
- if (!display && this.activeDrawMode === 'Delete') this.relevanceEntry = {}
924
- }
925
- },
926
- setActiveDrawIcon: function () {
927
- let mclass
928
- if (document.querySelector('.toolSelected')) {
929
- this.drawingTypes.map((t) => {
930
- if (t !== 'All' && t !== 'None') {
931
- document.querySelector(`.draw${t}`).classList.remove('toolSelected');
932
- }
933
- })
934
- this.drawModes.map((m) => {
935
- if (m === 'Delete') mclass = '.drawTrash'
936
- else if (m === 'Edit') mclass = '.comment'
937
- document.querySelector(mclass).classList.remove('toolSelected');
938
- })
939
- }
940
- if (this.activeDrawTool) {
941
- document.querySelector(`.draw${this.activeDrawTool}`).classList.add('toolSelected');
942
- } else if (this.activeDrawMode) {
943
- if (this.activeDrawMode === 'Delete') mclass = '.drawTrash'
944
- else if (this.activeDrawMode === 'Edit') mclass = '.comment'
945
- document.querySelector(mclass).classList.add('toolSelected');
934
+ initialiseDialog: function () {
935
+ this.connectionDisplay = false
936
+ this.connectionEntry = {}
937
+ },
938
+ connectionDialogPopup: function () {
939
+ const inactive = this.$el.querySelector('.drawConnection').classList.contains('inactive')
940
+ // disable click popup if icon inactive or in drawing
941
+ if (!inactive && !this.inDrawing) {
942
+ this.closePopup()
943
+ this.connectionDisplay = !this.connectionDisplay
946
944
  }
947
945
  },
948
- drawnEvent: function (type = undefined) {
946
+ drawingEvent: function (type) {
949
947
  this.closePopup()
950
- if (!type) {
951
- this.activeDrawTool = undefined
952
- this.activeDrawMode = undefined
953
- this.inDrawing = false
954
- } else if (this.drawingTypes.includes(type)) {
955
- if (this.activeDrawMode) {
956
- document.querySelector('.mapbox-gl-draw_trash').click()
957
- this.activeDrawMode = undefined
958
- }
948
+ // disable mode icon click if any tool is active
949
+ if (this.drawnTypes.includes(type) && !this.activeDrawMode && !this.connectionDisplay) {
959
950
  if (type === 'Point') {
960
- document.querySelector('.mapbox-gl-draw_point').click()
961
- this.activeDrawTool = this.activeDrawTool === 'Point' ? undefined : 'Point'
951
+ const point = this.$el.querySelector('.mapbox-gl-draw_point')
952
+ this.$el.querySelector('.mapbox-gl-draw_point').click()
953
+ this.activeDrawTool = point.classList.contains('active') ? 'Point' : undefined
962
954
  } else if (type === 'LineString') {
963
- document.querySelector('.mapbox-gl-draw_line').click()
964
- this.activeDrawTool = this.activeDrawTool === 'LineString' ? undefined : 'LineString'
955
+ const line = this.$el.querySelector('.mapbox-gl-draw_line')
956
+ this.$el.querySelector('.mapbox-gl-draw_line').click()
957
+ this.activeDrawTool = line.classList.contains('active') ? 'LineString' : undefined
965
958
  } else if (type === 'Polygon') {
966
- document.querySelector('.mapbox-gl-draw_polygon').click()
967
- this.activeDrawTool = this.activeDrawTool === 'Polygon' ? undefined : 'Polygon'
968
- }
969
- } else if (this.drawModes.includes(type)) {
970
- if (this.activeDrawTool) {
971
- document.querySelector('.mapbox-gl-draw_trash').click()
972
- this.activeDrawTool = undefined
959
+ const polygon = this.$el.querySelector('.mapbox-gl-draw_polygon')
960
+ this.$el.querySelector('.mapbox-gl-draw_polygon').click()
961
+ this.activeDrawTool = polygon.classList.contains('active') ? 'Polygon' : undefined
973
962
  }
963
+ // disable tool icon click if any mode is on
964
+ } else if (this.drawModes.includes(type) && !this.activeDrawTool) {
974
965
  if (type === 'Delete') {
975
- if (this.currentDrawnFeature && !this.activeDrawMode) {
966
+ if (
967
+ this.currentDrawnFeature &&
968
+ // For either no mode is on or edit is on
969
+ (!this.activeDrawMode || this.activeDrawMode === 'Edit')
970
+ ) {
976
971
  // Force simple_select a feature for delete event
977
972
  this.doubleClickedFeature = false
978
973
  this.changeAnnotationDrawMode({
979
974
  mode: 'simple_select',
980
975
  options: { featureIds: [this.currentDrawnFeature.id] }
981
976
  })
982
- this.trashAnnotationFeature()
977
+ this.deleteOrEditAnnotationFeature()
983
978
  }
984
979
  this.activeDrawMode = this.activeDrawMode === 'Delete' ? undefined : 'Delete'
980
+ // clear currentDrawnFeature when quit delete mode
981
+ if (!this.activeDrawMode) {
982
+ this.currentDrawnFeature = undefined
983
+ }
985
984
  } else if (type === 'Edit') {
986
985
  this.activeDrawMode = this.activeDrawMode === 'Edit' ? undefined : 'Edit'
987
986
  }
988
987
  }
989
- this.setActiveDrawIcon()
990
988
  },
991
989
  changeAnnotationDrawMode: function (mode) {
992
990
  if (this.mapImp) {
@@ -1003,17 +1001,21 @@ export default {
1003
1001
  this.mapImp.clearAnnotationFeature()
1004
1002
  }
1005
1003
  },
1006
- trashAnnotationFeature: function () {
1004
+ deleteOrEditAnnotationFeature: function () {
1007
1005
  if (this.mapImp) {
1008
- this.mapImp.trashAnnotationFeature()
1006
+ // Fire the 'trash' button
1007
+ // Not only use to remove features
1008
+ // 'simple_select' for DELETE and 'direct_select' for EDIT
1009
+ this.mapImp.removeAnnotationFeature()
1009
1010
  }
1010
1011
  },
1011
1012
  rollbackAnnotationEvent: function () {
1012
- if (this.mapImp) {
1013
- // For 'updated' and 'deleted' callback
1014
- if (this.drawnAnnotationEvent.includes(this.annotationEntry.type)) {
1015
- this.mapImp.rollbackAnnotationEvent(this.annotationEntry)
1016
- }
1013
+ // For 'updated' and 'deleted' callback
1014
+ if (
1015
+ this.mapImp &&
1016
+ this.drawnAnnotationEvent.includes(this.annotationEntry.type)
1017
+ ) {
1018
+ this.mapImp.rollbackAnnotationEvent(this.annotationEntry)
1017
1019
  }
1018
1020
  },
1019
1021
  commitAnnotationEvent: function (annotation) {
@@ -1024,14 +1026,23 @@ export default {
1024
1026
  annotation
1025
1027
  ) {
1026
1028
  this.annotationSubmitted = true
1027
- if (this.annotationEntry.type === 'deleted') this.closePopup()
1028
1029
  this.mapImp.commitAnnotationEvent(this.annotationEntry)
1030
+ if (this.annotationEntry.type === 'deleted') {
1031
+ this.closePopup()
1032
+ } else {
1033
+ // Use to update 'this.drawnAnnotationFeatures' when created or updated
1034
+ this.addAnnotationFeature()
1035
+ }
1029
1036
  }
1030
1037
  },
1031
1038
  setFeatureAnnotated: function () {
1032
1039
  if (this.mapImp) {
1033
- this.annotator.annotatedItemIds(this.serverUUID)
1040
+ this.annotator.annotatedItemIds(this.userToken, this.serverURL)
1034
1041
  .then((annotatedItemIds) => {
1042
+ if ('resource' in annotatedItemIds) {
1043
+ // The annotator has `resource` and `items` fields
1044
+ annotatedItemIds = annotatedItemIds.items
1045
+ }
1035
1046
  for (const id of annotatedItemIds) {
1036
1047
  this.mapImp.setFeatureAnnotated(id)
1037
1048
  }
@@ -1043,39 +1054,48 @@ export default {
1043
1054
  },
1044
1055
  addAnnotationFeature: function () {
1045
1056
  if (this.mapImp) {
1046
- this.clearAnnotationFeature()
1047
- if (this.drawingType !== 'None') {
1048
- this.annotator.drawnFeatures(this.serverUUID)
1057
+ if (!this.annotationSubmitted) this.clearAnnotationFeature()
1058
+ if (this.drawnType !== 'None') {
1059
+ if (!this.annotationSubmitted) this.loading = true
1060
+ this.annotator.drawnFeatures(this.userToken, this.serverURL)
1049
1061
  .then((drawnFeatures) => {
1062
+ if ('resource' in drawnFeatures) {
1063
+ // The annotator has `resource` and `features` fields
1064
+ drawnFeatures = drawnFeatures.features
1065
+ }
1050
1066
  // Use to switch the displayed feature type
1051
- if (this.drawingType !== 'All') {
1067
+ if (this.drawnType !== 'All tools') {
1052
1068
  drawnFeatures = drawnFeatures.filter((feature) => {
1053
- return feature.geometry.type === this.drawingType
1069
+ return feature.geometry.type === this.drawnType
1054
1070
  })
1055
1071
  }
1056
1072
  this.drawnAnnotationFeatures = drawnFeatures
1057
- for (const feature of drawnFeatures) {
1058
- if (this.participationType !== 'All') {
1059
- this.annotator
1060
- .itemAnnotations(this.serverUUID, feature.id)
1061
- .then((value) => {
1062
- let participated = value.filter((v) => {
1063
- return (
1064
- v.creator.name === this.userInformation.name &&
1065
- v.creator.email === this.userInformation.email
1066
- )
1067
- }).length > 0
1068
- if (
1069
- (this.participationType === 'Participated' && participated) ||
1070
- (this.participationType === 'Not participated' && !participated)
1071
- ) {
1072
- this.mapImp.addAnnotationFeature(feature)
1073
- }
1074
- })
1075
- .catch((reason) => {
1076
- console.log(reason) // Error!
1077
- })
1078
- } else this.mapImp.addAnnotationFeature(feature)
1073
+ this.loading = false
1074
+ // No need to call 'addAnnotationFeature' when a new feature created
1075
+ if (!this.annotationSubmitted) {
1076
+ for (const feature of drawnFeatures) {
1077
+ if (this.annotatedType !== 'Anyone') {
1078
+ this.annotator
1079
+ .itemAnnotations(this.userToken, this.serverURL, feature.id)
1080
+ .then((value) => {
1081
+ let participated = value.filter((v) => {
1082
+ return (
1083
+ v.creator.name === this.userInformation.name &&
1084
+ v.creator.email === this.userInformation.email
1085
+ )
1086
+ }).length > 0
1087
+ if (
1088
+ (this.annotatedType === 'Me' && participated) ||
1089
+ (this.annotatedType === 'Others' && !participated)
1090
+ ) {
1091
+ this.mapImp.addAnnotationFeature(feature)
1092
+ }
1093
+ })
1094
+ .catch((reason) => {
1095
+ console.log(reason) // Error!
1096
+ })
1097
+ } else this.mapImp.addAnnotationFeature(feature)
1098
+ }
1079
1099
  }
1080
1100
  })
1081
1101
  .catch((reason) => {
@@ -1089,27 +1109,36 @@ export default {
1089
1109
  // Control the show/hide of the drawn annotations
1090
1110
  this.mapImp.showAnnotator(flag)
1091
1111
  // Hide default toolbar, we will use customised SVG icons instead
1092
- document.querySelector('.maplibregl-ctrl-group').style.display = 'none'
1112
+ this.$el.querySelector('.maplibregl-ctrl-group').style.display = 'none'
1093
1113
  }
1094
1114
  },
1095
- setDrawingType: function (flag) {
1096
- this.drawingType = flag
1115
+ setDrawnType: function (flag) {
1116
+ this.drawnType = flag
1097
1117
  if (this.mapImp) {
1098
1118
  this.addAnnotationFeature()
1099
1119
  }
1100
1120
  },
1101
- setParticipationType: function (flag) {
1102
- this.participationType = flag
1121
+ setAnnotatedType: function (flag) {
1122
+ this.annotatedType = flag
1103
1123
  if (this.mapImp) {
1104
1124
  this.addAnnotationFeature()
1105
1125
  }
1106
1126
  },
1107
- setDimension: function (flag) {
1108
- this.dimensionRadio = flag
1127
+ /**
1128
+ * @vuese
1129
+ * Function to switch from 2D to 3D
1130
+ * @arg flag
1131
+ */
1132
+ setFlightPath3D: function (flag) {
1133
+ this.flightPath3DRadio = flag
1109
1134
  if (this.mapImp) {
1110
- this.mapImp.enable3dPaths(flag)
1135
+ this.mapImp.enableFlightPaths(flag)
1111
1136
  }
1112
1137
  },
1138
+ /**
1139
+ * @vuese
1140
+ * Function to view the latest map (example when you are on legacy map).
1141
+ */
1113
1142
  viewLatestMap: function () {
1114
1143
  let biologicalSex = this.biologicalSex ? this.biologicalSex : undefined
1115
1144
  //Human requires special handling
@@ -1121,14 +1150,28 @@ export default {
1121
1150
  biologicalSex,
1122
1151
  viewport: this.mapImp.getState(),
1123
1152
  }
1153
+ /**
1154
+ * The event emitted by ``viewLatestMap`` method.
1155
+ */
1124
1156
  this.$emit('view-latest-map', state)
1125
1157
  },
1158
+ /**
1159
+ * @vuese
1160
+ * Function to change the background colour of the map
1161
+ * by providing the ``colour``.
1162
+ * @arg colour
1163
+ */
1126
1164
  backgroundChangeCallback: function (colour) {
1127
1165
  this.currentBackground = colour
1128
1166
  if (this.mapImp) {
1129
1167
  this.mapImp.setBackgroundColour(this.currentBackground, 1)
1130
1168
  }
1131
1169
  },
1170
+ /**
1171
+ * @vuese
1172
+ * Function to process a list of a FC flatmap's systems.
1173
+ * @arg systems
1174
+ */
1132
1175
  processSystems: function (systems) {
1133
1176
  this.systems.length = 0
1134
1177
  if (systems && systems.length > 0) {
@@ -1148,6 +1191,13 @@ export default {
1148
1191
  this.systems.push(data)
1149
1192
  }
1150
1193
  },
1194
+ /**
1195
+ * @vuese
1196
+ * Function to add taxon identifiers into the taxon connectivity array,
1197
+ * by retrieving their corresponding labels using the flatmap API.
1198
+ * @arg flatmapAPI,
1199
+ * @arg taxonIdentifiers
1200
+ */
1151
1201
  processTaxon: function (flatmapAPI, taxonIdentifiers) {
1152
1202
  this.taxonConnectivity.length = 0
1153
1203
  taxonIdentifiers.forEach((taxon) => {
@@ -1157,11 +1207,18 @@ export default {
1157
1207
  })
1158
1208
  })
1159
1209
  },
1210
+ /**
1211
+ * @vuese
1212
+ * Function to show or hide the display of the bottom-left drawer container.
1213
+ */
1160
1214
  toggleDrawer: function () {
1161
1215
  this.drawerOpen = !this.drawerOpen
1162
1216
  },
1163
1217
  /**
1218
+ * @vuese
1164
1219
  * Function to toggle colour/greyscale of organs.
1220
+ * The parameter ``flag`` is a boolean, ``true`` (colour) and ``false`` (greyscale).
1221
+ * @arg flag
1165
1222
  */
1166
1223
  setColour: function (flag) {
1167
1224
  this.colourRadio = flag
@@ -1170,7 +1227,10 @@ export default {
1170
1227
  }
1171
1228
  },
1172
1229
  /**
1230
+ * @vuese
1173
1231
  * Function to toggle outlines f organs.
1232
+ * The parameter ``flag`` is a boolean, ``true`` to show outlines, ``false`` to hide outlines.
1233
+ * @arg flag
1174
1234
  */
1175
1235
  setOutlines: function (flag) {
1176
1236
  this.outlineRadio = flag
@@ -1179,6 +1239,7 @@ export default {
1179
1239
  }
1180
1240
  },
1181
1241
  /**
1242
+ * @vuese
1182
1243
  * Function to toggle paths to default.
1183
1244
  * Also called when the associated button is pressed.
1184
1245
  */
@@ -1203,6 +1264,7 @@ export default {
1203
1264
  }
1204
1265
  },
1205
1266
  /**
1267
+ * @vuese
1206
1268
  * Function to zoom in.
1207
1269
  * Also called when the associated button is pressed.
1208
1270
  */
@@ -1212,6 +1274,7 @@ export default {
1212
1274
  }
1213
1275
  },
1214
1276
  /**
1277
+ * @vuese
1215
1278
  * Function to zoom out.
1216
1279
  * Also called when the associated button is pressed.
1217
1280
  */
@@ -1220,16 +1283,34 @@ export default {
1220
1283
  this.mapImp.zoomOut()
1221
1284
  }
1222
1285
  },
1286
+ /**
1287
+ * @vuese
1288
+ * Function to show or hide centrelines and nodes.
1289
+ * The parameter ``payload`` is an object with a boolean property, ``value``,
1290
+ * ``payload.value = true/false``.
1291
+ * @arg payload
1292
+ */
1223
1293
  centreLinesSelected: function (payload) {
1224
1294
  if (this.mapImp) {
1225
1295
  this.mapImp.enableCentrelines(payload.value)
1226
1296
  }
1227
1297
  },
1298
+ /**
1299
+ * // Currently not in use
1300
+ * Function to show or hide paths valid in SCKAN
1301
+ * by providing ``{key, value}`` pair in ``payload``.
1302
+ * @arg payload
1303
+ */
1228
1304
  sckanSelected: function (payload) {
1229
1305
  if (this.mapImp) {
1230
1306
  this.mapImp.enableSckanPath(payload.key, payload.value)
1231
1307
  }
1232
1308
  },
1309
+ /**
1310
+ * // Currently not in use
1311
+ * Function to show or hide all paths valid in SCKAN.
1312
+ * @arg payload
1313
+ */
1233
1314
  checkAllSCKAN: function (payload) {
1234
1315
  if (this.mapImp) {
1235
1316
  payload.keys.forEach((key) =>
@@ -1237,6 +1318,12 @@ export default {
1237
1318
  )
1238
1319
  }
1239
1320
  },
1321
+ /**
1322
+ * @vuese
1323
+ * Function to highlight the connected paths
1324
+ * by providing path model identifier, ``pathId``.
1325
+ * @arg pathId
1326
+ */
1240
1327
  highlightConnectedPaths: function (payload) {
1241
1328
  if (this.mapImp) {
1242
1329
  let paths = [...this.mapImp.pathModelNodes(payload)]
@@ -1253,11 +1340,23 @@ export default {
1253
1340
  this.mapImp.zoomToFeatures(toHighlight, { noZoomIn: true })
1254
1341
  }
1255
1342
  },
1343
+ /**
1344
+ * @vuese
1345
+ * Function to enable/disable (show/hide) the system
1346
+ * by providing ``kay, value`` ``payload`` object ``{systemId, true/false}``.
1347
+ * @arg payload
1348
+ */
1256
1349
  systemSelected: function (payload) {
1257
1350
  if (this.mapImp) {
1258
1351
  this.mapImp.enableSystem(payload.key, payload.value)
1259
1352
  }
1260
1353
  },
1354
+ /**
1355
+ * @vuese
1356
+ * Function to enable/disable (show/hide) all systems
1357
+ * by providing ``flag`` (true/false).
1358
+ * @arg flag
1359
+ */
1261
1360
  checkAllSystems: function (flag) {
1262
1361
  if (this.mapImp) {
1263
1362
  this.systems[0].children.forEach((key) =>
@@ -1265,14 +1364,31 @@ export default {
1265
1364
  )
1266
1365
  }
1267
1366
  },
1367
+ /**
1368
+ * @vuese
1369
+ * Function to display features with annotation matching the provided term.
1370
+ * @arg models
1371
+ */
1268
1372
  ftuSelected: function (models) {
1269
1373
  this.searchAndShowResult(models, true)
1270
1374
  },
1375
+ /**
1376
+ * @vuese
1377
+ * Function to show or hide the layer
1378
+ * by providing ``{layerId, true/false}`` in ``payload``.
1379
+ * @arg payload
1380
+ */
1271
1381
  layersSelected: function (payload) {
1272
1382
  if (this.mapImp) {
1273
1383
  this.mapImp.enableLayer(payload.key, payload.value)
1274
1384
  }
1275
1385
  },
1386
+ /**
1387
+ * @vuese
1388
+ * Function to show or hide all layers
1389
+ * by providing ``payload`` with ``payload.keys`` array and ``payload.value`` flag.
1390
+ * @arg payload
1391
+ */
1276
1392
  checkAllLayers: function (payload) {
1277
1393
  if (this.mapImp) {
1278
1394
  payload.keys.forEach((key) =>
@@ -1280,11 +1396,23 @@ export default {
1280
1396
  )
1281
1397
  }
1282
1398
  },
1399
+ /**
1400
+ * @vuese
1401
+ * Function to show or hide connectivity features observed in particular species
1402
+ * by providing ``{taxonId, true/false}`` in ``payload.key, payload.value``.
1403
+ * @arg payload
1404
+ */
1283
1405
  taxonsSelected: function (payload) {
1284
1406
  if (this.mapImp) {
1285
1407
  this.mapImp.enableConnectivityByTaxonIds(payload.key, payload.value)
1286
1408
  }
1287
1409
  },
1410
+ /**
1411
+ * @vuese
1412
+ * Function to show or hide connectivity features observed in particular species
1413
+ * by providing ``payload`` with ``payload.keys`` array and ``payload.value`` flag.
1414
+ * @arg payload
1415
+ */
1288
1416
  checkAllTaxons: function (payload) {
1289
1417
  if (this.mapImp) {
1290
1418
  payload.keys.forEach((key) =>
@@ -1292,11 +1420,23 @@ export default {
1292
1420
  )
1293
1421
  }
1294
1422
  },
1423
+ /**
1424
+ * @vuese
1425
+ * Function to hide or show paths of a given type
1426
+ * by providing ``{pathType, true/false}`` in ``payload.key, payload.value``.
1427
+ * @arg payload
1428
+ */
1295
1429
  pathwaysSelected: function (payload) {
1296
1430
  if (this.mapImp) {
1297
1431
  this.mapImp.enablePath(payload.key, payload.value)
1298
1432
  }
1299
1433
  },
1434
+ /**
1435
+ * @vuese
1436
+ * Function to hide or show paths of a given type
1437
+ * by providing ``payload`` with ``payload.keys`` array and ``payload.value`` flag.
1438
+ * @arg payload
1439
+ */
1300
1440
  checkAllPathways: function (payload) {
1301
1441
  if (this.mapImp) {
1302
1442
  payload.keys.forEach((key) =>
@@ -1304,9 +1444,21 @@ export default {
1304
1444
  )
1305
1445
  }
1306
1446
  },
1447
+ /**
1448
+ * @vuese
1449
+ * Function to generate callbacks as a result of panning/zooming the map.
1450
+ * ``flag`` (boolean) - generate callbacks when ``true``, otherwise disable them.
1451
+ * @arg flag
1452
+ */
1307
1453
  enablePanZoomEvents: function (flag) {
1308
1454
  this.mapImp.enablePanZoomEvents(flag)
1309
1455
  },
1456
+ /**
1457
+ * @vuese
1458
+ * A callback function, invoked when events occur with the map.
1459
+ * The first parameter gives the type of event, the second provides details about the event.
1460
+ * _(This is the ``callback`` function from ``MapManager.loadMap()``)_.
1461
+ */
1310
1462
  eventCallback: function () {
1311
1463
  return (eventType, data, ...args) => {
1312
1464
  if (eventType === 'annotation') {
@@ -1318,17 +1470,21 @@ export default {
1318
1470
  // Popup closed will trigger aborted event
1319
1471
  if (data.type === 'aborted') {
1320
1472
  // Rollback drawing when no new annotation submitted
1321
- if (!this.annotationSubmitted) {
1322
- this.rollbackAnnotationEvent()
1323
- }
1473
+ if (!this.annotationSubmitted) this.rollbackAnnotationEvent()
1474
+ else this.annotationSubmitted = false
1324
1475
  } else if (data.type === 'modeChanged') {
1325
1476
  // 'modeChanged' event is before 'created' event
1326
1477
  if (data.feature.mode.startsWith('draw_')) {
1327
1478
  // Reset data entry for every draw
1328
- this.relevanceEntry = {}
1479
+ this.initialiseDialog()
1329
1480
  this.inDrawing = true
1330
1481
  } else if (data.feature.mode === 'simple_select' && this.inDrawing) {
1331
- this.displayRelevanceDialog(true)
1482
+ if (this.createdEvent) {
1483
+ this.connectionDisplay = true
1484
+ } else {
1485
+ // Reset if a invalid draw
1486
+ this.initialiseDrawing()
1487
+ }
1332
1488
  } else if (data.feature.mode === 'direct_select') {
1333
1489
  this.doubleClickedFeature = true
1334
1490
  }
@@ -1338,8 +1494,18 @@ export default {
1338
1494
  undefined :
1339
1495
  data.feature.features[0]
1340
1496
  payload.feature.feature = this.currentDrawnFeature
1341
- // For exist drawn annotation features
1342
- this.checkAndCreateDrawnFeaturePopups(payload)
1497
+ if (!this.inDrawing) {
1498
+ this.initialiseDialog()
1499
+ // For exist drawn annotation features
1500
+ if (this.currentDrawnFeature) {
1501
+ let feature = this.drawnAnnotationFeatures
1502
+ .filter((feature) => feature.id === this.currentDrawnFeature.id)[0]
1503
+ if (feature && feature.connection) {
1504
+ this.connectionEntry = feature.connection
1505
+ }
1506
+ this.drawModeEvent(payload)
1507
+ }
1508
+ }
1343
1509
  } else {
1344
1510
  if (data.type === 'created' || data.type === 'updated') {
1345
1511
  if (data.type === 'updated' && data.feature.action) {
@@ -1364,6 +1530,15 @@ export default {
1364
1530
  const resource = [data.models]
1365
1531
  const taxonomy = this.entry
1366
1532
  const biologicalSex = this.biologicalSex
1533
+ let taxons = undefined
1534
+ if (data.taxons) {
1535
+ // check if data.taxons is string or array
1536
+ if (typeof data.taxons !== 'object') {
1537
+ taxons = JSON.parse(data.taxons)
1538
+ } else {
1539
+ taxons = data.taxons
1540
+ }
1541
+ }
1367
1542
  const payload = {
1368
1543
  dataset: data.dataset,
1369
1544
  biologicalSex: biologicalSex,
@@ -1373,16 +1548,25 @@ export default {
1373
1548
  feature: data,
1374
1549
  userData: args,
1375
1550
  eventType: eventType,
1376
- provenanceTaxonomy: data.taxons
1377
- ? JSON.parse(data.taxons)
1378
- : undefined,
1551
+ provenanceTaxonomy: taxons,
1379
1552
  }
1380
1553
  if (eventType === 'click') {
1381
1554
  if (this.viewingMode === 'Network Discovery') {
1382
1555
  this.highlightConnectedPaths([data.models])
1383
1556
  } else {
1384
1557
  this.currentActive = data.models ? data.models : ''
1385
- this.allocateRelevance(payload)
1558
+ // Stop adding features if dialog displayed
1559
+ if (this.inDrawing && !this.connectionDisplay) {
1560
+ // Only clicked connection data will be added
1561
+ let nodeLabel = data.label ? data.label : `Feature ${data.id}`
1562
+ // only the linestring will have connection at the current stage
1563
+ if (nodeLabel && this.activeDrawTool === 'LineString') {
1564
+ this.connectionEntry[data.featureId] = Object.assign({label: nodeLabel},
1565
+ Object.fromEntries(
1566
+ Object.entries(data)
1567
+ .filter(([key]) => ['featureId', 'models'].includes(key))))
1568
+ }
1569
+ }
1386
1570
  }
1387
1571
  } else if (
1388
1572
  eventType === 'mouseenter' &&
@@ -1407,67 +1591,112 @@ export default {
1407
1591
  }
1408
1592
  }
1409
1593
  },
1410
- allocateRelevance: function (data = undefined) {
1411
- if (data && data.feature) {
1412
- // Only clicked relevance data will be added
1413
- let relevance = data.feature.models ?
1414
- data.feature.models :
1415
- data.feature.featureId
1416
- if (
1417
- relevance &&
1418
- this.inDrawing &&
1419
- // Currently only draw line will show relevance
1420
- this.activeDrawTool === 'LineString' &&
1421
- !(relevance in this.relevanceEntry)
1422
- ) {
1423
- this.relevanceEntry[relevance] = data
1594
+ // for dialog popup
1595
+ dialogCssHacks: function () {
1596
+ this.$nextTick(() => {
1597
+ const dialog = this.$el.querySelector('.connection-dialog')
1598
+ draggable(this.$el, dialog)
1599
+ // dialog popup at the click position
1600
+ // slightly change x or y if close to boundary
1601
+ let posX, posY
1602
+ const containerRect = this.$el.getBoundingClientRect()
1603
+ const dialogRect = dialog.getBoundingClientRect()
1604
+ if (this.dialogPosition.x > containerRect.width / 2) {
1605
+ posX = this.dialogPosition.x - dialogRect.width
1606
+ } else {
1607
+ posX = this.dialogPosition.x
1424
1608
  }
1425
- } else if (this.currentDrawnFeature && this.drawnAnnotationFeatures) {
1426
- let relevance = this.drawnAnnotationFeatures
1427
- .filter((feature) => {
1428
- return feature.id === this.currentDrawnFeature.id
1429
- })[0].relevance
1430
- if (relevance) this.relevanceEntry = relevance
1431
- }
1432
- },
1433
- checkAndCreateDrawnFeaturePopups: function (data) {
1434
- if (!this.inDrawing) {
1435
- this.relevanceEntry = {}
1436
- if (this.currentDrawnFeature) {
1437
- this.allocateRelevance()
1438
- if (this.activeDrawMode) {
1439
- // double click fires 'updated' callback
1440
- if (this.doubleClickedFeature) {
1441
- if (data.feature.feature.geometry.type !== 'Point') {
1442
- // show tooltip and enter edit mode
1443
- this.changeAnnotationDrawMode({
1444
- mode: 'direct_select',
1445
- options: { featureId: data.feature.feature.id }
1446
- })
1447
- this.trashAnnotationFeature()
1448
- }
1449
- this.doubleClickedFeature = false
1450
- } else { // single click
1451
- if (this.activeDrawMode === 'Delete') {
1452
- this.changeAnnotationDrawMode({
1453
- mode: 'simple_select',
1454
- options: { featureIds: [data.feature.feature.id] }
1455
- })
1456
- this.trashAnnotationFeature()
1457
- }
1458
- }
1609
+ if (this.dialogPosition.y > containerRect.height / 2) {
1610
+ posY = this.dialogPosition.y - dialogRect.height
1611
+ } else {
1612
+ posY = this.dialogPosition.y
1613
+ }
1614
+ dialog.style.transform =
1615
+ `translate(${posX - this.dialogPosition.offsetX}px, ${posY - this.dialogPosition.offsetY}px)`
1616
+ })
1617
+ },
1618
+ drawIconCssHacks: function () {
1619
+ // set tool/mode icon status
1620
+ if (this.$el.querySelector('.iconSelected') || !this.connectionDisplay) {
1621
+ this.drawnTypes.map((t) => {
1622
+ const dtype = this.$el.querySelector(`.draw${t}`)
1623
+ if (dtype) {
1624
+ dtype.classList.remove('iconSelected');
1625
+ dtype.classList.remove('inactive');
1626
+ }
1627
+ })
1628
+ this.drawModes.map((m) => {
1629
+ this.$el.querySelector(`.draw${m}`).classList.remove('iconSelected');
1630
+ this.$el.querySelector(`.draw${m}`).classList.remove('inactive');
1631
+ })
1632
+ }
1633
+ if (this.activeDrawTool) {
1634
+ this.$el.querySelector(`.draw${this.activeDrawTool}`).classList.add('iconSelected');
1635
+ this.drawModes.map((m) => {
1636
+ this.$el.querySelector(`.draw${m}`).classList.add('inactive');
1637
+ })
1638
+ } else if (this.activeDrawMode || this.connectionDisplay) {
1639
+ if (this.activeDrawMode) {
1640
+ this.$el.querySelector(`.draw${this.activeDrawMode}`).classList.add('iconSelected');
1641
+ }
1642
+ this.drawnTypes.map((t) => {
1643
+ const dtype = this.$el.querySelector(`.draw${t}`)
1644
+ if (dtype) dtype.classList.add('inactive');
1645
+ })
1646
+ }
1647
+ },
1648
+ // Fire either update or delete event
1649
+ drawModeEvent: function (data) {
1650
+ if (this.activeDrawMode) {
1651
+ // double click fires 'updated' callback
1652
+ if (this.doubleClickedFeature) {
1653
+ if (data.feature.feature.geometry.type !== 'Point') {
1654
+ // show tooltip and enter edit mode
1655
+ this.changeAnnotationDrawMode({
1656
+ mode: 'direct_select',
1657
+ options: { featureId: data.feature.feature.id }
1658
+ })
1659
+ this.deleteOrEditAnnotationFeature()
1660
+ }
1661
+ this.doubleClickedFeature = false
1662
+ } else {
1663
+ // single click fires delete
1664
+ if (this.activeDrawMode === 'Delete') {
1665
+ this.changeAnnotationDrawMode({
1666
+ mode: 'simple_select',
1667
+ options: { featureIds: [data.feature.feature.id] }
1668
+ })
1669
+ this.deleteOrEditAnnotationFeature()
1459
1670
  }
1460
1671
  }
1461
1672
  }
1462
1673
  },
1463
1674
  // checkNeuronClicked shows a neuron path pop up if a path was recently clicked
1675
+ createConnectivityBody: function () {
1676
+ if (Object.keys(this.connectionEntry).length > 0) {
1677
+ const features = Object.values(this.connectionEntry)
1678
+ const body = {
1679
+ type: 'connectivity',
1680
+ source: features[0],
1681
+ target: features[features.length - 1],
1682
+ intermediates: features.slice(1, -1),
1683
+ }
1684
+ this.annotationEntry.body = body
1685
+ }
1686
+ },
1687
+ /**
1688
+ * @vuese
1689
+ * Function to create/display tooltips from the provided ``data``.
1690
+ * _checkNeuronClicked shows a neuron path pop up if a path was recently clicked._
1691
+ * @arg data
1692
+ */
1464
1693
  checkAndCreatePopups: async function (data) {
1465
1694
  // Call flatmap database to get the connection data
1466
1695
  if (this.viewingMode === 'Annotation') {
1467
1696
  if (data.feature) {
1468
1697
  this.annotationEntry = {
1469
1698
  ...data.feature,
1470
- resourceId: this.serverUUID,
1699
+ resourceId: this.serverURL,
1471
1700
  }
1472
1701
  if (data.feature.featureId && data.feature.models) {
1473
1702
  this.displayTooltip(data.feature.models)
@@ -1475,14 +1704,21 @@ export default {
1475
1704
  if (this.inDrawing || this.activeDrawMode) {
1476
1705
  this.annotationSubmitted = false
1477
1706
  this.annotationEntry.featureId = data.feature.feature.id
1478
- let featureGeometry = centroid(data.feature.feature.geometry)
1479
- this.displayTooltip(data.feature.feature.id, featureGeometry)
1707
+ this.createConnectivityBody()
1708
+ this.displayTooltip(
1709
+ data.feature.feature.id,
1710
+ centroid(data.feature.feature.geometry)
1711
+ )
1480
1712
  } else {
1481
- // Not allowed to update feature if edit mode not on
1713
+ // Not allowed to update feature if not on edit mode
1482
1714
  if (data.feature.type === 'updated') {
1483
1715
  this.rollbackAnnotationEvent()
1484
1716
  }
1485
1717
  }
1718
+ // Hide dialog when updated or deleted event is fired and tooltip is displayed
1719
+ if (data.feature.type === 'updated' || data.feature.type === 'deleted') {
1720
+ this.initialiseDialog()
1721
+ }
1486
1722
  }
1487
1723
  } else {
1488
1724
  this.annotation = {}
@@ -1503,6 +1739,9 @@ export default {
1503
1739
  }
1504
1740
  }
1505
1741
  },
1742
+ /**
1743
+ * A hack to remove flatmap tooltips while popup is open
1744
+ */
1506
1745
  popUpCssHacks: function () {
1507
1746
  // Below is a hack to remove flatmap tooltips while popup is open
1508
1747
  let ftooltip = document.querySelector('.flatmap-tooltip-popup')
@@ -1518,18 +1757,34 @@ export default {
1518
1757
  let cbutton = document.querySelector('.maplibregl-popup-close-button')
1519
1758
  if (cbutton) cbutton.click()
1520
1759
  },
1760
+ /**
1761
+ * @vuese
1762
+ * Function to close tooltip.
1763
+ */
1521
1764
  closeTooltip: function () {
1522
1765
  this.$refs.tooltip.$el.style.display = 'none'
1523
1766
  document.querySelectorAll('.maplibregl-popup').forEach((item) => {
1524
1767
  item.style.display = 'none'
1525
1768
  })
1526
1769
  },
1770
+ /**
1771
+ * @vuese
1772
+ * Function to create tooltip from Neuron Curation ``data``.
1773
+ * @arg data
1774
+ */
1527
1775
  createTooltipFromNeuronCuration: async function (data) {
1528
1776
  this.tooltipEntry = await this.flatmapQueries.createTooltipData(data)
1529
1777
  this.displayTooltip(data.resource[0])
1530
1778
  },
1531
- // Keeping this as an API
1779
+ /**
1780
+ * @vuese
1781
+ * Function to show popup on map.
1782
+ * @arg featureId,
1783
+ * @arg node,
1784
+ * @arg options
1785
+ */
1532
1786
  showPopup: function (featureId, node, options) {
1787
+ // Keeping this as an API
1533
1788
  let myOptions = options
1534
1789
  if (this.mapImp) {
1535
1790
  if (myOptions) {
@@ -1540,11 +1795,22 @@ export default {
1540
1795
  this.mapImp.showPopup(featureId, node, myOptions)
1541
1796
  }
1542
1797
  },
1798
+ /**
1799
+ * @vuese
1800
+ * Function to show marker popup.
1801
+ * @arg featureId,
1802
+ * @arg node,
1803
+ * @arg options
1804
+ */
1543
1805
  showMarkerPopup: function (featureId, node, options) {
1544
1806
  if (this.mapImp) {
1545
1807
  this.mapImp.showMarkerPopup(featureId, node, options)
1546
1808
  }
1547
1809
  },
1810
+ /**
1811
+ * @vuese
1812
+ * Function to close minimap.
1813
+ */
1548
1814
  closeMinimap: function () {
1549
1815
  let minimapEl = this.$refs.flatmapContainer.querySelector(
1550
1816
  '.maplibregl-ctrl-minimap'
@@ -1559,6 +1825,9 @@ export default {
1559
1825
  }
1560
1826
  this.minimapSmall = !this.minimapSmall
1561
1827
  },
1828
+ /**
1829
+ * Function to add resize button to minimap.
1830
+ */
1562
1831
  addResizeButtonToMinimap: function () {
1563
1832
  let minimapEl = this.$refs.flatmapContainer.querySelector(
1564
1833
  '.maplibregl-ctrl-minimap'
@@ -1573,6 +1842,12 @@ export default {
1573
1842
  this.minimapResizeShow = true
1574
1843
  }
1575
1844
  },
1845
+ /**
1846
+ * @vuese
1847
+ * Function to set help mode
1848
+ * by providing flag ``helpMode`` (true/false).
1849
+ * @arg helpMode
1850
+ */
1576
1851
  setHelpMode: function (helpMode) {
1577
1852
  if (helpMode) {
1578
1853
  this.inHelp = true
@@ -1588,6 +1863,12 @@ export default {
1588
1863
  this.closeFlatmapHelpPopup()
1589
1864
  }
1590
1865
  },
1866
+ /**
1867
+ * @vuese
1868
+ * Function to show tooltip
1869
+ * by providing ``tooltipNumber``.
1870
+ * @arg tooltipNumber
1871
+ */
1591
1872
  showToolitip: function (tooltipNumber) {
1592
1873
  if (!this.inHelp) {
1593
1874
  clearTimeout(this.tooltipWait[tooltipNumber])
@@ -1596,6 +1877,12 @@ export default {
1596
1877
  }, 500)
1597
1878
  }
1598
1879
  },
1880
+ /**
1881
+ * @vuese
1882
+ * Function to hide tooltip
1883
+ * by providing ``tooltipNumber``.
1884
+ * @arg tooltipNumber
1885
+ */
1599
1886
  hideToolitip: function (tooltipNumber) {
1600
1887
  if (!this.inHelp) {
1601
1888
  clearTimeout(this.tooltipWait[tooltipNumber])
@@ -1604,6 +1891,12 @@ export default {
1604
1891
  }, 500)
1605
1892
  }
1606
1893
  },
1894
+ /**
1895
+ * @vuese
1896
+ * Function to display tooltip
1897
+ * by providing featureId (``feature``).
1898
+ * @arg feature
1899
+ */
1607
1900
  displayTooltip: function (feature, geometry = undefined) {
1608
1901
  this.tooltipDisplay = true
1609
1902
  let featureId = undefined
@@ -1618,10 +1911,16 @@ export default {
1618
1911
  }
1619
1912
  }
1620
1913
  if (!this.disableUI) {
1621
- this.mapImp.showPopup(featureId, this.$refs.tooltip.$el, options)
1914
+ this.$nextTick(() => {
1915
+ this.mapImp.showPopup(featureId, this.$refs.tooltip.$el, options)
1916
+ this.popUpCssHacks()
1917
+ })
1622
1918
  }
1623
- this.popUpCssHacks()
1624
1919
  },
1920
+ /**
1921
+ * @vuese
1922
+ * Function to open Flatmap Help Popup.
1923
+ */
1625
1924
  openFlatmapHelpPopup: function () {
1626
1925
  if (this.mapImp) {
1627
1926
  let heartId = this.mapImp.modelFeatureIds('UBERON:0000948')
@@ -1634,6 +1933,10 @@ export default {
1634
1933
  }
1635
1934
  }
1636
1935
  },
1936
+ /**
1937
+ * @vuese
1938
+ * Function to close Flatmap Help Popup.
1939
+ */
1637
1940
  closeFlatmapHelpPopup: function () {
1638
1941
  this.$el
1639
1942
  .querySelectorAll('.maplibregl-popup-close-button')
@@ -1641,6 +1944,10 @@ export default {
1641
1944
  item.click()
1642
1945
  })
1643
1946
  },
1947
+ /**
1948
+ * @vuese
1949
+ * Function to get annotation labels.
1950
+ */
1644
1951
  getLabels: function () {
1645
1952
  let labels = []
1646
1953
  if (this.mapImp) {
@@ -1651,6 +1958,10 @@ export default {
1651
1958
  return Array.from(new Set(labels))
1652
1959
  }
1653
1960
  },
1961
+ /**
1962
+ * @vuese
1963
+ * Function to get the state (object) of the map.
1964
+ */
1654
1965
  getState: function () {
1655
1966
  if (this.mapImp) {
1656
1967
  let state = {
@@ -1666,6 +1977,11 @@ export default {
1666
1977
  }
1667
1978
  return undefined
1668
1979
  },
1980
+ /**
1981
+ * @vuese
1982
+ * Function to set state (object) for the map.
1983
+ * @arg state
1984
+ */
1669
1985
  setState: function (state) {
1670
1986
  if (state) {
1671
1987
  if (
@@ -1683,12 +1999,40 @@ export default {
1683
1999
  this.setStateRequired = false
1684
2000
  }
1685
2001
  },
2002
+ /**
2003
+ * @vuese
2004
+ * Function to restore map's state
2005
+ * from the ``state`` provided.
2006
+ * @arg state
2007
+ */
1686
2008
  restoreMapState: function (state) {
1687
2009
  if (state) {
1688
2010
  if (state.viewport) this.mapImp.setState(state.viewport)
1689
2011
  if (state.searchTerm) this.searchAndShowResult(state.searchTerm, true)
1690
2012
  }
1691
2013
  },
2014
+ /**
2015
+ * @vuese
2016
+ * Function to show flight path option
2017
+ * (3D option)
2018
+ * based on the map version (currently 1.6 and above).
2019
+ * @arg mapVersion
2020
+ */
2021
+ setFlightPathInfo: function (mapVersion) {
2022
+ const mapVersionForFlightPath = 1.6
2023
+ if (mapVersion === mapVersionForFlightPath || mapVersion > mapVersionForFlightPath) {
2024
+ // Show flight path option UI
2025
+ this.displayFlightPathOption = true
2026
+ // Show 2D as default on FC type
2027
+ this.setFlightPath3D(false)
2028
+ }
2029
+ },
2030
+ /**
2031
+ * @vuese
2032
+ * Function to create Flatmap
2033
+ * by providing the ``state``.
2034
+ * @arg state
2035
+ */
1692
2036
  createFlatmap: function (state) {
1693
2037
  if (!this.mapImp && !this.loading) {
1694
2038
  this.loading = true
@@ -1746,18 +2090,16 @@ export default {
1746
2090
  //fullscreenControl: false,
1747
2091
  //annotatable: false,
1748
2092
  //debug: true,
1749
- featureInfo: this.featureInfo,
1750
- 'min-zoom': this.minZoom,
1751
- layerControl: true,
1752
- pathControls: true,
1753
- searchable: this.searchable,
2093
+ minZoom: this.minZoom,
1754
2094
  tooltips: this.tooltips,
1755
2095
  minimap: minimap,
1756
2096
  }
1757
2097
  )
1758
2098
  promise1.then((returnedObject) => {
1759
2099
  this.mapImp = returnedObject
1760
- this.serverUUID = this.mapImp.getIdentifier().uuid
2100
+ this.serverURL = this.mapImp.makeServerUrl('').slice(0, -1)
2101
+ let mapVersion = this.mapImp.details.version
2102
+ this.setFlightPathInfo(mapVersion)
1761
2103
  this.onFlatmapReady()
1762
2104
  if (this._stateToBeSet) this.restoreMapState(this._stateToBeSet)
1763
2105
  else {
@@ -1773,6 +2115,10 @@ export default {
1773
2115
  this.restoreMapState(this._stateToBeSet)
1774
2116
  }
1775
2117
  },
2118
+ /**
2119
+ * @vuese
2120
+ * Function to compute path controls maximum height.
2121
+ */
1776
2122
  computePathControlsMaximumHeight() {
1777
2123
  const elem = this.$refs.display
1778
2124
  if (elem) {
@@ -1783,6 +2129,10 @@ export default {
1783
2129
  this.pathwaysMaxHeight = height - 170
1784
2130
  }
1785
2131
  },
2132
+ /**
2133
+ * @vuese
2134
+ * Function to resize the map.
2135
+ */
1786
2136
  mapResize: function () {
1787
2137
  try {
1788
2138
  this.computePathControlsMaximumHeight()
@@ -1797,6 +2147,10 @@ export default {
1797
2147
  console.error('Map resize error')
1798
2148
  }
1799
2149
  },
2150
+ /**
2151
+ * @vuese
2152
+ * This function is used for functions that need to run immediately after the flatmap is loaded.
2153
+ */
1800
2154
  onFlatmapReady: function () {
1801
2155
  // onFlatmapReady is used for functions that need to run immediately after the flatmap is loaded
1802
2156
  this.sensor = new ResizeSensor(this.$refs.display, this.mapResize)
@@ -1816,17 +2170,36 @@ export default {
1816
2170
  this.computePathControlsMaximumHeight()
1817
2171
  this.drawerOpen = true
1818
2172
  this.mapResize()
2173
+ /**
2174
+ * This is ``onFlatmapReady`` event.
2175
+ * @arg ``this`` (Component Vue Instance)
2176
+ */
1819
2177
  this.$emit('ready', this)
1820
2178
  },
2179
+ /**
2180
+ * @vuese
2181
+ * Function to show or hide the minimap
2182
+ * by providing ``flag`` (boolean) value.
2183
+ * @arg flag
2184
+ */
1821
2185
  showMinimap: function (flag) {
1822
2186
  if (this.mapImp) this.mapImp.showMinimap(flag)
1823
2187
  },
2188
+ /**
2189
+ * @vuese
2190
+ * Function to show or hide the pathways drawer
2191
+ * by providing ``flag`` (boolean) value.
2192
+ * @arg flag
2193
+ */
1824
2194
  showPathwaysDrawer: function (flag) {
1825
2195
  this.drawerOpen = flag
1826
2196
  },
1827
2197
  /**
2198
+ * @vuese
1828
2199
  * Function to display features with annotation matching the provided term,
1829
2200
  * with the option to display the label using displayLabel flag.
2201
+ * @arg term,
2202
+ * @arg displayLabel
1830
2203
  */
1831
2204
  searchAndShowResult: function (term, displayLabel) {
1832
2205
  if (this.mapImp) {
@@ -1866,7 +2239,10 @@ export default {
1866
2239
  return false
1867
2240
  },
1868
2241
  /**
1869
- * Get the list of suggested terms
2242
+ * @vuese
2243
+ * Function to show search suggestions
2244
+ * from the ``term`` provided.
2245
+ * @arg term
1870
2246
  */
1871
2247
  searchSuggestions: function (term) {
1872
2248
  if (this.mapImp) return this.mapImp.search(term)
@@ -1874,48 +2250,66 @@ export default {
1874
2250
  },
1875
2251
  },
1876
2252
  props: {
1877
- entry: String,
2253
+ /**
2254
+ * The taxon identifier of the species represented by the map.
2255
+ */
2256
+ entry: {
2257
+ type: String,
2258
+ required: true,
2259
+ },
2260
+ /**
2261
+ * The unique ``uuid`` of the flatmap.
2262
+ * If given then this exact map will be loaded,
2263
+ * overriding ``taxon`` and ``biologicalSex``.
2264
+ */
1878
2265
  uuid: String,
2266
+ /**
2267
+ * The biological sex of the species represented by the map.
2268
+ * This is specified as metadata in the map's source file.
2269
+ */
1879
2270
  biologicalSex: {
1880
2271
  type: String,
1881
2272
  default: '',
1882
2273
  },
1883
- featureInfo: {
1884
- type: Boolean,
1885
- default: false,
1886
- },
2274
+ /**
2275
+ * The minimum zoom level of the map.
2276
+ */
1887
2277
  minZoom: {
1888
2278
  type: Number,
1889
2279
  default: 4,
1890
2280
  },
1891
- pathControls: {
1892
- type: Boolean,
1893
- default: false,
1894
- },
1895
- searchable: {
1896
- type: Boolean,
1897
- default: false,
1898
- },
1899
- layerControl: {
1900
- type: Boolean,
1901
- default: false,
1902
- },
2281
+ /**
2282
+ * The option to add another feature label _(`FeatureSmallSymbolLayer`)_
2283
+ * when this `tooltips` is set to `false`.
2284
+ */
1903
2285
  tooltips: {
1904
2286
  type: Boolean,
1905
2287
  default: true,
1906
2288
  },
2289
+ /**
2290
+ * The option to show tooltips for help mode.
2291
+ */
1907
2292
  helpMode: {
1908
2293
  type: Boolean,
1909
2294
  default: false,
1910
2295
  },
2296
+ /**
2297
+ * The option to create map on component mounted.
2298
+ */
1911
2299
  renderAtMounted: {
1912
2300
  type: Boolean,
1913
2301
  default: true,
1914
2302
  },
2303
+ /**
2304
+ * The option to display minimap at the top-right corner of the map.
2305
+ */
1915
2306
  displayMinimap: {
1916
2307
  type: Boolean,
1917
2308
  default: false,
1918
2309
  },
2310
+ /**
2311
+ * The option to show warning. Example for legacy or beta maps.
2312
+ */
1919
2313
  displayWarning: {
1920
2314
  type: Boolean,
1921
2315
  default: false,
@@ -1928,8 +2322,28 @@ export default {
1928
2322
  type: Boolean,
1929
2323
  default: false,
1930
2324
  },
2325
+ /**
2326
+ * The data to show different map options.
2327
+ * Available at the bottom-left corner ("Open new map" tooltip).
2328
+ */
1931
2329
  openMapOptions: {
1932
2330
  type: Array,
2331
+ /**
2332
+ * ```[
2333
+ {
2334
+ display: 'Open AC Map',
2335
+ key: 'AC',
2336
+ },
2337
+ {
2338
+ display: 'Open FC Map',
2339
+ key: 'FC',
2340
+ },
2341
+ {
2342
+ display: 'Open 3D Human Map',
2343
+ key: '3D',
2344
+ },
2345
+ ]```
2346
+ */
1933
2347
  default: function () {
1934
2348
  return [
1935
2349
  {
@@ -1947,14 +2361,24 @@ export default {
1947
2361
  ]
1948
2362
  },
1949
2363
  },
2364
+ /**
2365
+ * The option to show star in legend area.
2366
+ */
1950
2367
  showStarInLegend: {
1951
2368
  type: Boolean,
1952
2369
  default: false,
1953
2370
  },
2371
+ /**
2372
+ * Flag to determine whether this is legacy map or not.
2373
+ * ``displayWarning`` should be shown for legacy map.
2374
+ */
1954
2375
  isLegacy: {
1955
2376
  type: Boolean,
1956
2377
  default: false,
1957
2378
  },
2379
+ /**
2380
+ * The option to show the latest changes.
2381
+ */
1958
2382
  displayLatestChanges: {
1959
2383
  type: Boolean,
1960
2384
  default: false,
@@ -1973,6 +2397,9 @@ export default {
1973
2397
  type: String,
1974
2398
  default: 'https://mapcore-demo.org/current/flatmap/v3/',
1975
2399
  },
2400
+ /**
2401
+ * Specify the endpoint of the SPARC API.
2402
+ */
1976
2403
  sparcAPI: {
1977
2404
  type: String,
1978
2405
  default: 'https://api.sparc.science/',
@@ -1989,7 +2416,8 @@ export default {
1989
2416
  return {
1990
2417
  flatmapAPI: this.flatmapAPI,
1991
2418
  sparcAPI: this.sparcAPI,
1992
- $annotator: this.annotator
2419
+ $annotator: this.annotator,
2420
+ userApiKey: this.userToken
1993
2421
  }
1994
2422
  },
1995
2423
  data: function () {
@@ -1998,8 +2426,8 @@ export default {
1998
2426
  //tooltip display has to be set to false until it is rendered
1999
2427
  //for the first time, otherwise it may display an arrow at a
2000
2428
  //undesired location.
2001
- tooltipDisplay: true,
2002
- serverUUID: undefined,
2429
+ tooltipDisplay: false,
2430
+ serverURL: undefined,
2003
2431
  layers: [],
2004
2432
  pathways: [],
2005
2433
  sckanDisplay: [
@@ -2046,7 +2474,8 @@ export default {
2046
2474
  tooltipEntry: createUnfilledTooltipData(),
2047
2475
  connectivityTooltipVisible: false,
2048
2476
  drawerOpen: false,
2049
- dimensionRadio: false,
2477
+ flightPath3DRadio: false,
2478
+ displayFlightPathOption: false,
2050
2479
  colourRadio: true,
2051
2480
  outlinesRadio: true,
2052
2481
  minimapResizeShow: false,
@@ -2056,10 +2485,10 @@ export default {
2056
2485
  currentHover: '',
2057
2486
  viewingMode: 'Exploration',
2058
2487
  viewingModes: ['Annotation', 'Exploration', 'Network Discovery'],
2059
- drawingType: 'All',
2060
- drawingTypes: ['All', 'Point', 'LineString', 'Polygon', 'None'],
2061
- participationType: 'All',
2062
- participationTypes: ['All', 'Participated', 'Not participated'],
2488
+ drawnType: 'All tools',
2489
+ drawnTypes: ['All tools', 'Point', 'LineString', 'Polygon', 'None'],
2490
+ annotatedType: 'Anyone',
2491
+ annotatedTypes: ['Anyone', 'Me', 'Others'],
2063
2492
  openMapRef: undefined,
2064
2493
  backgroundIconRef: undefined,
2065
2494
  annotator: undefined,
@@ -2069,49 +2498,114 @@ export default {
2069
2498
  createdEvent: undefined,
2070
2499
  annotationSubmitted: false,
2071
2500
  inDrawing: false,
2072
- relevanceDisplay: false,
2073
- relevanceEntry: {},
2074
- drawnAnnotationFeatures: undefined, // Store all exist drawn annotations
2501
+ connectionDisplay: false,
2502
+ connectionEntry: {},
2503
+ drawnAnnotationFeatures: undefined, // Store all exist drawn features
2075
2504
  doubleClickedFeature: false,
2076
2505
  activeDrawMode: undefined,
2077
2506
  drawModes: ['Delete', 'Edit'],
2507
+ dialogPosition: {
2508
+ offsetX: 0,
2509
+ offsetY: 0,
2510
+ x: undefined,
2511
+ y: undefined
2512
+ }
2078
2513
  }
2079
2514
  },
2080
2515
  computed: {
2081
- hasRelevance: function () {
2082
- return Object.keys(this.relevanceEntry).length > 0
2516
+ ...mapState(useMainStore, ['userToken']),
2517
+ connection: function () {
2518
+ return Object.keys(this.connectionEntry).length > 0
2083
2519
  }
2084
2520
  },
2085
2521
  watch: {
2086
2522
  entry: function () {
2087
2523
  if (!this.state) this.createFlatmap()
2088
2524
  },
2089
- helpMode: function (val) {
2090
- this.setHelpMode(val)
2525
+ helpMode: function (newVal, oldVal) {
2526
+ if (newVal !== oldVal) {
2527
+ this.setHelpMode(val)
2528
+ }
2091
2529
  },
2092
2530
  state: {
2093
- handler: function (state) {
2094
- if (this.mapManager) {
2095
- this.setState(state)
2096
- } else {
2097
- //this component has not been mounted yet
2098
- this.setStateRequired = true
2531
+ handler: function (state, oldVal) {
2532
+ if (state !== oldVal) {
2533
+ if (this.mapManager) {
2534
+ this.setState(state)
2535
+ } else {
2536
+ //this component has not been mounted yet
2537
+ this.setStateRequired = true
2538
+ }
2099
2539
  }
2100
2540
  },
2101
2541
  immediate: true,
2102
2542
  deep: true,
2103
2543
  },
2544
+ activeDrawTool: function () {
2545
+ this.drawIconCssHacks()
2546
+ },
2547
+ activeDrawMode: function () {
2548
+ this.drawIconCssHacks()
2549
+ },
2550
+ /**
2551
+ * hide dialog when connectionEntry is empty
2552
+ */
2553
+ connection: function (value) {
2554
+ const connectionIcon = this.$el.querySelector('.drawConnection')
2555
+ if (!value) {
2556
+ this.connectionDisplay = false
2557
+ connectionIcon.classList.add('inactive')
2558
+ } else {
2559
+ connectionIcon.classList.remove('inactive')
2560
+ }
2561
+ },
2562
+ /**
2563
+ * popup dialog via click icon
2564
+ */
2565
+ connectionDisplay: function (display) {
2566
+ const connectionIcon = this.$el.querySelector('.drawConnection')
2567
+ if (display) {
2568
+ connectionIcon.classList.add('iconSelected')
2569
+ this.dialogCssHacks()
2570
+ } else {
2571
+ connectionIcon.classList.remove('iconSelected')
2572
+ }
2573
+ this.drawIconCssHacks()
2574
+ },
2575
+ /**
2576
+ * Set dialog offset when flatmap annotator used
2577
+ */
2578
+ dialogPosition: {
2579
+ handler: function () {
2580
+ const containerRect = this.$el.getBoundingClientRect()
2581
+ this.dialogPosition.offsetX = containerRect.x
2582
+ this.dialogPosition.offsetY = containerRect.y
2583
+ },
2584
+ deep: true,
2585
+ once: true,
2586
+ },
2104
2587
  viewingMode: function (mode) {
2105
2588
  if (mode === 'Annotation') {
2106
- this.showAnnotator(true)
2107
- this.annotator.authenticate().then((userData) => {
2589
+ this.$el.querySelector('.maplibregl-canvas').addEventListener('click', (e) => {
2590
+ e.preventDefault();
2591
+ this.dialogPosition.x = e.clientX
2592
+ this.dialogPosition.y = e.clientY
2593
+ // use to fix the draw point pop up position issue
2594
+ if (this.activeDrawTool === 'Point') {
2595
+ this.dialogCssHacks()
2596
+ }
2597
+ }, false)
2598
+ this.loading = true
2599
+ this.annotator.authenticate(this.userToken).then((userData) => {
2108
2600
  if (userData.name && userData.email) {
2601
+ this.showAnnotator(true)
2109
2602
  this.userInformation = userData
2110
2603
  this.setFeatureAnnotated()
2111
2604
  if (!this.drawnAnnotationFeatures) {
2112
2605
  this.addAnnotationFeature()
2113
2606
  }
2114
2607
  }
2608
+ this.loading = false
2115
2609
  })
2116
2610
  } else this.showAnnotator(false)
2117
2611
  },
@@ -2197,6 +2691,7 @@ export default {
2197
2691
  position: absolute;
2198
2692
  bottom: 0px;
2199
2693
  transition: all 1s ease;
2694
+ z-index: 8;
2200
2695
  &.open {
2201
2696
  left: 0px;
2202
2697
  }
@@ -2227,6 +2722,8 @@ export default {
2227
2722
  transition: all 1s ease;
2228
2723
  &.open {
2229
2724
  opacity: 1;
2725
+ position: relative;
2726
+ z-index: 2;
2230
2727
  }
2231
2728
  &.close {
2232
2729
  opacity: 0;
@@ -2269,7 +2766,8 @@ export default {
2269
2766
  }
2270
2767
 
2271
2768
  :deep(.maplibregl-popup) {
2272
- max-width: 300px !important;
2769
+ z-index: 10;
2770
+ max-width: 330px !important;
2273
2771
  }
2274
2772
 
2275
2773
  :deep(.flatmap-tooltip-popup) {
@@ -2383,15 +2881,21 @@ export default {
2383
2881
  }
2384
2882
  }
2385
2883
 
2386
- .drawPoint, .drawLineString, .drawPolygon, .drawTrash,
2387
- .connection, .comment, .zoomIn, .zoomOut, .fitWindow {
2388
- padding-left: 8px;
2884
+ .drawPoint, .drawLineString, .drawPolygon,
2885
+ .drawDelete, .drawEdit, .drawConnection,
2886
+ .zoomIn, .zoomOut, .fitWindow {
2887
+ padding: 4px;
2389
2888
  }
2390
2889
 
2391
- .toolSelected {
2890
+ .iconSelected {
2392
2891
  color: var(--el-color-primary-light-5) !important;
2393
2892
  }
2394
2893
 
2894
+ .inactive {
2895
+ color: #DDDDDD !important;
2896
+ cursor: not-allowed !important;
2897
+ }
2898
+
2395
2899
  .yellow-star-legend {
2396
2900
  width: 130px;
2397
2901
  cursor: pointer;
@@ -2401,6 +2905,7 @@ export default {
2401
2905
  bottom: 16px;
2402
2906
  position: absolute;
2403
2907
  transition: all 1s ease;
2908
+ z-index: 10;
2404
2909
  &.open {
2405
2910
  left: 322px;
2406
2911
  }
@@ -2423,6 +2928,10 @@ export default {
2423
2928
  }
2424
2929
  }
2425
2930
 
2931
+ :deep(.background-popper.el-popover.el-popper.h-auto) {
2932
+ height: auto !important;
2933
+ }
2934
+
2426
2935
  :deep(.open-map-popper.el-popover.el-popper) {
2427
2936
  padding-top: 5px;
2428
2937
  padding-bottom: 5px;
@@ -2598,15 +3107,22 @@ export default {
2598
3107
  }
2599
3108
 
2600
3109
  .bottom-draw-control {
3110
+ background-color: var(--el-color-primary-light-9);
3111
+ padding: 4px 4px 2px 4px;
3112
+ border-style: solid;
3113
+ border-color: var(--el-color-primary-light-5);
3114
+ border-radius: 1rem;
2601
3115
  position: absolute;
2602
- right: 40%;
3116
+ right: calc(50vw - 100px);;
2603
3117
  bottom: 16px;
3118
+ z-index: 10;
2604
3119
  }
2605
3120
 
2606
3121
  .bottom-right-control {
2607
3122
  position: absolute;
2608
3123
  right: 16px;
2609
3124
  bottom: 16px;
3125
+ z-index: 10;
2610
3126
  }
2611
3127
 
2612
3128
  :deep(.my-drawer) {
@@ -2793,34 +3309,10 @@ export default {
2793
3309
  }
2794
3310
  }
2795
3311
 
2796
- :deep(.el-dialog) {
2797
- text-align: justify;
2798
- border-radius: 4px;
2799
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
2800
- pointer-events: auto;
2801
- background: #fff;
2802
- border: 1px solid $app-primary-color;
2803
- display: flex;
2804
- flex-direction: column;
3312
+ .connection-dialog {
2805
3313
  position: absolute;
2806
- left: 100px;
2807
- bottom: 0px;
2808
- }
2809
-
2810
- :deep(.el-dialog__body, .el-dialog__header) {
2811
- padding-top: 10px;
2812
- padding-bottom: 10px;
2813
- }
2814
-
2815
- .dialog-title {
2816
- font-size: 18px;
2817
- font-weight: bold;
2818
- color: rgb(131, 0, 191);
2819
- }
2820
-
2821
- :deep(.el-card) {
2822
- --el-card-padding: 12px;
2823
- border: 0;
3314
+ z-index: 10;
3315
+ cursor: move;
2824
3316
  }
2825
3317
  </style>
2826
3318