@abi-software/flatmapvuer 1.12.2 → 1.12.3-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,7 +11,11 @@
11
11
  style="height: 100%; width: 100%; position: relative; overflow-y: none"
12
12
  >
13
13
  <!-- flatmap-display -->
14
- <div style="height: 100%; width: 100%" ref="display" class="flatmap-display"></div>
14
+ <div
15
+ style="height: 100%; width: 100%"
16
+ ref="display"
17
+ class="flatmap-display"
18
+ ></div>
15
19
  <!-- flatmap-error -->
16
20
  <FlatmapError v-if="flatmapError" :flatmapError="flatmapError" />
17
21
 
@@ -25,7 +29,7 @@
25
29
  :visible="hoverVisibilities[7].value"
26
30
  ref="warningPopover"
27
31
  >
28
- <!--
32
+ <!--
29
33
  What magic meaning do the numbers 6, 7, etc have?
30
34
 
31
35
  Please use `const` to assign meaningful names to them...
@@ -59,10 +63,7 @@ Please use `const` to assign meaningful names to them...
59
63
  SCKAN </a
60
64
  >.
61
65
  </p>
62
- <p v-else
63
- @mouseover="showTooltip(7)"
64
- @mouseout="hideTooltip(7)"
65
- >
66
+ <p v-else @mouseover="showTooltip(7)" @mouseout="hideTooltip(7)">
66
67
  This map displays the connectivity of neuron populations.
67
68
  Specifically, those from the primarily rat-based
68
69
  <a
@@ -86,7 +87,9 @@ Please use `const` to assign meaningful names to them...
86
87
  @mouseover="showTooltip(7)"
87
88
  @mouseout="hideTooltip(7)"
88
89
  >
89
- <el-icon v-if="displayWarning || isLegacy"><el-icon-warning-filled /></el-icon>
90
+ <el-icon v-if="displayWarning || isLegacy"
91
+ ><el-icon-warning-filled
92
+ /></el-icon>
90
93
  <template v-if="isLegacy">
91
94
  <span class="warning-text">Legacy Map</span>
92
95
  <div class="latest-map-text" @click="viewLatestMap">
@@ -123,13 +126,13 @@ Please use `const` to assign meaningful names to them...
123
126
  <template #default>
124
127
  <b>Connectivity References</b>
125
128
  <p>
126
- Connectivity references have been improved and available
127
- in various formats.
129
+ Connectivity references have been improved and available in
130
+ various formats.
128
131
  </p>
129
132
  <b>Improved state storing</b>
130
133
  <p>
131
- Current selection and visibility filters are now stored
132
- when creating a permalink.
134
+ Current selection and visibility filters are now stored when
135
+ creating a permalink.
133
136
  </p>
134
137
  </template>
135
138
  </el-popover>
@@ -147,7 +150,11 @@ Please use `const` to assign meaningful names to them...
147
150
  </el-icon>
148
151
 
149
152
  <DrawToolbar
150
- v-if="viewingMode === 'Annotation' && (authorisedUser || offlineAnnotationEnabled) && !disableUI"
153
+ v-if="
154
+ viewingMode === 'Annotation' &&
155
+ (authorisedUser || offlineAnnotationEnabled) &&
156
+ !disableUI
157
+ "
151
158
  :mapCanvas="{
152
159
  containerHTML: this.$el,
153
160
  class: '.maplibregl-canvas',
@@ -166,7 +173,79 @@ Please use `const` to assign meaningful names to them...
166
173
  @hideTooltip="hideTooltip"
167
174
  ref="toolbarPopover"
168
175
  />
169
-
176
+ <!-- <div class="top-left-control" v-if="simulationInfo.length > 0"> -->
177
+ <el-popover
178
+ content="Open simulation protocols"
179
+ v-if="simulationInfo.length > 0"
180
+ placement="right"
181
+ :teleported="false"
182
+ trigger="manual"
183
+ :offset="-18"
184
+ popper-class="flatmap-popper"
185
+ :visible="hoverVisibilities[16].value"
186
+ ref="simulationPopover"
187
+ >
188
+ <template #reference>
189
+ <div
190
+ class="popover-location top"
191
+ :class="{
192
+ open: simulationDrawerOpen,
193
+ close: !simulationDrawerOpen,
194
+ }"
195
+ v-show="!disableUI"
196
+ >
197
+ <div
198
+ class="pathway-container"
199
+ :class="{
200
+ open: simulationDrawerOpen,
201
+ close: !simulationDrawerOpen,
202
+ }"
203
+ v-popover:simulationPopover
204
+ >
205
+ <h4 style="margin-top: 0; margin-bottom: 10px">
206
+ Available Protocols
207
+ </h4>
208
+ <el-select
209
+ v-model="selectedSimulation"
210
+ placeholder="Select a simulation"
211
+ size="default"
212
+ style="width: 100%; margin-bottom: 10px"
213
+ value-key="path"
214
+ >
215
+ <el-option
216
+ v-for="info in simulationInfo"
217
+ :key="info.path"
218
+ :label="getSimulationLabel(info)"
219
+ :value="info"
220
+ />
221
+ </el-select>
222
+ <el-button
223
+ type="primary"
224
+ @click="openSimulation"
225
+ :disabled="!selectedSimulation"
226
+ style="width: 100%"
227
+ >
228
+ Open Simulation
229
+ </el-button>
230
+ </div>
231
+ <div
232
+ @click="simulationDrawerOpen = !simulationDrawerOpen"
233
+ class="drawer-button"
234
+ :class="{
235
+ open: simulationDrawerOpen,
236
+ close: !simulationDrawerOpen,
237
+ }"
238
+ title="Toggle Simulation Panel"
239
+ >
240
+ <!-- Arrow icons for open/close state -->
241
+ <el-icon>
242
+ <el-icon-arrow-left />
243
+ </el-icon>
244
+ </div>
245
+ </div>
246
+ </template>
247
+ </el-popover>
248
+ <!-- </div> -->
170
249
  <div class="bottom-right-control" v-show="!disableUI">
171
250
  <el-popover
172
251
  content="Zoom in"
@@ -185,10 +264,7 @@ Please use `const` to assign meaningful names to them...
185
264
  @mouseover="showTooltip(1)"
186
265
  @mouseout="hideTooltip(1)"
187
266
  >
188
- <map-svg-icon
189
- class="icon-button zoomIn"
190
- icon="zoomIn"
191
- />
267
+ <map-svg-icon class="icon-button zoomIn" icon="zoomIn" />
192
268
  </div>
193
269
  </template>
194
270
  </el-popover>
@@ -196,23 +272,14 @@ Please use `const` to assign meaningful names to them...
196
272
  content="Zoom out"
197
273
  placement="top-end"
198
274
  :teleported="false"
199
- trigger="manual"
275
+ :auto-close="1300"
200
276
  width="70"
201
277
  popper-class="flatmap-popper"
202
- :visible="hoverVisibilities[2].value"
203
278
  ref="zoomOutPopover"
204
279
  >
205
280
  <template #reference>
206
- <div
207
- class="icon-button-container"
208
- @click="zoomOut()"
209
- @mouseover="showTooltip(2)"
210
- @mouseout="hideTooltip(2)"
211
- >
212
- <map-svg-icon
213
- class="icon-button zoomOut"
214
- icon="zoomOut"
215
- />
281
+ <div class="icon-button-container" @click="zoomOut()">
282
+ <map-svg-icon class="icon-button zoomOut" icon="zoomOut" />
216
283
  </div>
217
284
  </template>
218
285
  </el-popover>
@@ -238,16 +305,14 @@ Please use `const` to assign meaningful names to them...
238
305
  @mouseover="showTooltip(3)"
239
306
  @mouseout="hideTooltip(3)"
240
307
  >
241
- <map-svg-icon
242
- class="icon-button fitWindow"
243
- icon="fitWindow"
244
- />
308
+ <map-svg-icon class="icon-button fitWindow" icon="fitWindow" />
245
309
  </div>
246
310
  </template>
247
311
  </el-popover>
248
312
  </div>
249
313
  <el-popover
250
314
  content="Change pathway visibility"
315
+ class="somerandomclass"
251
316
  placement="right"
252
317
  :teleported="false"
253
318
  trigger="manual"
@@ -258,7 +323,7 @@ Please use `const` to assign meaningful names to them...
258
323
  >
259
324
  <template #reference>
260
325
  <div
261
- class="pathway-location"
326
+ class="popover-location bottom"
262
327
  :class="{ open: drawerOpen, close: !drawerOpen }"
263
328
  v-show="!disableUI && requiresDrawer"
264
329
  >
@@ -268,7 +333,7 @@ Please use `const` to assign meaningful names to them...
268
333
  :style="{ 'max-height': pathwaysMaxHeight + 'px' }"
269
334
  v-popover:checkBoxPopover
270
335
  >
271
- <dynamic-legends
336
+ <DynamicLegends
272
337
  v-if="legendEntry.length"
273
338
  identifierKey="prompt"
274
339
  colourKey="colour"
@@ -366,7 +431,11 @@ Please use `const` to assign meaningful names to them...
366
431
  key="pathwaysSelection"
367
432
  />
368
433
  <selections-group
369
- v-if="taxonConnectivity && taxonConnectivity.length > 0 && showPathwayFilter"
434
+ v-if="
435
+ taxonConnectivity &&
436
+ taxonConnectivity.length > 0 &&
437
+ showPathwayFilter
438
+ "
370
439
  title="Studied in"
371
440
  labelKey="label"
372
441
  identifierKey="taxon"
@@ -408,9 +477,7 @@ Please use `const` to assign meaningful names to them...
408
477
  @event open-map
409
478
  @arg {String} `mapOption.key`
410
479
  -->
411
- <el-button type="primary" plain
412
- @click="$emit('open-map', item.key)"
413
- >
480
+ <el-button type="primary" plain @click="$emit('open-map', item.key)">
414
481
  {{ item.display }}
415
482
  </el-button>
416
483
  </el-row>
@@ -428,23 +495,29 @@ Please use `const` to assign meaningful names to them...
428
495
  <div>
429
496
  <el-row class="backgroundText">Viewing Mode</el-row>
430
497
  <el-row class="backgroundControl">
431
- <div style="margin-bottom: 2px;">
432
- <template
433
- v-for="(value, key, index) in viewingModes"
434
- :key="key"
435
- >
436
- <template v-if="key === viewingMode">
437
- <span class="viewing-mode-title"><b >{{ key }}</b></span>
438
- </template>
439
- <template v-else>
440
- <span class="viewing-mode-unselected" @click="changeViewingMode(key)">{{ key }}</span>
441
- </template>
498
+ <div style="margin-bottom: 2px">
499
+ <template v-for="(value, key, index) in viewingModes" :key="key">
500
+ <template v-if="key === viewingMode">
501
+ <span class="viewing-mode-title"
502
+ ><b>{{ key }}</b></span
503
+ >
504
+ </template>
505
+ <template v-else>
506
+ <span
507
+ class="viewing-mode-unselected"
508
+ @click="changeViewingMode(key)"
509
+ >{{ key }}</span
510
+ >
511
+ </template>
442
512
  </template>
443
513
  </div>
444
514
  <el-row class="viewing-mode-description">
445
515
  {{ modeDescription }}
446
516
  </el-row>
447
- <el-row v-if="viewingMode === 'Annotation' && offlineAnnotationEnabled" class="viewing-mode-description">
517
+ <el-row
518
+ v-if="viewingMode === 'Annotation' && offlineAnnotationEnabled"
519
+ class="viewing-mode-description"
520
+ >
448
521
  (Anonymous annotate)
449
522
  </el-row>
450
523
  </el-row>
@@ -472,16 +545,21 @@ Please use `const` to assign meaningful names to them...
472
545
  </el-select>
473
546
  </el-row>
474
547
  </template>
475
- <el-row class="backgroundSpacer" v-if="displayFlightPathOption"></el-row>
476
- <el-row class="backgroundText" v-if="displayFlightPathOption">Flight path display</el-row>
548
+ <el-row
549
+ class="backgroundSpacer"
550
+ v-if="displayFlightPathOption"
551
+ ></el-row>
552
+ <el-row class="backgroundText" v-if="displayFlightPathOption"
553
+ >Flight path display</el-row
554
+ >
477
555
  <el-row class="backgroundControl" v-if="displayFlightPathOption">
478
556
  <el-radio-group
479
557
  v-model="flightPath3DRadio"
480
558
  class="flatmap-radio"
481
559
  @change="setFlightPath3D"
482
560
  >
483
- <el-radio :value="false">2D</el-radio>
484
- <el-radio :value="true">3D</el-radio>
561
+ <el-radio :value="false">2D</el-radio>
562
+ <el-radio :value="true">3D</el-radio>
485
563
  </el-radio-group>
486
564
  </el-row>
487
565
  <el-row class="backgroundSpacer"></el-row>
@@ -571,10 +649,7 @@ Please use `const` to assign meaningful names to them...
571
649
  @mouseover="showTooltip(5)"
572
650
  @mouseout="hideTooltip(5)"
573
651
  >
574
- <map-svg-icon
575
- icon="changeBckgd"
576
- class="icon-button"
577
- />
652
+ <map-svg-icon icon="changeBckgd" class="icon-button" />
578
653
  </div>
579
654
  </template>
580
655
  </el-popover>
@@ -636,24 +711,24 @@ import ResizeSensor from 'css-element-queries/src/ResizeSensor'
636
711
  import flatmap from '../services/flatmapLoader.js'
637
712
  import { AnnotationService } from '@abi-software/sparc-annotation'
638
713
  import { mapState } from 'pinia'
639
- import { useMainStore } from '@/store/index'
714
+ import { useMainStore } from '../store/index.js'
640
715
  import {
641
716
  fetchLabels,
642
717
  DrawToolbar,
643
718
  Tooltip,
644
719
  TreeControls,
645
- getFlatmapFilterOptions
720
+ getFlatmapFilterOptions,
646
721
  } from '@abi-software/map-utilities'
647
722
  import '@abi-software/map-utilities/dist/style.css'
648
723
  import EventBus from './EventBus.js'
649
724
  import FlatmapError from './FlatmapError.vue'
650
725
 
651
- const ERROR_MESSAGE = 'cannot be found on the map.';
726
+ const ERROR_MESSAGE = 'cannot be found on the map.'
652
727
 
653
728
  const centroid = (geometry) => {
654
- let featureGeometry = { lng: 0, lat: 0, }
729
+ let featureGeometry = { lng: 0, lat: 0 }
655
730
  let coordinates
656
- if (geometry.type === "Polygon") {
731
+ if (geometry.type === 'Polygon') {
657
732
  if (geometry.coordinates.length) {
658
733
  coordinates = geometry.coordinates[0]
659
734
  }
@@ -727,6 +802,7 @@ export default {
727
802
  ElIconArrowDown,
728
803
  ElIconArrowLeft,
729
804
  DrawToolbar,
805
+ DynamicLegends,
730
806
  FlatmapError,
731
807
  },
732
808
  beforeCreate: function () {
@@ -738,7 +814,7 @@ export default {
738
814
  setup(props) {
739
815
  let annotator = inject('$annotator')
740
816
  if (!annotator) {
741
- annotator = markRaw(new AnnotationService(`${props.flatmapAPI}annotator`));
817
+ annotator = markRaw(new AnnotationService(`${props.flatmapAPI}annotator`))
742
818
  provide('$annotator', annotator)
743
819
  }
744
820
  return { annotator }
@@ -763,17 +839,17 @@ export default {
763
839
  if (this.mapImp) {
764
840
  if (this.mapImp.contextLost) {
765
841
  if (filter) {
766
- this.filterToRestore = markRaw(JSON.parse(JSON.stringify(filter)));
842
+ this.filterToRestore = markRaw(JSON.parse(JSON.stringify(filter)))
767
843
  } else {
768
- this.filterToRestore = undefined;
844
+ this.filterToRestore = undefined
769
845
  }
770
846
  } else {
771
847
  if (filter) {
772
- this.mapImp.setVisibilityFilter(filter);
848
+ this.mapImp.setVisibilityFilter(filter)
773
849
  } else {
774
- this.mapImp.clearVisibilityFilter();
850
+ this.mapImp.clearVisibilityFilter()
775
851
  }
776
- this.filterToRestore = undefined;
852
+ this.filterToRestore = undefined
777
853
  }
778
854
  }
779
855
  },
@@ -782,7 +858,7 @@ export default {
782
858
  * Function to manually send aborted signal when annotation tooltip popup or sidebar tab closed.
783
859
  */
784
860
  manualAbortedOnClose: function () {
785
- if (this.annotationSidebar) this.$emit("annotation-close")
861
+ if (this.annotationSidebar) this.$emit('annotation-close')
786
862
  this.closeTooltip()
787
863
  this.annotationEventCallback({}, { type: 'aborted' })
788
864
  this.initialiseDrawing()
@@ -803,12 +879,14 @@ export default {
803
879
  */
804
880
  cancelDrawnFeature: function () {
805
881
  if (this.isValidDrawnCreated) {
806
- if (this.annotationSidebar) this.$emit("annotation-close")
882
+ if (this.annotationSidebar) this.$emit('annotation-close')
807
883
  this.closeTooltip()
808
- this.annotationEntry = [{
809
- ...this.drawnCreatedEvent.feature,
810
- resourceId: this.serverURL,
811
- }]
884
+ this.annotationEntry = [
885
+ {
886
+ ...this.drawnCreatedEvent.feature,
887
+ resourceId: this.serverURL,
888
+ },
889
+ ]
812
890
  this.rollbackAnnotationEvent()
813
891
  this.initialiseDrawing()
814
892
  }
@@ -824,7 +902,11 @@ export default {
824
902
  const numericId = Number(value)
825
903
  const featureObject = numericId
826
904
  ? this.mapImp.featureProperties(numericId)
827
- : { feature: this.existDrawnFeatures.find(feature => feature.id === value.trim()) };
905
+ : {
906
+ feature: this.existDrawnFeatures.find(
907
+ (feature) => feature.id === value.trim()
908
+ ),
909
+ }
828
910
  let payload = { feature: featureObject }
829
911
  this.checkAndCreatePopups([payload], false)
830
912
  } else {
@@ -855,7 +937,7 @@ export default {
855
937
  * @arg {String} `name`
856
938
  */
857
939
  toolbarEvent: function (type, name) {
858
- if (this.isValidDrawnCreated) return;
940
+ if (this.isValidDrawnCreated) return
859
941
  this.manualAbortedOnClose()
860
942
  this.doubleClickedFeature = false
861
943
  // Deselect any feature when draw mode/tool is changed
@@ -866,7 +948,10 @@ export default {
866
948
  // Remove any unsubmitted drawn
867
949
  this.cancelDrawnFeature()
868
950
  if (name) {
869
- const tool = name.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`)
951
+ const tool = name.replace(
952
+ /[A-Z]/g,
953
+ (letter) => `_${letter.toLowerCase()}`
954
+ )
870
955
  this.changeAnnotationDrawMode({ mode: `draw${tool}` })
871
956
  }
872
957
  this.activeDrawTool = name
@@ -884,7 +969,7 @@ export default {
884
969
  if (data.feature.feature.geometry.type !== 'Point') {
885
970
  this.changeAnnotationDrawMode({
886
971
  mode: 'direct_select',
887
- options: { featureId: data.feature.feature.id }
972
+ options: { featureId: data.feature.feature.id },
888
973
  })
889
974
  this.modifyAnnotationFeature()
890
975
  }
@@ -893,7 +978,7 @@ export default {
893
978
  } else if (this.activeDrawMode === 'Delete') {
894
979
  this.changeAnnotationDrawMode({
895
980
  mode: 'simple_select',
896
- options: { featureIds: [data.feature.feature.id] }
981
+ options: { featureIds: [data.feature.feature.id] },
897
982
  })
898
983
  this.modifyAnnotationFeature()
899
984
  }
@@ -908,7 +993,9 @@ export default {
908
993
  type: 'connectivity',
909
994
  source: features[0],
910
995
  target: features[features.length - 1],
911
- intermediates: features.filter((f, index) => index !== 0 && index !== features.length - 1),
996
+ intermediates: features.filter(
997
+ (f, index) => index !== 0 && index !== features.length - 1
998
+ ),
912
999
  }
913
1000
  this.annotationEntry[0].body = body
914
1001
  }
@@ -932,12 +1019,12 @@ export default {
932
1019
  this.mapImp.clearAnnotationFeature()
933
1020
  }
934
1021
  },
935
- forceContextLoss: function() {
1022
+ forceContextLoss: function () {
936
1023
  if (this.mapImp && !this.mapImp.contextLost && !this.loading) {
937
1024
  this.mapImp.forceContextLoss()
938
1025
  }
939
1026
  },
940
- forceContextRestore: function() {
1027
+ forceContextRestore: function () {
941
1028
  if (this.mapImp) {
942
1029
  this.flatmapError = null
943
1030
  this.mapImp.forceContextRestore()
@@ -979,22 +1066,35 @@ export default {
979
1066
  commitAnnotationEvent: function (annotation) {
980
1067
  if (this.mapImp) {
981
1068
  if (this.offlineAnnotationEnabled) {
982
- this.offlineAnnotations = JSON.parse(sessionStorage.getItem('anonymous-annotation')) || []
1069
+ this.offlineAnnotations =
1070
+ JSON.parse(sessionStorage.getItem('anonymous-annotation')) || []
983
1071
  this.offlineAnnotations.push(annotation)
984
1072
  if (this.annotationEntry[0].type === 'deleted') {
985
- this.offlineAnnotations = this.offlineAnnotations.filter((offline) => {
986
- return offline.resource !== this.serverURL || offline.item.id !== annotation.item.id
987
- })
1073
+ this.offlineAnnotations = this.offlineAnnotations.filter(
1074
+ (offline) => {
1075
+ return (
1076
+ offline.resource !== this.serverURL ||
1077
+ offline.item.id !== annotation.item.id
1078
+ )
1079
+ }
1080
+ )
988
1081
  }
989
- sessionStorage.setItem('anonymous-annotation', JSON.stringify(this.offlineAnnotations))
1082
+ sessionStorage.setItem(
1083
+ 'anonymous-annotation',
1084
+ JSON.stringify(this.offlineAnnotations)
1085
+ )
990
1086
  }
991
- if (['created', 'updated', 'deleted'].includes(this.annotationEntry[0].type)) {
1087
+ if (
1088
+ ['created', 'updated', 'deleted'].includes(
1089
+ this.annotationEntry[0].type
1090
+ )
1091
+ ) {
992
1092
  this.featureAnnotationSubmitted = true
993
1093
  this.mapImp.commitAnnotationEvent(this.annotationEntry[0])
994
- if (annotation.body.comment === "Position Updated") {
1094
+ if (annotation.body.comment === 'Position Updated') {
995
1095
  this.annotationEntry[0].positionUpdated = false
996
1096
  } else if (this.annotationEntry[0].type === 'deleted') {
997
- if (this.annotationSidebar) this.$emit("annotation-close")
1097
+ if (this.annotationSidebar) this.$emit('annotation-close')
998
1098
  this.closeTooltip()
999
1099
  // Only delete need, keep the annotation tooltip/sidebar open if created/updated
1000
1100
  this.annotationEntry = []
@@ -1009,17 +1109,29 @@ export default {
1009
1109
  * @arg {String} `userId`,
1010
1110
  * @arg {String} `participated`
1011
1111
  */
1012
- fetchAnnotatedItemIds: async function (userId = undefined, participated = undefined) {
1112
+ fetchAnnotatedItemIds: async function (
1113
+ userId = undefined,
1114
+ participated = undefined
1115
+ ) {
1013
1116
  let annotatedItemIds
1014
1117
  if (this.offlineAnnotationEnabled) {
1015
- this.offlineAnnotations = JSON.parse(sessionStorage.getItem('anonymous-annotation')) || []
1016
- annotatedItemIds = this.offlineAnnotations.filter((offline) => {
1017
- return offline.resource === this.serverURL
1018
- }).map(offline => offline.item.id)
1118
+ this.offlineAnnotations =
1119
+ JSON.parse(sessionStorage.getItem('anonymous-annotation')) || []
1120
+ annotatedItemIds = this.offlineAnnotations
1121
+ .filter((offline) => {
1122
+ return offline.resource === this.serverURL
1123
+ })
1124
+ .map((offline) => offline.item.id)
1019
1125
  } else {
1020
- annotatedItemIds = await this.annotator.annotatedItemIds(this.userToken, this.serverURL, userId, participated)
1126
+ annotatedItemIds = await this.annotator.annotatedItemIds(
1127
+ this.userToken,
1128
+ this.serverURL,
1129
+ userId,
1130
+ participated
1131
+ )
1021
1132
  // The annotator has `resource` and `items` fields
1022
- if ('resource' in annotatedItemIds) annotatedItemIds = annotatedItemIds.itemIds
1133
+ if ('resource' in annotatedItemIds)
1134
+ annotatedItemIds = annotatedItemIds.itemIds
1023
1135
  }
1024
1136
  return annotatedItemIds
1025
1137
  },
@@ -1044,13 +1156,23 @@ export default {
1044
1156
  fetchDrawnFeatures: async function (userId, participated) {
1045
1157
  let drawnFeatures
1046
1158
  if (this.offlineAnnotationEnabled) {
1047
- this.offlineAnnotations = JSON.parse(sessionStorage.getItem('anonymous-annotation')) || []
1048
- drawnFeatures = this.offlineAnnotations.filter((offline) => {
1049
- return offline.feature && offline.resource === this.serverURL
1050
- }).map(offline => offline.feature)
1159
+ this.offlineAnnotations =
1160
+ JSON.parse(sessionStorage.getItem('anonymous-annotation')) || []
1161
+ drawnFeatures = this.offlineAnnotations
1162
+ .filter((offline) => {
1163
+ return offline.feature && offline.resource === this.serverURL
1164
+ })
1165
+ .map((offline) => offline.feature)
1051
1166
  } else {
1052
- const annotatedItemIds = await this.fetchAnnotatedItemIds(userId, participated)
1053
- drawnFeatures = await this.annotator.drawnFeatures(this.userToken, this.serverURL, annotatedItemIds)
1167
+ const annotatedItemIds = await this.fetchAnnotatedItemIds(
1168
+ userId,
1169
+ participated
1170
+ )
1171
+ drawnFeatures = await this.annotator.drawnFeatures(
1172
+ this.userToken,
1173
+ this.serverURL,
1174
+ annotatedItemIds
1175
+ )
1054
1176
  // The annotator has `resource` and `features` fields
1055
1177
  if ('resource' in drawnFeatures) drawnFeatures = drawnFeatures.features
1056
1178
  }
@@ -1066,13 +1188,22 @@ export default {
1066
1188
  this.clearAnnotationFeature()
1067
1189
  this.loading = true
1068
1190
  }
1069
- const userId = this.annotationFrom === 'Anyone' ?
1070
- undefined : this.authorisedUser.orcid ?
1071
- this.authorisedUser.orcid : '0000-0000-0000-0000'
1072
- const participated = this.annotationFrom === 'Anyone' ?
1073
- undefined : this.annotationFrom === 'Me' ?
1074
- true : false
1075
- const drawnFeatures = await this.fetchDrawnFeatures(userId, participated)
1191
+ const userId =
1192
+ this.annotationFrom === 'Anyone'
1193
+ ? undefined
1194
+ : this.authorisedUser.orcid
1195
+ ? this.authorisedUser.orcid
1196
+ : '0000-0000-0000-0000'
1197
+ const participated =
1198
+ this.annotationFrom === 'Anyone'
1199
+ ? undefined
1200
+ : this.annotationFrom === 'Me'
1201
+ ? true
1202
+ : false
1203
+ const drawnFeatures = await this.fetchDrawnFeatures(
1204
+ userId,
1205
+ participated
1206
+ )
1076
1207
  this.existDrawnFeatures = drawnFeatures
1077
1208
  this.loading = false
1078
1209
  if (!this.featureAnnotationSubmitted) {
@@ -1111,7 +1242,10 @@ export default {
1111
1242
  * Function to emit offline annotation enabled status
1112
1243
  */
1113
1244
  emitOfflineAnnotationUpdate: function () {
1114
- this.$emit('update-offline-annotation-enabled', this.offlineAnnotationEnabled);
1245
+ this.$emit(
1246
+ 'update-offline-annotation-enabled',
1247
+ this.offlineAnnotationEnabled
1248
+ )
1115
1249
  },
1116
1250
  /**
1117
1251
  * @public
@@ -1193,15 +1327,20 @@ export default {
1193
1327
  entityLabels.forEach((entityLabel) => {
1194
1328
  let enabled = true
1195
1329
  if (state) {
1196
- enabled = state.checkAll ? true : state.checked.includes(entityLabel.taxon)
1330
+ enabled = state.checkAll
1331
+ ? true
1332
+ : state.checked.includes(entityLabel.taxon)
1197
1333
  }
1198
- this.taxonConnectivity.push({...entityLabel, enabled});
1334
+ this.taxonConnectivity.push({ ...entityLabel, enabled })
1199
1335
  if (this.mapImp) {
1200
- this.mapImp.enableConnectivityByTaxonIds(entityLabel.taxon, enabled)
1336
+ this.mapImp.enableConnectivityByTaxonIds(
1337
+ entityLabel.taxon,
1338
+ enabled
1339
+ )
1201
1340
  }
1202
- });
1341
+ })
1203
1342
  }
1204
- });
1343
+ })
1205
1344
  },
1206
1345
  /**
1207
1346
  * @public
@@ -1236,19 +1375,19 @@ export default {
1236
1375
  },
1237
1376
  setInitMapState: function () {
1238
1377
  if (this.mapImp) {
1239
- const map = this.mapImp.map;
1240
- const bounds = this.mapImp.options.bounds;
1378
+ const map = this.mapImp.map
1379
+ const bounds = this.mapImp.options.bounds
1241
1380
  const initBounds = [
1242
1381
  [bounds[0], bounds[1]],
1243
- [bounds[2], bounds[3]]
1244
- ];
1382
+ [bounds[2], bounds[3]],
1383
+ ]
1245
1384
 
1246
- map.setMaxBounds(null); // override default
1247
- map.setRenderWorldCopies(false);
1385
+ map.setMaxBounds(null) // override default
1386
+ map.setRenderWorldCopies(false)
1248
1387
 
1249
1388
  this.initMapState = markRaw({
1250
1389
  initBounds,
1251
- });
1390
+ })
1252
1391
  }
1253
1392
  },
1254
1393
  /**
@@ -1259,17 +1398,17 @@ export default {
1259
1398
  resetView: function () {
1260
1399
  if (this.mapImp) {
1261
1400
  // fit to window
1262
- const map = this.mapImp.map;
1263
- const { initBounds } = this.initMapState;
1401
+ const map = this.mapImp.map
1402
+ const { initBounds } = this.initMapState
1264
1403
  // reset rotation
1265
1404
  map.resetNorthPitch({
1266
1405
  animate: false,
1267
- });
1406
+ })
1268
1407
  if (initBounds) {
1269
1408
  // reset zoom and position
1270
1409
  map.fitBounds(initBounds, {
1271
- animate: false
1272
- });
1410
+ animate: false,
1411
+ })
1273
1412
  }
1274
1413
  if (this.$refs.skcanSelection) {
1275
1414
  this.$refs.skcanSelection.reset()
@@ -1306,7 +1445,7 @@ export default {
1306
1445
  }
1307
1446
  },
1308
1447
  onSelectionsDataChanged: function (data) {
1309
- this.$emit('pathway-selection-changed', data);
1448
+ this.$emit('pathway-selection-changed', data)
1310
1449
  },
1311
1450
  /**
1312
1451
  * // Currently not in use
@@ -1349,76 +1488,94 @@ export default {
1349
1488
  retrieveConnectedPaths: async function (payload, options = {}) {
1350
1489
  // query all connected paths from flatmap
1351
1490
  if (this.mapImp) {
1352
- let connectedPaths = [];
1353
- let connectedTarget = options.target?.length ? options.target : [];
1491
+ let connectedPaths = []
1492
+ let connectedTarget = options.target?.length ? options.target : []
1354
1493
  // The line below is to get the path features from the geojson ids
1355
- const nodeFeatureIds = [...this.mapImp.pathModelNodes(payload)];
1356
- const pathsOfEntities = await this.mapImp.queryPathsForFeatures(payload);
1494
+ const nodeFeatureIds = [...this.mapImp.pathModelNodes(payload)]
1495
+ const pathsOfEntities = await this.mapImp.queryPathsForFeatures(payload)
1357
1496
  if (nodeFeatureIds.length) {
1358
1497
  if (!connectedTarget.length) {
1359
- const connectedType = options.type?.length ? options.type : ["all"];
1360
- const connectivity = await this.flatmapQueries.queryForConnectivityNew(this.mapImp, payload[0]);
1361
- const originsFlat = connectivity?.ids?.dendrites.flat(Infinity);
1362
- const componentsFlat = connectivity?.ids?.components.flat(Infinity);
1363
- const destinationsFlat = connectivity?.ids?.axons.flat(Infinity);
1364
- let connected = [];
1365
- if (connectedType.includes("origins")) connected.push(...originsFlat);
1366
- if (connectedType.includes("components")) connected.push(...componentsFlat);
1367
- if (connectedType.includes("destinations")) connected.push(...destinationsFlat);
1368
- if (connectedType.includes("all")) connected.push(...originsFlat, ...componentsFlat, ...destinationsFlat);
1369
- connectedTarget = [...new Set(connected)];
1498
+ const connectedType = options.type?.length ? options.type : ['all']
1499
+ const connectivity =
1500
+ await this.flatmapQueries.queryForConnectivityNew(
1501
+ this.mapImp,
1502
+ payload[0]
1503
+ )
1504
+ const originsFlat = connectivity?.ids?.dendrites.flat(Infinity)
1505
+ const componentsFlat = connectivity?.ids?.components.flat(Infinity)
1506
+ const destinationsFlat = connectivity?.ids?.axons.flat(Infinity)
1507
+ let connected = []
1508
+ if (connectedType.includes('origins'))
1509
+ connected.push(...originsFlat)
1510
+ if (connectedType.includes('components'))
1511
+ connected.push(...componentsFlat)
1512
+ if (connectedType.includes('destinations'))
1513
+ connected.push(...destinationsFlat)
1514
+ if (connectedType.includes('all'))
1515
+ connected.push(
1516
+ ...originsFlat,
1517
+ ...componentsFlat,
1518
+ ...destinationsFlat
1519
+ )
1520
+ connectedTarget = [...new Set(connected)]
1370
1521
  }
1371
1522
  // Loop through the node features and check if we have certain nodes
1372
1523
  nodeFeatureIds.forEach((featureId) => {
1373
1524
  // Get the paths from each node feature
1374
- const pathsL2 = this.mapImp.nodePathModels(featureId);
1525
+ const pathsL2 = this.mapImp.nodePathModels(featureId)
1375
1526
  pathsL2.forEach((path) => {
1376
1527
  // nodes of the second level path
1377
- const nodeFeatureIdsL2 = this.mapImp.pathModelNodes(path);
1528
+ const nodeFeatureIdsL2 = this.mapImp.pathModelNodes(path)
1378
1529
  const nodeModelsL2 = nodeFeatureIdsL2.map((featureIdL2) => {
1379
- return this.mapImp.featureProperties(featureIdL2).models;
1380
- });
1381
- const intersection = connectedTarget.filter(element => nodeModelsL2.includes(element));
1382
- if (intersection.length && !connectedPaths.includes(path)) connectedPaths.push(path);
1383
- });
1384
- });
1530
+ return this.mapImp.featureProperties(featureIdL2).models
1531
+ })
1532
+ const intersection = connectedTarget.filter((element) =>
1533
+ nodeModelsL2.includes(element)
1534
+ )
1535
+ if (intersection.length && !connectedPaths.includes(path))
1536
+ connectedPaths.push(path)
1537
+ })
1538
+ })
1385
1539
  } else if (pathsOfEntities.length) {
1386
1540
  if (connectedTarget.length) {
1387
1541
  pathsOfEntities.forEach((path) => {
1388
- const nodeFeatureIds = this.mapImp.pathModelNodes(path);
1542
+ const nodeFeatureIds = this.mapImp.pathModelNodes(path)
1389
1543
  const nodeModels = nodeFeatureIds.map((featureId) => {
1390
- return this.mapImp.featureProperties(featureId).models;
1391
- });
1392
- const intersection = connectedTarget.filter(element => nodeModels.includes(element));
1393
- if (intersection.length && !connectedPaths.includes(path)) connectedPaths.push(path);
1394
- });
1544
+ return this.mapImp.featureProperties(featureId).models
1545
+ })
1546
+ const intersection = connectedTarget.filter((element) =>
1547
+ nodeModels.includes(element)
1548
+ )
1549
+ if (intersection.length && !connectedPaths.includes(path))
1550
+ connectedPaths.push(path)
1551
+ })
1395
1552
  } else {
1396
- connectedPaths = pathsOfEntities;
1553
+ connectedPaths = pathsOfEntities
1397
1554
  }
1398
1555
  }
1399
- connectedPaths = [...new Set([...connectedPaths, ...payload])];
1400
- return connectedPaths;
1556
+ connectedPaths = [...new Set([...connectedPaths, ...payload])]
1557
+ return connectedPaths
1401
1558
  }
1402
1559
  },
1403
- resetMapFilter: function() {
1404
- const alert = this.mapFilters.alert;
1405
- let filter;
1406
- const isPathways = { 'tile-layer': 'pathways' };
1407
- const notPathways = { NOT: isPathways };
1560
+ resetMapFilter: function () {
1561
+ const alert = this.mapFilters.alert
1562
+ let filter
1563
+ const isPathways = { 'tile-layer': 'pathways' }
1564
+ const notPathways = { NOT: isPathways }
1408
1565
 
1409
1566
  if (alert.with && !alert.without) {
1410
1567
  // Show pathways with alert
1411
1568
  filter = {
1412
- OR: [notPathways, { AND: [isPathways, { HAS: 'alert' }] }]
1413
- };
1569
+ OR: [notPathways, { AND: [isPathways, { HAS: 'alert' }] }],
1570
+ }
1414
1571
  } else if (!alert.with && alert.without) {
1415
1572
  // Show pathways without alert
1416
1573
  filter = {
1417
- OR: [notPathways, { AND: [isPathways, { NOT: { HAS: 'alert' } }] }]
1418
- };
1574
+ OR: [notPathways, { AND: [isPathways, { NOT: { HAS: 'alert' } }] }],
1575
+ }
1419
1576
  } else if (!alert.with && !alert.without) {
1420
1577
  // Hide all pathways
1421
- filter = notPathways;
1578
+ filter = notPathways
1422
1579
  }
1423
1580
  this.setVisibilityFilter(filter)
1424
1581
  },
@@ -1431,16 +1588,17 @@ export default {
1431
1588
  alertMouseEnterEmitted: function (payload) {
1432
1589
  if (this.mapImp) {
1433
1590
  if (payload.value) {
1434
- let filter;
1435
- const isPathways = { 'tile-layer': 'pathways' };
1436
- const notPathways = { NOT: isPathways };
1591
+ let filter
1592
+ const isPathways = { 'tile-layer': 'pathways' }
1593
+ const notPathways = { NOT: isPathways }
1437
1594
 
1438
- if (payload.key === "alert" || payload.key === "withoutAlert") {
1439
- const hasAlert = payload.key === "alert" ?
1440
- { HAS: 'alert' } :
1441
- { NOT: { HAS: 'alert' } };
1595
+ if (payload.key === 'alert' || payload.key === 'withoutAlert') {
1596
+ const hasAlert =
1597
+ payload.key === 'alert'
1598
+ ? { HAS: 'alert' }
1599
+ : { NOT: { HAS: 'alert' } }
1442
1600
 
1443
- filter = { OR: [notPathways, { AND: [isPathways, hasAlert] }] };
1601
+ filter = { OR: [notPathways, { AND: [isPathways, hasAlert] }] }
1444
1602
  }
1445
1603
  this.setVisibilityFilter(filter)
1446
1604
  } else {
@@ -1456,13 +1614,13 @@ export default {
1456
1614
  */
1457
1615
  alertSelected: function (payload) {
1458
1616
  if (this.mapImp) {
1459
- if (payload.key === "alert") {
1617
+ if (payload.key === 'alert') {
1460
1618
  if (payload.value) {
1461
1619
  this.mapFilters.alert.with = true
1462
1620
  } else {
1463
1621
  this.mapFilters.alert.with = false
1464
1622
  }
1465
- } else if (payload.key === "withoutAlert") {
1623
+ } else if (payload.key === 'withoutAlert') {
1466
1624
  if (payload.value) {
1467
1625
  this.mapFilters.alert.without = true
1468
1626
  } else {
@@ -1563,7 +1721,7 @@ export default {
1563
1721
  clearTimeout(this.taxonLeaveDelay)
1564
1722
  let gid = this.mapImp.taxonFeatureIds(payload.key)
1565
1723
  this.mapImp.enableConnectivityByTaxonIds(payload.key, payload.value) // make sure path is visible
1566
- this.mapImp.zoomToGeoJSONFeatures(gid, {noZoomIn: true})
1724
+ this.mapImp.zoomToGeoJSONFeatures(gid, { noZoomIn: true })
1567
1725
  } else {
1568
1726
  this.taxonLeaveDelay = setTimeout(() => {
1569
1727
  // reset visibility of paths
@@ -1572,7 +1730,7 @@ export default {
1572
1730
  let show = payload.checked.includes(item.taxon)
1573
1731
  this.mapImp.enableConnectivityByTaxonIds(item.taxon, show)
1574
1732
  })
1575
- }, 1000);
1733
+ }, 1000)
1576
1734
  }
1577
1735
  }
1578
1736
  },
@@ -1634,15 +1792,23 @@ export default {
1634
1792
  else this.featureAnnotationSubmitted = false
1635
1793
  this.annotationEntry = []
1636
1794
  } else if (data.type === 'modeChanged') {
1637
- if (data.feature.mode === 'direct_select') this.doubleClickedFeature = true
1638
- if (this.annotationSidebar && data.feature.mode === 'simple_select' && this.activeDrawMode === 'Deleted') {
1795
+ if (data.feature.mode === 'direct_select')
1796
+ this.doubleClickedFeature = true
1797
+ if (
1798
+ this.annotationSidebar &&
1799
+ data.feature.mode === 'simple_select' &&
1800
+ this.activeDrawMode === 'Deleted'
1801
+ ) {
1639
1802
  this.annotationEventCallback({}, { type: 'aborted' })
1640
1803
  }
1641
1804
  } else if (data.type === 'selectionChanged') {
1642
- this.selectedDrawnFeature = data.feature.features.length === 0 ?
1643
- undefined : data.feature.features[0]
1805
+ this.selectedDrawnFeature =
1806
+ data.feature.features.length === 0
1807
+ ? undefined
1808
+ : data.feature.features[0]
1644
1809
  payload.feature.feature = this.selectedDrawnFeature
1645
- if (!this.activeDrawTool) { // Make sure dialog content doesn't change
1810
+ if (!this.activeDrawTool) {
1811
+ // Make sure dialog content doesn't change
1646
1812
  this.connectionEntry = {}
1647
1813
  // For exist drawn annotation features
1648
1814
  if (this.selectedDrawnFeature) {
@@ -1656,11 +1822,16 @@ export default {
1656
1822
  }
1657
1823
  this.annotationDrawModeEvent(payload)
1658
1824
  } else {
1659
- if (this.annotationSidebar && this.previousEditEvent.type === 'updated') {
1660
- this.annotationEntry = [{
1661
- ...this.previousEditEvent,
1662
- resourceId: this.serverURL
1663
- }]
1825
+ if (
1826
+ this.annotationSidebar &&
1827
+ this.previousEditEvent.type === 'updated'
1828
+ ) {
1829
+ this.annotationEntry = [
1830
+ {
1831
+ ...this.previousEditEvent,
1832
+ resourceId: this.serverURL,
1833
+ },
1834
+ ]
1664
1835
  this.annotationEventCallback({}, { type: 'aborted' })
1665
1836
  }
1666
1837
  this.previousEditEvent = {}
@@ -1671,7 +1842,9 @@ export default {
1671
1842
  if (data.type === 'updated' && data.feature.action) {
1672
1843
  data.positionUpdated = data.feature.action === 'move'
1673
1844
  }
1674
- const feature = this.mapImp.refreshAnnotationFeatureGeometry(data.feature)
1845
+ const feature = this.mapImp.refreshAnnotationFeatureGeometry(
1846
+ data.feature
1847
+ )
1675
1848
  payload.feature.feature = feature
1676
1849
  // NB. this might now be `null` if user has deleted it (before OK/Submit)
1677
1850
  // so maybe then no `service.addAnnotation` ??
@@ -1725,36 +1898,39 @@ export default {
1725
1898
  const biologicalSex = this.biologicalSex
1726
1899
  const featuresAlert = data.alert
1727
1900
  const taxons = this.getTaxons(data)
1728
- let payload = [{
1729
- dataset: data.dataset,
1730
- biologicalSex: biologicalSex,
1731
- taxonomy: taxonomy,
1732
- resource: resource,
1733
- label: label,
1734
- feature: data,
1735
- userData: args,
1736
- eventType: eventType,
1737
- provenanceTaxonomy: taxons,
1738
- alert: featuresAlert
1739
- }]
1901
+ let payload = [
1902
+ {
1903
+ dataset: data.dataset,
1904
+ biologicalSex: biologicalSex,
1905
+ taxonomy: taxonomy,
1906
+ resource: resource,
1907
+ label: label,
1908
+ feature: data,
1909
+ protocol: this.selectedSimulation,
1910
+ userData: args,
1911
+ eventType: eventType,
1912
+ provenanceTaxonomy: taxons,
1913
+ alert: featuresAlert,
1914
+ },
1915
+ ]
1740
1916
  if (eventType === 'click') {
1741
1917
  // If multiple paths overlap at the click location,
1742
1918
  // `data` is an object with numeric keys for each feature (e.g., {0: {...}, 1: {...}, ..., mapUUID: '...'}).
1743
1919
  // If only one feature or path is clicked,
1744
1920
  // `data` is a single object (e.g., {featureId: '...', mapUUID: '...'}).
1745
- const singleSelection = !data[0];
1921
+ const singleSelection = !data[0]
1746
1922
  if (!singleSelection) {
1747
1923
  payload = []
1748
1924
  const mapuuid = data.mapUUID
1749
- const seenIds = new Set();
1925
+ const seenIds = new Set()
1750
1926
  for (let [key, value] of Object.entries(data)) {
1751
1927
  if (key !== 'mapUUID') {
1752
1928
  const id = value.featureId
1753
1929
  const label = value.label
1754
1930
  const resource = [value.models]
1755
1931
  const taxons = this.getTaxons(value)
1756
- if (seenIds.has(id)) continue;
1757
- seenIds.add(id);
1932
+ if (seenIds.has(id)) continue
1933
+ seenIds.add(id)
1758
1934
  payload.push({
1759
1935
  dataset: value.dataset,
1760
1936
  biologicalSex: biologicalSex,
@@ -1766,13 +1942,13 @@ export default {
1766
1942
  eventType: eventType,
1767
1943
  provenanceTaxonomy: taxons,
1768
1944
  alert: value.alert,
1769
- mapUUID: mapuuid
1945
+ mapUUID: mapuuid,
1770
1946
  })
1771
1947
  }
1772
1948
  }
1773
1949
  }
1774
1950
  const clickedItem = singleSelection ? data : data[0]
1775
- this.setConnectivityDataSource(this.viewingMode, clickedItem);
1951
+ this.setConnectivityDataSource(this.viewingMode, clickedItem)
1776
1952
  if (this.viewingMode === 'Neuron Connection') {
1777
1953
  // do nothing here
1778
1954
  // the method to highlight paths is moved to checkAndCreatePopups function
@@ -1781,20 +1957,33 @@ export default {
1781
1957
  // This is for annotation mode - draw connectivity between features/paths
1782
1958
  if (this.activeDrawTool && !this.isValidDrawnCreated) {
1783
1959
  // Check if flatmap features or existing drawn features
1784
- const validDrawnFeature = clickedItem.featureId || this.existDrawnFeatures.find(
1785
- (feature) => feature.id === clickedItem.id
1786
- )
1960
+ const validDrawnFeature =
1961
+ clickedItem.featureId ||
1962
+ this.existDrawnFeatures.find(
1963
+ (feature) => feature.id === clickedItem.id
1964
+ )
1787
1965
  // Only the linestring will have connection
1788
1966
  if (this.activeDrawTool === 'LineString' && validDrawnFeature) {
1789
- const key = clickedItem.featureId ? clickedItem.featureId : clickedItem.id
1790
- const nodeLabel = clickedItem.label ? clickedItem.label : `Feature ${clickedItem.id}`
1967
+ const key = clickedItem.featureId
1968
+ ? clickedItem.featureId
1969
+ : clickedItem.id
1970
+ const nodeLabel = clickedItem.label
1971
+ ? clickedItem.label
1972
+ : `Feature ${clickedItem.id}`
1791
1973
  // Add space before key to make sure properties follows adding order
1792
1974
  this.connectionEntry[` ${key}`] = Object.assign(
1793
1975
  { label: nodeLabel },
1794
1976
  Object.fromEntries(
1795
1977
  Object.entries(clickedItem)
1796
- .filter(([key]) => ['featureId', 'models'].includes(key))
1797
- .map(([key, value]) => [(key === 'featureId') ? 'id' : key, value])))
1978
+ .filter(([key]) =>
1979
+ ['featureId', 'models'].includes(key)
1980
+ )
1981
+ .map(([key, value]) => [
1982
+ key === 'featureId' ? 'id' : key,
1983
+ value,
1984
+ ])
1985
+ )
1986
+ )
1798
1987
  }
1799
1988
  }
1800
1989
  }
@@ -1803,7 +1992,10 @@ export default {
1803
1992
  if (data && data.type !== 'marker' && !this.activeDrawTool) {
1804
1993
  this.checkAndCreatePopups(payload)
1805
1994
  }
1806
- } else if (eventType === 'mouseenter' && this.viewingMode !== 'Neuron Connection') {
1995
+ } else if (
1996
+ eventType === 'mouseenter' &&
1997
+ this.viewingMode !== 'Neuron Connection'
1998
+ ) {
1807
1999
  this.currentHover = data.models ? data.models : ''
1808
2000
  }
1809
2001
 
@@ -1823,11 +2015,13 @@ export default {
1823
2015
  setConnectivityDataSource: function (viewingMode, data) {
1824
2016
  // Exploration mode, only path click will be used as data source
1825
2017
  if (viewingMode === 'Exploration') {
1826
- this.connectivityDataSource = data.models?.startsWith('ilxtr:') ? data.models : '';
2018
+ this.connectivityDataSource = data.models?.startsWith('ilxtr:')
2019
+ ? data.models
2020
+ : ''
1827
2021
  } else {
1828
2022
  // Other modes, it can be anything
1829
2023
  // (annotation drawing doesn't have featureId or models)
1830
- this.connectivityDataSource = data.featureId || data.id;
2024
+ this.connectivityDataSource = data.featureId || data.id
1831
2025
  }
1832
2026
  },
1833
2027
  /**
@@ -1850,12 +2044,12 @@ export default {
1850
2044
  removeActiveTooltips: function () {
1851
2045
  // Remove active tooltip/popup on map
1852
2046
  if (this.mapImp) {
1853
- this.mapImp.removePopup();
2047
+ this.mapImp.removePopup()
1854
2048
  }
1855
2049
 
1856
2050
  // Fallback: remove any existing toolitp on DOM
1857
- const tooltips = this.$el.querySelectorAll('.flatmap-tooltip-popup');
1858
- tooltips.forEach((tooltip) => tooltip.remove());
2051
+ const tooltips = this.$el.querySelectorAll('.flatmap-tooltip-popup')
2052
+ tooltips.forEach((tooltip) => tooltip.remove())
1859
2053
  },
1860
2054
  /**
1861
2055
  * Function to create tooltip for the provided connectivity data.
@@ -1864,28 +2058,24 @@ export default {
1864
2058
  createTooltipForConnectivity: function (connectivityData, geojsonId) {
1865
2059
  // combine all labels to show together
1866
2060
  // content type must be DOM object to use HTML
1867
- const labelsContainer = document.createElement('div');
1868
- labelsContainer.classList.add('flatmap-feature-label');
2061
+ const labelsContainer = document.createElement('div')
2062
+ labelsContainer.classList.add('flatmap-feature-label')
1869
2063
 
1870
2064
  connectivityData.forEach((connectivity, i) => {
1871
- const { label } = connectivity;
1872
- labelsContainer.append(capitalise(label));
2065
+ const { label } = connectivity
2066
+ labelsContainer.append(capitalise(label))
1873
2067
 
1874
- if ((i + 1) < connectivityData.length) {
1875
- const hr = document.createElement('hr');
1876
- labelsContainer.appendChild(hr);
2068
+ if (i + 1 < connectivityData.length) {
2069
+ const hr = document.createElement('hr')
2070
+ labelsContainer.appendChild(hr)
1877
2071
  }
1878
- });
2072
+ })
1879
2073
 
1880
- this.mapImp.showPopup(
1881
- geojsonId,
1882
- labelsContainer,
1883
- {
1884
- className: 'custom-popup flatmap-tooltip-popup',
1885
- positionAtLastClick: false,
1886
- preserveSelection: true,
1887
- }
1888
- );
2074
+ this.mapImp.showPopup(geojsonId, labelsContainer, {
2075
+ className: 'custom-popup flatmap-tooltip-popup',
2076
+ positionAtLastClick: false,
2077
+ preserveSelection: true,
2078
+ })
1889
2079
  },
1890
2080
  /**
1891
2081
  * Function to show connectivity tooltips on the map
@@ -1893,129 +2083,140 @@ export default {
1893
2083
  * @arg {Object} `payload`
1894
2084
  */
1895
2085
  showConnectivityTooltips: function (payload) {
1896
- const { connectivityInfo, data } = payload;
1897
- const featuresToHighlight = [];
1898
- const geojsonHighlights = [];
1899
- const connectivityData = [];
1900
- const errorData = [];
2086
+ const { connectivityInfo, data } = payload
2087
+ const featuresToHighlight = []
2088
+ const geojsonHighlights = []
2089
+ const connectivityData = []
2090
+ const errorData = []
1901
2091
 
1902
2092
  // to keep the highlighted path on map
1903
2093
  if (connectivityInfo && connectivityInfo.featureId) {
1904
- featuresToHighlight.push(...connectivityInfo.featureId);
2094
+ featuresToHighlight.push(...connectivityInfo.featureId)
1905
2095
  }
1906
2096
 
1907
2097
  if (this.mapImp) {
1908
2098
  // search the features on the map first
1909
2099
  data.forEach((connectivity) => {
1910
- const response = this.mapImp.search(connectivity.id);
2100
+ const response = this.mapImp.search(connectivity.id)
1911
2101
 
1912
2102
  if (response?.results.length) {
1913
- const featureId = response?.results[0].featureId;
1914
- connectivityData.push({ featureId, ...connectivity });
2103
+ const featureId = response?.results[0].featureId
2104
+ connectivityData.push({ featureId, ...connectivity })
1915
2105
  } else {
1916
- errorData.push(connectivity);
2106
+ errorData.push(connectivity)
1917
2107
  }
1918
- });
2108
+ })
1919
2109
 
1920
2110
  if (connectivityData.length) {
1921
- let geojsonId = connectivityData[0].featureId;
2111
+ let geojsonId = connectivityData[0].featureId
1922
2112
 
1923
2113
  this.mapImp.annotations.forEach((annotation) => {
1924
- const anatomicalNodes = annotation['anatomical-nodes'];
2114
+ const anatomicalNodes = annotation['anatomical-nodes']
1925
2115
 
1926
2116
  if (anatomicalNodes) {
1927
- const anatomicalNodesString = anatomicalNodes.join('');
1928
- const foundItem = connectivityData.every((item) =>
1929
- anatomicalNodesString.indexOf(item.id) !== -1
1930
- );
2117
+ const anatomicalNodesString = anatomicalNodes.join('')
2118
+ const foundItem = connectivityData.every(
2119
+ (item) => anatomicalNodesString.indexOf(item.id) !== -1
2120
+ )
1931
2121
 
1932
2122
  if (foundItem) {
1933
- geojsonId = annotation.featureId;
1934
- geojsonHighlights.push(geojsonId);
2123
+ geojsonId = annotation.featureId
2124
+ geojsonHighlights.push(geojsonId)
1935
2125
  }
1936
2126
  }
1937
- });
2127
+ })
1938
2128
 
1939
- this.createTooltipForConnectivity(connectivityData, geojsonId);
2129
+ this.createTooltipForConnectivity(connectivityData, geojsonId)
1940
2130
  } else {
1941
2131
  // Close all tooltips on the current flatmap element
1942
- this.removeActiveTooltips();
2132
+ this.removeActiveTooltips()
1943
2133
  }
1944
2134
 
1945
2135
  // Emit error message for connectivity
1946
- this.emitConnectivityError(errorData);
2136
+ this.emitConnectivityError(errorData)
1947
2137
 
1948
2138
  // highlight all available features
1949
2139
  const connectivityFeatures = featuresToHighlight.reduce((arr, path) => {
1950
- const connectivityObj = this.mapImp.pathways.paths[path];
1951
- const connectivities = connectivityObj ? connectivityObj.connectivity : null;
2140
+ const connectivityObj = this.mapImp.pathways.paths[path]
2141
+ const connectivities = connectivityObj
2142
+ ? connectivityObj.connectivity
2143
+ : null
1952
2144
  if (connectivities) {
1953
- const flatFeatures = connectivities.flat(Infinity);
1954
- arr.push(...flatFeatures);
2145
+ const flatFeatures = connectivities.flat(Infinity)
2146
+ arr.push(...flatFeatures)
1955
2147
  }
1956
- return arr;
1957
- }, []);
1958
- const uniqueConnectivityFeatures = [...new Set(connectivityFeatures)];
1959
- const combinedFeatures = [...featuresToHighlight, ...uniqueConnectivityFeatures];
1960
- const featureIdsToHighlight = this.mapImp.modelFeatureIdList(combinedFeatures);
2148
+ return arr
2149
+ }, [])
2150
+ const uniqueConnectivityFeatures = [...new Set(connectivityFeatures)]
2151
+ const combinedFeatures = [
2152
+ ...featuresToHighlight,
2153
+ ...uniqueConnectivityFeatures,
2154
+ ]
2155
+ const featureIdsToHighlight =
2156
+ this.mapImp.modelFeatureIdList(combinedFeatures)
1961
2157
  const allFeaturesToHighlight = [
1962
2158
  ...featureIdsToHighlight,
1963
- ...geojsonHighlights
1964
- ];
2159
+ ...geojsonHighlights,
2160
+ ]
1965
2161
 
1966
- this.mapImp.selectGeoJSONFeatures(allFeaturesToHighlight);
2162
+ this.mapImp.selectGeoJSONFeatures(allFeaturesToHighlight)
1967
2163
  }
1968
2164
  },
1969
2165
  showConnectivitiesByReference: function (resource) {
1970
2166
  this.searchConnectivitiesByReference(resource).then((featureIds) => {
1971
- this.mapImp.selectFeatures(featureIds);
1972
- });
2167
+ this.mapImp.selectFeatures(featureIds)
2168
+ })
1973
2169
  },
1974
2170
  searchConnectivitiesByReference: async function (resource) {
1975
- const flatmapKnowledge = sessionStorage.getItem('flatmap-knowledge');
1976
- let featureIds = [];
2171
+ const flatmapKnowledge = sessionStorage.getItem('flatmap-knowledge')
2172
+ let featureIds = []
1977
2173
 
1978
2174
  if (flatmapKnowledge) {
1979
- featureIds = await getReferenceConnectivitiesFromStorage(resource);
2175
+ featureIds = await getReferenceConnectivitiesFromStorage(resource)
1980
2176
  } else {
1981
- featureIds = await getReferenceConnectivitiesByAPI(this.mapImp, resource, this.flatmapQueries);
1982
- }
1983
- return featureIds;
1984
- },
1985
- getFlatmapKnowledge: function () {
1986
- let flatmapKnowledge = [];
1987
- const flatmapKnowledgeRaw = sessionStorage.getItem('flatmap-knowledge');
1988
- if (flatmapKnowledgeRaw) {
1989
- flatmapKnowledge = JSON.parse(flatmapKnowledgeRaw);
2177
+ featureIds = await getReferenceConnectivitiesByAPI(
2178
+ this.mapImp,
2179
+ resource,
2180
+ this.flatmapQueries
2181
+ )
1990
2182
  }
1991
- return flatmapKnowledge;
2183
+ return featureIds
1992
2184
  },
1993
2185
  emitConnectivityError: function (errorData) {
1994
2186
  this.$emit('connectivity-error', {
1995
2187
  data: {
1996
2188
  errorData: errorData,
1997
2189
  errorMessage: ERROR_MESSAGE,
1998
- }
1999
- });
2190
+ },
2191
+ })
2000
2192
  },
2001
- checkConnectivityTooltipEntry: function(tooltipEntry) {
2193
+ checkConnectivityTooltipEntry: function (tooltipEntry) {
2002
2194
  if (tooltipEntry?.length) {
2003
- return undefined !== (tooltipEntry.find(entry => entry?.destinations?.length || entry?.components?.length))
2195
+ return (
2196
+ undefined !==
2197
+ tooltipEntry.find(
2198
+ (entry) => entry?.destinations?.length || entry?.components?.length
2199
+ )
2200
+ )
2004
2201
  }
2005
2202
  return false
2006
2203
  },
2007
2204
  changeConnectivitySource: async function (payload) {
2008
- const { entry, connectivitySource } = payload;
2205
+ const { entry, connectivitySource } = payload
2009
2206
  if (entry.mapId === this.mapImp.id) {
2010
- await this.flatmapQueries.queryForConnectivityNew(this.mapImp, entry.featureId[0], connectivitySource);
2207
+ await this.flatmapQueries.queryForConnectivityNew(
2208
+ this.mapImp,
2209
+ entry.featureId[0],
2210
+ connectivitySource
2211
+ )
2011
2212
  this.tooltipEntry = this.tooltipEntry.map((tooltip) => {
2012
2213
  if (tooltip.featureId[0] === entry.featureId[0]) {
2013
- return this.flatmapQueries.updateTooltipData(tooltip);
2214
+ return this.flatmapQueries.updateTooltipData(tooltip)
2014
2215
  }
2015
- return tooltip;
2216
+ return tooltip
2016
2217
  })
2017
2218
  if (this.checkConnectivityTooltipEntry(this.tooltipEntry)) {
2018
- this.$emit('connectivity-info-open', this.tooltipEntry);
2219
+ this.$emit('connectivity-info-open', this.tooltipEntry)
2019
2220
  }
2020
2221
  }
2021
2222
  },
@@ -2028,28 +2229,39 @@ export default {
2028
2229
  checkAndCreatePopups: async function (data, mapclick = true) {
2029
2230
  // Call flatmap database to get the connection data
2030
2231
  if (this.viewingMode === 'Annotation') {
2031
- const features = data.filter(d => d.feature).map(d => d.feature)
2232
+ const features = data.filter((d) => d.feature).map((d) => d.feature)
2032
2233
  if (features.length > 0) {
2033
- if (this.annotationSidebar && this.previousDeletedEvent.type === 'deleted') {
2034
- this.annotationEntry = [{
2035
- ...this.previousDeletedEvent,
2036
- resourceId: this.serverURL
2037
- }]
2234
+ if (
2235
+ this.annotationSidebar &&
2236
+ this.previousDeletedEvent.type === 'deleted'
2237
+ ) {
2238
+ this.annotationEntry = [
2239
+ {
2240
+ ...this.previousDeletedEvent,
2241
+ resourceId: this.serverURL,
2242
+ },
2243
+ ]
2038
2244
  this.annotationEventCallback({}, { type: 'aborted' })
2039
2245
  }
2040
2246
  this.annotationEntry = []
2041
- features.forEach(feature => {
2247
+ features.forEach((feature) => {
2042
2248
  this.annotationEntry.push({
2043
2249
  ...feature,
2044
2250
  resourceId: this.serverURL,
2045
- featureId: feature.featureId ? feature.featureId : feature.feature?.id,
2046
- offline: this.offlineAnnotationEnabled
2251
+ featureId: feature.featureId
2252
+ ? feature.featureId
2253
+ : feature.feature?.id,
2254
+ offline: this.offlineAnnotationEnabled,
2047
2255
  })
2048
- });
2256
+ })
2049
2257
  // Drawn feature annotationEntry will always have length of 1
2050
2258
  if (features[0].feature) {
2051
2259
  // in drawing or edit/delete mode is on or valid drawn
2052
- if (this.activeDrawTool || this.activeDrawMode || this.isValidDrawnCreated) {
2260
+ if (
2261
+ this.activeDrawTool ||
2262
+ this.activeDrawMode ||
2263
+ this.isValidDrawnCreated
2264
+ ) {
2053
2265
  this.featureAnnotationSubmitted = false
2054
2266
  if (this.activeDrawTool) {
2055
2267
  this.createConnectivityBody()
@@ -2063,8 +2275,8 @@ export default {
2063
2275
  }
2064
2276
  } else {
2065
2277
  const featureIds = this.annotationEntry
2066
- .filter(annotation => annotation.featureId && annotation.models)
2067
- .map(annotation => annotation.models)
2278
+ .filter((annotation) => annotation.featureId && annotation.models)
2279
+ .map((annotation) => annotation.models)
2068
2280
  if (featureIds.length > 0) {
2069
2281
  this.displayTooltip(featureIds)
2070
2282
  }
@@ -2076,115 +2288,130 @@ export default {
2076
2288
  // clicking on a connectivity explorer card will be the same as exploration mode
2077
2289
  // the card should be opened without doing other functions
2078
2290
  else if (this.viewingMode === 'Neuron Connection' && mapclick) {
2079
- const resources = data.map(tooltip => tooltip.resource[0]);
2291
+ const resources = data.map((tooltip) => tooltip.resource[0])
2080
2292
 
2081
2293
  // filter out paths
2082
- const featureId = resources.find(resource => !resource.startsWith('ilxtr:'));
2294
+ const featureId = resources.find(
2295
+ (resource) => !resource.startsWith('ilxtr:')
2296
+ )
2083
2297
  if (featureId) {
2084
2298
  // fallback if it cannot find in anatomical nodes
2085
- const transformResources = Array.isArray(resources) ? [...resources] : [resources];
2299
+ const transformResources = Array.isArray(resources)
2300
+ ? [...resources]
2301
+ : [resources]
2086
2302
  if (transformResources.length === 1) {
2087
- transformResources.push([]);
2303
+ transformResources.push([])
2088
2304
  }
2089
2305
 
2090
- const featureId = data[0].feature?.featureId;
2091
- const annotation = this.mapImp.annotations.get(featureId);
2092
- const anatomicalNodes = annotation?.['anatomical-nodes'];
2093
- const annotationModels = annotation?.['models'];
2094
- let anatomicalNode;
2095
- let uniqueResource = transformResources;
2096
- const models = annotation?.['models'];
2306
+ const featureId = data[0].feature?.featureId
2307
+ const annotation = this.mapImp.annotations.get(featureId)
2308
+ const anatomicalNodes = annotation?.['anatomical-nodes']
2309
+ const annotationModels = annotation?.['models']
2310
+ let anatomicalNode
2311
+ let uniqueResource = transformResources
2312
+ const models = annotation?.['models']
2097
2313
  if (anatomicalNodes?.length) {
2098
2314
  // get the node which match the feature in a location
2099
2315
  // [feature, location]
2100
- anatomicalNode = anatomicalNodes.find((node) =>
2101
- JSON.parse(node)[0] === annotationModels
2102
- );
2316
+ anatomicalNode = anatomicalNodes.find(
2317
+ (node) => JSON.parse(node)[0] === annotationModels
2318
+ )
2103
2319
  }
2104
2320
  if (anatomicalNode) {
2105
- uniqueResource = JSON.parse(anatomicalNode);
2321
+ uniqueResource = JSON.parse(anatomicalNode)
2106
2322
  } else if (models) {
2107
- uniqueResource = [models, []];
2323
+ uniqueResource = [models, []]
2108
2324
  }
2109
2325
 
2110
- const knowledgeSource = this.mapImp.knowledgeSource;
2111
- const terms = uniqueResource.flat(Infinity);
2112
- const uniqueTerms = [...new Set(terms)];
2113
- const fetchResults = await fetchLabels(this.flatmapAPI, uniqueTerms);
2326
+ const knowledgeSource = this.mapImp.knowledgeSource
2327
+ const terms = uniqueResource.flat(Infinity)
2328
+ const uniqueTerms = [...new Set(terms)]
2329
+ const fetchResults = await fetchLabels(this.flatmapAPI, uniqueTerms)
2114
2330
  const objectResults = fetchResults.reduce((arr, item) => {
2115
- const id = item[0];
2116
- const valObj = JSON.parse(item[1]);
2117
- arr.push({ id, label: valObj.label, source: valObj.source });
2118
- return arr;
2119
- }, []);
2331
+ const id = item[0]
2332
+ const valObj = JSON.parse(item[1])
2333
+ arr.push({ id, label: valObj.label, source: valObj.source })
2334
+ return arr
2335
+ }, [])
2120
2336
 
2121
2337
  // sort matched knowledgeSource items for same id
2122
2338
  objectResults.sort((a, b) => {
2123
2339
  if (a.id === b.id) {
2124
- if (a.source === knowledgeSource && b.source !== knowledgeSource) return -1;
2125
- if (a.source !== knowledgeSource && b.source === knowledgeSource) return 1;
2126
- return 0;
2340
+ if (a.source === knowledgeSource && b.source !== knowledgeSource)
2341
+ return -1
2342
+ if (a.source !== knowledgeSource && b.source === knowledgeSource)
2343
+ return 1
2344
+ return 0
2127
2345
  }
2128
- return a.id.localeCompare(b.id);
2129
- });
2346
+ return a.id.localeCompare(b.id)
2347
+ })
2130
2348
 
2131
- const labels = [];
2349
+ const labels = []
2132
2350
  for (let i = 0; i < uniqueTerms.length; i++) {
2133
- const foundObj = objectResults.find((obj) => obj.id === uniqueTerms[i])
2351
+ const foundObj = objectResults.find(
2352
+ (obj) => obj.id === uniqueTerms[i]
2353
+ )
2134
2354
  if (foundObj) {
2135
- labels.push(foundObj.label);
2355
+ labels.push(foundObj.label)
2136
2356
  }
2137
2357
  }
2138
- const filterItemLabel = capitalise(labels.join(', '));
2358
+ const filterItemLabel = capitalise(labels.join(', '))
2139
2359
  const newConnectivityfilter = {
2140
2360
  facet: JSON.stringify(uniqueResource),
2141
2361
  facetPropPath: `flatmap.connectivity.source.${this.connectionType.toLowerCase()}`,
2142
2362
  tagLabel: filterItemLabel, // used tagLabel here instead of label since the label and value are different
2143
- term: this.connectionType
2144
- };
2363
+ term: this.connectionType,
2364
+ }
2145
2365
  // check for existing item
2146
- const isNewFilterItemExist = this.connectivityFilters.some((connectivityfilter) => (
2147
- connectivityfilter.facet === newConnectivityfilter.facet &&
2148
- connectivityfilter.facetPropPath === newConnectivityfilter.facetPropPath
2149
- ));
2366
+ const isNewFilterItemExist = this.connectivityFilters.some(
2367
+ (connectivityfilter) =>
2368
+ connectivityfilter.facet === newConnectivityfilter.facet &&
2369
+ connectivityfilter.facetPropPath ===
2370
+ newConnectivityfilter.facetPropPath
2371
+ )
2150
2372
 
2151
2373
  if (!isNewFilterItemExist) {
2152
- this.connectivityFilters.push(newConnectivityfilter);
2374
+ this.connectivityFilters.push(newConnectivityfilter)
2153
2375
  }
2154
2376
 
2155
2377
  this.$emit('neuron-connection-feature-click', {
2156
2378
  filters: this.connectivityFilters,
2157
2379
  search: '',
2158
- });
2380
+ })
2159
2381
  } else {
2160
- // clicking on paths
2161
- await this.openConnectivityInfo(data);
2382
+ await this.openConnectivityInfo(data)
2162
2383
  }
2163
2384
  } else {
2164
- await this.openConnectivityInfo(data);
2385
+ await this.openConnectivityInfo(data)
2165
2386
  }
2166
2387
  },
2167
2388
  openConnectivityInfo: async function (data) {
2168
2389
  // load and store knowledge
2169
- loadAndStoreKnowledge(this.mapImp, this.flatmapQueries);
2390
+ loadAndStoreKnowledge(this.mapImp, this.flatmapQueries)
2170
2391
  let prom1 = []
2171
2392
  // Emit placeholders first.
2172
2393
  // This may contain invalid connectivity.
2173
2394
  this.tooltipEntry = data
2174
- .filter(tooltip => tooltip.resource[0] in this.mapImp.pathways.paths)
2395
+ .filter((tooltip) => tooltip.resource[0] in this.mapImp.pathways.paths)
2175
2396
  .map((tooltip) => {
2176
- return { title: tooltip.label, featureId: tooltip.resource, ready: false }
2397
+ return {
2398
+ title: tooltip.label,
2399
+ featureId: tooltip.resource,
2400
+ ready: false,
2401
+ }
2177
2402
  })
2178
2403
  // this should only for flatmap paths not all features
2179
2404
  if (this.tooltipEntry.length) {
2180
- this.$emit('connectivity-info-open', this.tooltipEntry);
2405
+ this.$emit('connectivity-info-open', this.tooltipEntry)
2181
2406
 
2182
2407
  // While having placeholders displayed, get details for all paths and then replace.
2183
2408
  for (let index = 0; index < data.length; index++) {
2184
2409
  prom1.push(await this.getKnowledgeTooltip(data[index]))
2185
2410
  }
2186
2411
  this.tooltipEntry = await Promise.all(prom1)
2187
- const featureIds = this.tooltipEntry.map(tooltip => tooltip.featureId[0])
2412
+ const featureIds = this.tooltipEntry.map(
2413
+ (tooltip) => tooltip.featureId[0]
2414
+ )
2188
2415
  if (featureIds.length > 0) {
2189
2416
  this.displayTooltip(featureIds)
2190
2417
  }
@@ -2196,79 +2423,93 @@ export default {
2196
2423
  * @param {Array} payload - The array of filter items to update.
2197
2424
  */
2198
2425
  updateConnectivityFilters: function (payload) {
2199
- if (!payload.length) return;
2200
- this.connectivityFilters = payload.filter((filterItem) => (
2201
- filterItem.facet.toLowerCase() !== 'show all'
2202
- ));
2426
+ if (!payload.length) return
2427
+ this.connectivityFilters = payload.filter(
2428
+ (filterItem) => filterItem.facet.toLowerCase() !== 'show all'
2429
+ )
2203
2430
  },
2204
2431
  resetConnectivityfilters: function (payload) {
2205
2432
  if (payload.length) {
2206
2433
  // remove not found items
2207
- this.connectivityFilters = this.connectivityFilters.filter((connectivityfilter) =>
2208
- payload.some((notFoundItem) => (
2209
- notFoundItem.facetPropPath === connectivityfilter.facetPropPath &&
2210
- notFoundItem.facet !== connectivityfilter.facet
2211
- ))
2434
+ this.connectivityFilters = this.connectivityFilters.filter(
2435
+ (connectivityfilter) =>
2436
+ payload.some(
2437
+ (notFoundItem) =>
2438
+ notFoundItem.facetPropPath ===
2439
+ connectivityfilter.facetPropPath &&
2440
+ notFoundItem.facet !== connectivityfilter.facet
2441
+ )
2212
2442
  )
2213
2443
  } else {
2214
2444
  // full reset
2215
- this.connectivityFilters = [];
2445
+ this.connectivityFilters = []
2216
2446
  }
2217
2447
  },
2218
2448
  getKnowledgeTooltip: async function (data) {
2219
2449
  //require data.resource && data.feature.source
2220
- const results = await this.flatmapQueries.retrieveFlatmapKnowledgeForEvent(this.mapImp, data)
2221
- let tooltip = await this.flatmapQueries.createTooltipData(this.mapImp, data)
2450
+ const results =
2451
+ await this.flatmapQueries.retrieveFlatmapKnowledgeForEvent(
2452
+ this.mapImp,
2453
+ data
2454
+ )
2455
+ let tooltip = await this.flatmapQueries.createTooltipData(
2456
+ this.mapImp,
2457
+ data
2458
+ )
2459
+
2222
2460
  // The line below only creates the tooltip if some data was found on the path
2223
2461
  // the pubmed URLs are in knowledge response.references
2224
- if ((results && results[0]) || (data.feature.hyperlinks && data.feature.hyperlinks.length > 0)) {
2225
- tooltip['featuresAlert'] = data.alert;
2226
- tooltip['knowledgeSource'] = getKnowledgeSource(this.mapImp);
2462
+ if (
2463
+ (results && results[0]) ||
2464
+ (data.feature.hyperlinks && data.feature.hyperlinks.length > 0)
2465
+ ) {
2466
+ tooltip['featuresAlert'] = data.alert
2467
+ tooltip['knowledgeSource'] = getKnowledgeSource(this.mapImp)
2227
2468
  // Map id and uuid to load connectivity information from the map
2228
- tooltip['mapId'] = this.mapImp.mapMetadata.id;
2229
- tooltip['mapuuid'] = this.mapImp.mapMetadata.uuid;
2230
- // } else {
2231
- // tooltip = {
2232
- // ...tooltip,
2233
- // origins: [data.label],
2234
- // originsWithDatasets: [{ id: data.resource[0], name: data.label }],
2235
- // components: [],
2236
- // componentsWithDatasets: [],
2237
- // destinations: [],
2238
- // destinationsWithDatasets: [],
2239
- // }
2240
- // let featureIds = []
2241
- // const pathsOfEntities = await this.mapImp.queryPathsForFeatures(data.resource)
2242
- // if (pathsOfEntities.length) {
2243
- // pathsOfEntities.forEach((path) => {
2244
- // featureIds.push(...this.mapImp.pathModelNodes(path))
2245
- // const searchResults = this.mapImp.search(path)
2246
- // let featureId = undefined;
2247
- // for (let i = 0; i < searchResults.results.length; i++) {
2248
- // featureId = searchResults.results[i].featureId
2249
- // const annotation = this.mapImp.annotation(featureId)
2250
- // if (featureId && annotation?.label) break;
2251
- // }
2252
- // if (featureId) {
2253
- // const feature = this.mapImp.featureProperties(featureId)
2254
- // if (feature.label && !tooltip.components.includes(feature.label)) {
2255
- // tooltip.components.push(feature.label)
2256
- // tooltip.componentsWithDatasets.push({ id: feature.models, name: feature.label })
2257
- // }
2258
- // }
2259
- // })
2260
- // featureIds = [...new Set(featureIds)].filter(id => id !== data.feature.featureId)
2261
- // featureIds.forEach((id) => {
2262
- // const feature = this.mapImp.featureProperties(id)
2263
- // if (feature.label && !tooltip.destinations.includes(feature.label)) {
2264
- // tooltip.destinations.push(feature.label)
2265
- // tooltip.destinationsWithDatasets.push({ id: feature.models, name: feature.label })
2266
- // }
2267
- // })
2268
- // }
2269
- }
2270
- tooltip['ready'] = true;
2271
- return tooltip;
2469
+ tooltip['mapId'] = this.mapImp.mapMetadata.id
2470
+ tooltip['mapuuid'] = this.mapImp.mapMetadata.uuid
2471
+ // } else {
2472
+ // tooltip = {
2473
+ // ...tooltip,
2474
+ // origins: [data.label],
2475
+ // originsWithDatasets: [{ id: data.resource[0], name: data.label }],
2476
+ // components: [],
2477
+ // componentsWithDatasets: [],
2478
+ // destinations: [],
2479
+ // destinationsWithDatasets: [],
2480
+ // }
2481
+ // let featureIds = []
2482
+ // const pathsOfEntities = await this.mapImp.queryPathsForFeatures(data.resource)
2483
+ // if (pathsOfEntities.length) {
2484
+ // pathsOfEntities.forEach((path) => {
2485
+ // featureIds.push(...this.mapImp.pathModelNodes(path))
2486
+ // const searchResults = this.mapImp.search(path)
2487
+ // let featureId = undefined;
2488
+ // for (let i = 0; i < searchResults.results.length; i++) {
2489
+ // featureId = searchResults.results[i].featureId
2490
+ // const annotation = this.mapImp.annotation(featureId)
2491
+ // if (featureId && annotation?.label) break;
2492
+ // }
2493
+ // if (featureId) {
2494
+ // const feature = this.mapImp.featureProperties(featureId)
2495
+ // if (feature.label && !tooltip.components.includes(feature.label)) {
2496
+ // tooltip.components.push(feature.label)
2497
+ // tooltip.componentsWithDatasets.push({ id: feature.models, name: feature.label })
2498
+ // }
2499
+ // }
2500
+ // })
2501
+ // featureIds = [...new Set(featureIds)].filter(id => id !== data.feature.featureId)
2502
+ // featureIds.forEach((id) => {
2503
+ // const feature = this.mapImp.featureProperties(id)
2504
+ // if (feature.label && !tooltip.destinations.includes(feature.label)) {
2505
+ // tooltip.destinations.push(feature.label)
2506
+ // tooltip.destinationsWithDatasets.push({ id: feature.models, name: feature.label })
2507
+ // }
2508
+ // })
2509
+ // }
2510
+ }
2511
+ tooltip['ready'] = true
2512
+ return tooltip
2272
2513
  },
2273
2514
  /**
2274
2515
  * A hack to remove flatmap tooltips while popup is open
@@ -2276,7 +2517,9 @@ export default {
2276
2517
  popUpCssHacks: function () {
2277
2518
  // Below is a hack to remove flatmap tooltips while popup is open
2278
2519
  const ftooltip = document.querySelector('.flatmap-tooltip-popup')
2279
- const popupCloseButton = document.querySelector('.maplibregl-popup-close-button')
2520
+ const popupCloseButton = document.querySelector(
2521
+ '.maplibregl-popup-close-button'
2522
+ )
2280
2523
  if (ftooltip) ftooltip.style.display = 'none'
2281
2524
  popupCloseButton.style.display = 'block'
2282
2525
  this.$refs.tooltip.$el.style.display = 'flex'
@@ -2285,7 +2528,7 @@ export default {
2285
2528
  * This event is emitted
2286
2529
  * when a connectivity info (provenance popup) is closed.
2287
2530
  */
2288
- this.$emit('connectivity-info-close');
2531
+ this.$emit('connectivity-info-close')
2289
2532
  if (ftooltip) ftooltip.style.display = 'block'
2290
2533
  }
2291
2534
  },
@@ -2358,10 +2601,13 @@ export default {
2358
2601
  '.maplibregl-ctrl-minimap'
2359
2602
  )
2360
2603
  if (minimapEl) {
2361
- if (this.$refs.minimapResize &&
2362
- this.$refs.minimapResize.$el.parentNode) {
2604
+ if (
2605
+ this.$refs.minimapResize &&
2606
+ this.$refs.minimapResize.$el.parentNode
2607
+ ) {
2363
2608
  this.$refs.minimapResize.$el.parentNode.removeChild(
2364
- this.$refs.minimapResize.$el)
2609
+ this.$refs.minimapResize.$el
2610
+ )
2365
2611
  }
2366
2612
  minimapEl.appendChild(this.$refs.minimapResize.$el)
2367
2613
  this.minimapResizeShow = true
@@ -2374,52 +2620,58 @@ export default {
2374
2620
  * @arg {Boolean} `helpMode`
2375
2621
  */
2376
2622
  setHelpMode: function (helpMode) {
2377
- const toolTipsLength = this.hoverVisibilities.length;
2378
- const lastIndex = toolTipsLength - 1;
2379
- const activePopoverObj = this.hoverVisibilities[this.helpModeActiveIndex];
2623
+ const toolTipsLength = this.hoverVisibilities.length
2624
+ const lastIndex = toolTipsLength - 1
2625
+ const activePopoverObj = this.hoverVisibilities[this.helpModeActiveIndex]
2380
2626
 
2381
2627
  if (activePopoverObj) {
2382
- const popoverRefsId = activePopoverObj?.refs;
2383
- const popoverRefId = activePopoverObj?.ref;
2384
- const popoverRef = this.$refs[popoverRefsId ? popoverRefsId : popoverRefId];
2628
+ const popoverRefsId = activePopoverObj?.refs
2629
+ const popoverRefId = activePopoverObj?.ref
2630
+ const popoverRef =
2631
+ this.$refs[popoverRefsId ? popoverRefsId : popoverRefId]
2385
2632
 
2386
2633
  if (popoverRef) {
2387
2634
  // Open pathway drawer if the tooltip is inside or beside
2388
- const { parentElement, nextElementSibling } = popoverRef.$el;
2635
+ const { parentElement, nextElementSibling } = popoverRef.$el
2389
2636
  const isPathwayContainer = (element) => {
2390
- return element && (
2391
- element.classList.contains('pathway-container') ||
2392
- element.classList.contains('pathway-location')
2393
- );
2394
- };
2637
+ return (
2638
+ element &&
2639
+ (element.classList.contains('pathway-container') ||
2640
+ element.classList.contains('pathway-location'))
2641
+ )
2642
+ }
2395
2643
 
2396
2644
  if (
2397
2645
  isPathwayContainer(parentElement) ||
2398
2646
  isPathwayContainer(nextElementSibling)
2399
2647
  ) {
2400
2648
  if (this.requiresDrawer) {
2401
- this.drawerOpen = true;
2649
+ this.drawerOpen = true
2402
2650
  } else {
2403
- this.helpModeActiveIndex += 1;
2651
+ this.helpModeActiveIndex += 1
2404
2652
  }
2405
2653
  }
2406
2654
  } else {
2407
2655
  // skip the unavailable tooltips
2408
- this.helpModeActiveIndex += 1;
2409
- this.setHelpMode(helpMode);
2656
+ this.helpModeActiveIndex += 1
2657
+ this.setHelpMode(helpMode)
2410
2658
  }
2411
2659
  }
2412
2660
 
2413
2661
  // Skip checkbox tooltip if pathway filter is not shown
2414
- const activePopoverObjAfter = this.hoverVisibilities[this.helpModeActiveIndex];
2415
- if (activePopoverObjAfter?.ref === 'checkBoxPopover' && !this.showPathwayFilter) {
2416
- this.helpModeActiveIndex += 1;
2417
- this.setHelpMode(helpMode);
2662
+ const activePopoverObjAfter =
2663
+ this.hoverVisibilities[this.helpModeActiveIndex]
2664
+ if (
2665
+ activePopoverObjAfter?.ref === 'checkBoxPopover' &&
2666
+ !this.showPathwayFilter
2667
+ ) {
2668
+ this.helpModeActiveIndex += 1
2669
+ this.setHelpMode(helpMode)
2418
2670
  }
2419
2671
 
2420
2672
  if (!helpMode) {
2421
2673
  // reset to iniital state
2422
- this.helpModeActiveIndex = this.helpModeInitialIndex;
2674
+ this.helpModeActiveIndex = this.helpModeInitialIndex
2423
2675
  }
2424
2676
 
2425
2677
  if (this.viewingMode !== 'Annotation' && this.helpModeActiveIndex > 9) {
@@ -2430,31 +2682,34 @@ export default {
2430
2682
  /**
2431
2683
  * This event is emitted when the tooltips in help mode reach the last item.
2432
2684
  */
2433
- this.$emit('help-mode-last-item', true);
2685
+ this.$emit('help-mode-last-item', true)
2434
2686
  }
2435
2687
 
2436
2688
  if (helpMode && !this.helpModeDialog) {
2437
- this.inHelp = true;
2689
+ this.inHelp = true
2438
2690
  this.hoverVisibilities.forEach((item) => {
2439
- item.value = true;
2440
- });
2441
- } else if (helpMode && this.helpModeDialog && toolTipsLength > this.helpModeActiveIndex) {
2442
-
2691
+ item.value = true
2692
+ })
2693
+ } else if (
2694
+ helpMode &&
2695
+ this.helpModeDialog &&
2696
+ toolTipsLength > this.helpModeActiveIndex
2697
+ ) {
2443
2698
  // Show the map tooltip as first item
2444
2699
  if (this.helpModeActiveIndex > -1) {
2445
- this.closeFlatmapHelpPopup();
2700
+ this.closeFlatmapHelpPopup()
2446
2701
 
2447
2702
  // wait for CSS transition
2448
2703
  setTimeout(() => {
2449
- this.inHelp = false;
2704
+ this.inHelp = false
2450
2705
  this.hoverVisibilities.forEach((item) => {
2451
- item.value = false;
2452
- });
2706
+ item.value = false
2707
+ })
2453
2708
 
2454
- this.showTooltip(this.helpModeActiveIndex, 200);
2455
- }, 300);
2709
+ this.showTooltip(this.helpModeActiveIndex, 200)
2710
+ }, 300)
2456
2711
  } else if (this.helpModeActiveIndex === -1) {
2457
- this.openFlatmapHelpPopup();
2712
+ this.openFlatmapHelpPopup()
2458
2713
  }
2459
2714
  } else {
2460
2715
  this.inHelp = false
@@ -2479,7 +2734,7 @@ export default {
2479
2734
  /**
2480
2735
  * This event is emitted after a tooltip in Flatmap is shown.
2481
2736
  */
2482
- this.$emit('shown-tooltip');
2737
+ this.$emit('shown-tooltip')
2483
2738
  }, timeout)
2484
2739
  }
2485
2740
  },
@@ -2515,7 +2770,7 @@ export default {
2515
2770
  if (this.annotationEntry.length) {
2516
2771
  options['annotationEvent'] = {
2517
2772
  type: this.annotationEntry[0].type,
2518
- feature: this.annotationEntry[0].feature
2773
+ feature: this.annotationEntry[0].feature,
2519
2774
  }
2520
2775
  }
2521
2776
  } else {
@@ -2530,15 +2785,19 @@ export default {
2530
2785
  // If connectivityInfoSidebar is set to `true`
2531
2786
  // Connectivity info will show in sidebar
2532
2787
  if (
2533
- (this.connectivityInfoSidebar && this.tooltipEntry.length) &&
2788
+ this.connectivityInfoSidebar &&
2789
+ this.tooltipEntry.length &&
2534
2790
  this.viewingMode !== 'Annotation'
2535
2791
  ) {
2536
2792
  if (this.checkConnectivityTooltipEntry(this.tooltipEntry)) {
2537
- this.$emit('connectivity-info-open', this.tooltipEntry);
2793
+ this.$emit('connectivity-info-open', this.tooltipEntry)
2538
2794
  }
2539
2795
  }
2540
2796
  if (this.annotationSidebar && this.viewingMode === 'Annotation') {
2541
- this.$emit('annotation-open', {annotationEntry: this.annotationEntry, commitCallback: this.commitAnnotationEvent});
2797
+ this.$emit('annotation-open', {
2798
+ annotationEntry: this.annotationEntry,
2799
+ commitCallback: this.commitAnnotationEvent,
2800
+ })
2542
2801
  }
2543
2802
  // If UI is not disabled,
2544
2803
  // And connectivityInfoSidebar is not set (default) or set to `false`
@@ -2547,16 +2806,14 @@ export default {
2547
2806
  if (
2548
2807
  featureId &&
2549
2808
  !this.disableUI &&
2550
- (
2551
- (this.viewingMode === 'Annotation' && !this.annotationSidebar) ||
2552
- (this.viewingMode === 'Exploration' && !this.connectivityInfoSidebar)
2553
- )
2809
+ ((this.viewingMode === 'Annotation' && !this.annotationSidebar) ||
2810
+ (this.viewingMode === 'Exploration' && !this.connectivityInfoSidebar))
2554
2811
  ) {
2555
- this.tooltipDisplay = true;
2812
+ this.tooltipDisplay = true
2556
2813
  this.$nextTick(() => {
2557
- this.mapImp.showPopup(featureId, this.$refs.tooltip.$el, options);
2558
- this.popUpCssHacks();
2559
- });
2814
+ this.mapImp.showPopup(featureId, this.$refs.tooltip.$el, options)
2815
+ this.popUpCssHacks()
2816
+ })
2560
2817
  }
2561
2818
  },
2562
2819
  /**
@@ -2565,18 +2822,18 @@ export default {
2565
2822
  * because the sidebar is opened
2566
2823
  * @arg featureIds
2567
2824
  */
2568
- moveMap: function (featureIds, options = {}) {
2825
+ moveMap: function (featureIds, options = {}) {
2569
2826
  if (this.mapImp) {
2570
- const { offsetX = 0, offsetY = 0, zoom = 4 } = options;
2571
- const Map = this.mapImp.map;
2572
- const bbox = this.mapImp.bounds.toArray();
2827
+ const { offsetX = 0, offsetY = 0, zoom = 4 } = options
2828
+ const Map = this.mapImp.map
2829
+ const bbox = this.mapImp.bounds.toArray()
2573
2830
 
2574
2831
  // Zoom the map to features first
2575
- this.mapImp.zoomToFeatures(featureIds, { noZoomIn: true });
2832
+ this.mapImp.zoomToFeatures(featureIds, { noZoomIn: true })
2576
2833
 
2577
2834
  // Hide the left pathway drawer
2578
2835
  // to get more space for the map
2579
- this.showPathwaysDrawer(false);
2836
+ this.showPathwaysDrawer(false)
2580
2837
 
2581
2838
  // Move the map to left side
2582
2839
  // since the sidebar is taking space on the right
@@ -2585,9 +2842,9 @@ export default {
2585
2842
  Map.fitBounds(bbox, {
2586
2843
  offset: [offsetX, offsetY],
2587
2844
  zoom: zoom,
2588
- animate: true
2589
- });
2590
- });
2845
+ animate: true,
2846
+ })
2847
+ })
2591
2848
  }
2592
2849
  }
2593
2850
  },
@@ -2607,7 +2864,7 @@ export default {
2607
2864
  /**
2608
2865
  * This event is emitted after a tooltip on Flatmap's map is shown.
2609
2866
  */
2610
- this.$emit('shown-map-tooltip');
2867
+ this.$emit('shown-map-tooltip')
2611
2868
  }
2612
2869
  }
2613
2870
  },
@@ -2642,16 +2899,19 @@ export default {
2642
2899
  */
2643
2900
  getVisibilityState: function (state) {
2644
2901
  const refs = ['alertSelection', 'pathwaysSelection', 'taxonSelection']
2645
- refs.forEach(ref => {
2902
+ refs.forEach((ref) => {
2646
2903
  let comp = this.$refs[ref]
2647
2904
  if (comp) {
2648
2905
  state[ref] = comp.getState()
2649
2906
  }
2650
2907
  })
2651
2908
  if (this.$refs.treeControls) {
2652
- const checkedKeys = this.$refs.treeControls.$refs.regionTree.getCheckedKeys();
2909
+ const checkedKeys =
2910
+ this.$refs.treeControls.$refs.regionTree.getCheckedKeys()
2653
2911
  //Only store first level systems (terms without .)
2654
- state['systemsSelection'] = checkedKeys.filter(term => !term.includes('.'))
2912
+ state['systemsSelection'] = checkedKeys.filter(
2913
+ (term) => !term.includes('.')
2914
+ )
2655
2915
  }
2656
2916
  },
2657
2917
  /**
@@ -2660,7 +2920,7 @@ export default {
2660
2920
  */
2661
2921
  setVisibilityState: function (state) {
2662
2922
  const refs = ['alertSelection', 'pathwaysSelection', 'taxonSelection']
2663
- refs.forEach(ref => {
2923
+ refs.forEach((ref) => {
2664
2924
  const settings = state[ref]
2665
2925
  if (settings) {
2666
2926
  const comp = this.$refs[ref]
@@ -2671,9 +2931,14 @@ export default {
2671
2931
  })
2672
2932
  if ('systemsSelection' in state) {
2673
2933
  if (this.$refs.treeControls) {
2674
- this.$refs.treeControls.$refs.regionTree.setCheckedKeys(state['systemsSelection']);
2934
+ this.$refs.treeControls.$refs.regionTree.setCheckedKeys(
2935
+ state['systemsSelection']
2936
+ )
2675
2937
  this.systems[0].children.forEach((item) => {
2676
- this.mapImp.enableSystem(item.key, state['systemsSelection'].includes(item.key))
2938
+ this.mapImp.enableSystem(
2939
+ item.key,
2940
+ state['systemsSelection'].includes(item.key)
2941
+ )
2677
2942
  })
2678
2943
  }
2679
2944
  }
@@ -2700,7 +2965,9 @@ export default {
2700
2965
  state['outlines'] = this.outlinesRadio
2701
2966
  state['background'] = this.currentBackground
2702
2967
  if (this.offlineAnnotationEnabled) {
2703
- state['offlineAnnotations'] = sessionStorage.getItem('anonymous-annotation')
2968
+ state['offlineAnnotations'] = sessionStorage.getItem(
2969
+ 'anonymous-annotation'
2970
+ )
2704
2971
  }
2705
2972
  this.getVisibilityState(state)
2706
2973
  return state
@@ -2737,7 +3004,10 @@ export default {
2737
3004
  if (state) {
2738
3005
  if (state.viewport) this.mapImp.setState(state.viewport)
2739
3006
  if (state.offlineAnnotations) {
2740
- sessionStorage.setItem('anonymous-annotation', state.offlineAnnotations)
3007
+ sessionStorage.setItem(
3008
+ 'anonymous-annotation',
3009
+ state.offlineAnnotations
3010
+ )
2741
3011
  }
2742
3012
  if (state.viewingMode) this.changeViewingMode(state.viewingMode)
2743
3013
  //The following three are boolean
@@ -2761,7 +3031,10 @@ export default {
2761
3031
  */
2762
3032
  setFlightPathInfo: function (mapVersion) {
2763
3033
  const mapVersionForFlightPath = 1.6
2764
- if (mapVersion === mapVersionForFlightPath || mapVersion > mapVersionForFlightPath) {
3034
+ if (
3035
+ mapVersion === mapVersionForFlightPath ||
3036
+ mapVersion > mapVersionForFlightPath
3037
+ ) {
2765
3038
  // Show flight path option UI
2766
3039
  this.displayFlightPathOption = true
2767
3040
  // Show 2D as default on FC type
@@ -2807,10 +3080,10 @@ export default {
2807
3080
  identifier.taxon = state.entry
2808
3081
  }
2809
3082
  if (state.biologicalSex) {
2810
- identifier['biologicalSex'] = state.biologicalSex;
3083
+ identifier['biologicalSex'] = state.biologicalSex
2811
3084
  } else if (identifier.taxon === 'NCBITaxon:9606') {
2812
3085
  //For backward compatibility
2813
- identifier['biologicalSex'] = 'PATO:0000384';
3086
+ identifier['biologicalSex'] = 'PATO:0000384'
2814
3087
  }
2815
3088
  } else {
2816
3089
  // Set the bioloicalSex now if map is not resumed from
@@ -2834,48 +3107,52 @@ export default {
2834
3107
  // tooltipDelay: 15, // new feature to delay tooltips showing
2835
3108
  }
2836
3109
  )
2837
- promise1.then((returnedObject) => {
2838
- this.mapImp = returnedObject
2839
- this.serverURL = this.mapImp.makeServerUrl('').slice(0, -1)
2840
- let mapVersion = this.mapImp.details.version
2841
- this.setFlightPathInfo(mapVersion)
2842
- const stateToSet = this._stateToBeSet ? this._stateToBeSet : state
2843
- this.onFlatmapReady(stateToSet)
2844
- this.$nextTick(() => this.restoreMapState(stateToSet))
2845
- }).catch((error) => {
2846
- console.error('Flatmap loading error:', error)
2847
- // prepare error object
2848
- this.flatmapError = {};
2849
- if (error.message && error.message.indexOf('Unknown map') !== -1) {
2850
- this.flatmapError['title'] = 'Unknown Map!';
2851
- this.flatmapError['messages'] = Object.keys(identifier).map(key => {
2852
- const keyName = key === 'uuid' ? 'UUID' : capitalise(key);
2853
- return `${keyName}: ${identifier[key]}`
2854
- });
2855
- } else {
2856
- this.flatmapError['title'] = 'Error Loading Map!';
2857
- this.flatmapError['messages'] = [
2858
- error.message ? error.message : error.toString(),
2859
- 'Please try again later or contact support if the problem persists.'
2860
- ];
2861
- }
2862
- if (this.$parent?.$refs?.multiContainer) {
2863
- // if the flatmap is in a multiflatmapvuer
2864
- // show a button to load default map
2865
- const multiFlatmapVuer = this.$parent;
2866
- this.flatmapError['button'] = {
2867
- text: 'Load Default Map',
2868
- callback: () => {
2869
- const defaultSpecies = multiFlatmapVuer.initial;
2870
- multiFlatmapVuer.setSpecies(defaultSpecies, undefined, 3);
3110
+ promise1
3111
+ .then((returnedObject) => {
3112
+ this.mapImp = returnedObject
3113
+ this.serverURL = this.mapImp.makeServerUrl('').slice(0, -1)
3114
+ let mapVersion = this.mapImp.details.version
3115
+ this.setFlightPathInfo(mapVersion)
3116
+ const stateToSet = this._stateToBeSet ? this._stateToBeSet : state
3117
+ this.onFlatmapReady(stateToSet)
3118
+ this.$nextTick(() => this.restoreMapState(stateToSet))
3119
+ })
3120
+ .catch((error) => {
3121
+ console.error('Flatmap loading error:', error)
3122
+ // prepare error object
3123
+ this.flatmapError = {}
3124
+ if (error.message && error.message.indexOf('Unknown map') !== -1) {
3125
+ this.flatmapError['title'] = 'Unknown Map!'
3126
+ this.flatmapError['messages'] = Object.keys(identifier).map(
3127
+ (key) => {
3128
+ const keyName = key === 'uuid' ? 'UUID' : capitalise(key)
3129
+ return `${keyName}: ${identifier[key]}`
3130
+ }
3131
+ )
3132
+ } else {
3133
+ this.flatmapError['title'] = 'Error Loading Map!'
3134
+ this.flatmapError['messages'] = [
3135
+ error.message ? error.message : error.toString(),
3136
+ 'Please try again later or contact support if the problem persists.',
3137
+ ]
3138
+ }
3139
+ if (this.$parent?.$refs?.multiContainer) {
3140
+ // if the flatmap is in a multiflatmapvuer
3141
+ // show a button to load default map
3142
+ const multiFlatmapVuer = this.$parent
3143
+ this.flatmapError['button'] = {
3144
+ text: 'Load Default Map',
3145
+ callback: () => {
3146
+ const defaultSpecies = multiFlatmapVuer.initial
3147
+ multiFlatmapVuer.setSpecies(defaultSpecies, undefined, 3)
3148
+ },
2871
3149
  }
2872
- };
2873
- }
2874
- this.loading = false;
2875
- })
3150
+ }
3151
+ this.loading = false
3152
+ })
2876
3153
  } else if (state) {
2877
3154
  this._stateToBeSet = {
2878
- ...state
3155
+ ...state,
2879
3156
  }
2880
3157
  if (this.mapImp && !this.loading) {
2881
3158
  this.restoreMapState(this._stateToBeSet)
@@ -2917,7 +3194,7 @@ export default {
2917
3194
  let filterSourcesMap = new Map()
2918
3195
  for (const annotation of this.mapImp.annotations.values()) {
2919
3196
  if (annotation.source) {
2920
- if ("alert" in annotation) {
3197
+ if ('alert' in annotation) {
2921
3198
  withAlert.add(annotation.source)
2922
3199
  } else {
2923
3200
  withoutAlert.add(annotation.source)
@@ -2934,7 +3211,7 @@ export default {
2934
3211
  sourceMap.set(setKey, new Set())
2935
3212
  }
2936
3213
  sourceMap.get(setKey).add(`${annotation.source}`)
2937
- };
3214
+ }
2938
3215
  if (Array.isArray(value)) {
2939
3216
  value.forEach(addToSourceMap)
2940
3217
  } else {
@@ -2945,10 +3222,10 @@ export default {
2945
3222
  }
2946
3223
  }
2947
3224
  let filterSources = {
2948
- 'alert': {
2949
- 'with': [...withAlert],
2950
- 'without': [...withoutAlert]
2951
- }
3225
+ alert: {
3226
+ with: [...withAlert],
3227
+ without: [...withoutAlert],
3228
+ },
2952
3229
  }
2953
3230
  for (const [key, value] of filterSourcesMap.entries()) {
2954
3231
  filterSources[key] = {}
@@ -2959,10 +3236,15 @@ export default {
2959
3236
  return filterSources
2960
3237
  },
2961
3238
  getFilterOptions: async function (mapImp, _providedKnowledge) {
2962
- const providedKnowledge = _providedKnowledge || this.getFlatmapKnowledge();
2963
- const providedPathways = this.pathways;
2964
- const flatmapFilterOptions = await getFlatmapFilterOptions(this.flatmapAPI, mapImp, providedKnowledge, providedPathways);
2965
- return flatmapFilterOptions;
3239
+ const providedKnowledge = _providedKnowledge || this.getFlatmapKnowledge()
3240
+ const providedPathways = this.pathways
3241
+ const flatmapFilterOptions = await getFlatmapFilterOptions(
3242
+ this.flatmapAPI,
3243
+ mapImp,
3244
+ providedKnowledge,
3245
+ providedPathways
3246
+ )
3247
+ return flatmapFilterOptions
2966
3248
  },
2967
3249
  /**
2968
3250
  * @public
@@ -2970,33 +3252,40 @@ export default {
2970
3252
  */
2971
3253
  onFlatmapReady: function (state) {
2972
3254
  // onFlatmapReady is used for functions that need to run immediately after the flatmap is loaded
2973
- this.sensor = markRaw(new ResizeSensor(this.$refs.display, this.mapResize))
3255
+ this.sensor = markRaw(
3256
+ new ResizeSensor(this.$refs.display, this.mapResize)
3257
+ )
2974
3258
  if (this.mapImp.options?.style === 'functional') {
2975
3259
  this.isFC = true
2976
3260
  }
2977
3261
  this.mapImp.setBackgroundOpacity(1)
2978
3262
  this.backgroundChangeCallback(this.currentBackground)
2979
3263
  this.pathways = this.mapImp.pathTypes()
2980
- this.pathways = this.pathways.filter(path => {
3264
+ this.pathways = this.pathways.filter((path) => {
2981
3265
  return path.enabled && path.type !== 'other'
2982
3266
  })
2983
3267
  //Disable layers for now
2984
3268
  //this.layers = this.mapImp.getLayers();
2985
3269
  this.processSystems(this.mapImp.getSystems())
2986
3270
  //Async, pass the state for checking
2987
- this.processTaxon(this.mapImp.taxonIdentifiers, state ? state['taxonSelection'] : undefined)
2988
- this.containsAlert = "alert" in this.mapImp.featureFilterRanges()
3271
+ this.processTaxon(
3272
+ this.mapImp.taxonIdentifiers,
3273
+ state ? state['taxonSelection'] : undefined
3274
+ )
3275
+
3276
+ this.containsAlert = 'alert' in this.mapImp.featureFilterRanges()
2989
3277
  this.flatmapLegends = this.mapImp.flatmapLegend
2990
3278
  this.loading = false
2991
3279
  this.computePathControlsMaximumHeight()
2992
3280
  this.mapResize()
2993
- this.handleMapClick();
2994
- this.setInitMapState();
3281
+ this.handleMapClick()
3282
+ this.setInitMapState()
2995
3283
  if (this.displayMinimap) {
2996
- const minimapOptions = { position: 'top-right' };
2997
- this.mapImp.createMinimap(minimapOptions);
3284
+ const minimapOptions = { position: 'top-right' }
3285
+ this.mapImp.createMinimap(minimapOptions)
2998
3286
  this.addResizeButtonToMinimap()
2999
3287
  }
3288
+ this.currentFlatmapUuid = this.mapImp?.mapMetadata?.uuid
3000
3289
  /**
3001
3290
  * This is ``onFlatmapReady`` event.
3002
3291
  * @arg ``this`` (Component Vue Instance)
@@ -3009,33 +3298,35 @@ export default {
3009
3298
  * after the map is loaded.
3010
3299
  */
3011
3300
  handleMapClick: function () {
3012
- const _map = this.mapImp.map;
3301
+ const _map = this.mapImp.map
3013
3302
  if (_map) {
3014
3303
  _map.on('click', (e) => {
3015
3304
  if (!this.connectivityDataSource) {
3016
- this.$emit('connectivity-info-close');
3305
+ this.$emit('connectivity-info-close')
3017
3306
  }
3018
- this.connectivityDataSource = ''; // reset
3019
- });
3307
+ this.connectivityDataSource = '' // reset
3308
+ })
3020
3309
  }
3021
3310
  },
3022
- onContextLost: function() {
3311
+ onContextLost: function () {
3023
3312
  this.lastViewport = markRaw(this.mapImp.getState())
3024
- this.flatmapError = {};
3313
+ this.flatmapError = {}
3025
3314
  this.flatmapError['title'] = 'GL context lost!'
3026
- this.flatmapError['messages'] = [`A display issue has occurred due
3315
+ this.flatmapError['messages'] = [
3316
+ `A display issue has occurred due
3027
3317
  to a limit on available WebGL contexts. You can restore the display
3028
3318
  using the Restore Context button. Please see the
3029
3319
  <a href="https://docs.sparc.science/docs/integrated-maps-viewer-overview#limit-on-available-webgl-contexts" target='_blank'>documentation</a>
3030
- for more details.`]
3320
+ for more details.`,
3321
+ ]
3031
3322
  this.flatmapError['button'] = {
3032
3323
  text: 'Restore Context',
3033
3324
  callback: () => {
3034
3325
  this.forceContextRestore()
3035
- }
3036
- };
3326
+ },
3327
+ }
3037
3328
  },
3038
- onContextRestored: function() {
3329
+ onContextRestored: function () {
3039
3330
  if (this.mapImp) {
3040
3331
  this.handleMapClick()
3041
3332
  this.setInitMapState()
@@ -3045,8 +3336,8 @@ export default {
3045
3336
  }
3046
3337
  this.restoreMapState(lostState)
3047
3338
  if (this.displayMinimap) {
3048
- const minimapOptions = { position: 'top-right' };
3049
- this.mapImp.createMinimap(minimapOptions);
3339
+ const minimapOptions = { position: 'top-right' }
3340
+ this.mapImp.createMinimap(minimapOptions)
3050
3341
  this.addResizeButtonToMinimap()
3051
3342
  }
3052
3343
  if (this.filterToRestore) {
@@ -3077,23 +3368,23 @@ export default {
3077
3368
  if (this.mapImp) {
3078
3369
  if (term === undefined || term === '') {
3079
3370
  this.mapImp.clearSearchResults()
3080
- if (this.viewingMode === "Exploration") {
3081
- this.$emit('connectivity-info-close');
3082
- } else if (this.viewingMode === "Annotation") {
3371
+ if (this.viewingMode === 'Exploration') {
3372
+ this.$emit('connectivity-info-close')
3373
+ } else if (this.viewingMode === 'Annotation') {
3083
3374
  this.manualAbortedOnClose()
3084
3375
  }
3085
- this.searchTerm = ""
3376
+ this.searchTerm = ''
3086
3377
  return true
3087
3378
  } else {
3088
3379
  const searchResults = this.mapImp.search(term)
3089
3380
  if (searchResults?.results?.length) {
3090
3381
  this.mapImp.showSearchResults(searchResults)
3091
3382
  if (displayInfo) {
3092
- let featureId = undefined;
3383
+ let featureId = undefined
3093
3384
  for (let i = 0; i < searchResults.results.length; i++) {
3094
3385
  featureId = searchResults.results[i].featureId
3095
3386
  const annotation = this.mapImp.annotation(featureId)
3096
- if (featureId && annotation?.label) break;
3387
+ if (featureId && annotation?.label) break
3097
3388
  }
3098
3389
  if (featureId) {
3099
3390
  const feature = this.mapImp.featureProperties(featureId)
@@ -3129,10 +3420,13 @@ export default {
3129
3420
  highlightConnectedPaths: function (paths) {
3130
3421
  if (paths.length) {
3131
3422
  // filter paths for this map
3132
- const filteredPaths = paths.filter(path => (path in this.mapImp.pathways.paths))
3423
+ const filteredPaths = paths.filter(
3424
+ (path) => path in this.mapImp.pathways.paths
3425
+ )
3133
3426
  // this.zoomToFeatures is replaced with selectGeoJSONFeatures to highlight paths
3134
- const featureIdsToHighlight = this.mapImp.modelFeatureIdList(filteredPaths);
3135
- this.mapImp.selectGeoJSONFeatures(featureIdsToHighlight);
3427
+ const featureIdsToHighlight =
3428
+ this.mapImp.modelFeatureIdList(filteredPaths)
3429
+ this.mapImp.selectGeoJSONFeatures(featureIdsToHighlight)
3136
3430
  }
3137
3431
  },
3138
3432
  /**
@@ -3149,7 +3443,136 @@ export default {
3149
3443
  EventBus.emit('onActionClick', data)
3150
3444
  },
3151
3445
  setConnectionType: function (type) {
3152
- this.connectionType = type;
3446
+ this.connectionType = type
3447
+ },
3448
+ /**
3449
+ * Main function to coordinate fetching dataset info and processing files.
3450
+ */
3451
+ async fetchFlatmapProtocols(uuid) {
3452
+ const cacheKey = `flatmap_dataset_${uuid}`
3453
+
3454
+ // Try to get from cache first
3455
+ // console.log('------- caching temporary disabled for debugging -------')
3456
+ // const cachedData = null
3457
+ const cachedData = this.getSessionCache(cacheKey)
3458
+ if (cachedData) {
3459
+ this.datasetInfo = cachedData
3460
+ this.processDatasetFiles(cachedData)
3461
+ return
3462
+ }
3463
+
3464
+ // If not in cache, call the API
3465
+ try {
3466
+ console.log('Fetching dataset info from API...', this.sparcAPI, uuid)
3467
+ // Ensure the URL matches your backend route structure
3468
+ const response = await fetch(`${this.sparcAPI}flatmap/uuid?uuid=${uuid}`)
3469
+
3470
+ if (!response.ok)
3471
+ throw new Error(`API call failed: ${response.statusText}`)
3472
+
3473
+ const data = await response.json()
3474
+
3475
+ // Save to cache and process
3476
+ this.setSessionCache(cacheKey, data)
3477
+ this.datasetInfo = data
3478
+ this.processDatasetFiles(data)
3479
+ } catch (error) {
3480
+ console.error('Error fetching flatmap protocols:', error)
3481
+ }
3482
+ },
3483
+
3484
+ /**
3485
+ * Extract the bucket name from an S3 URI.
3486
+ *
3487
+ * @param s3Uri
3488
+ */
3489
+ extractBucketNameFromS3Uri(s3Uri) {
3490
+ try {
3491
+ // Use the native URL API to parse the s3:// URI
3492
+ // s3://bucket-name/path/to/key -> hostname is bucket-name
3493
+ const url = new URL(s3Uri)
3494
+ return url.hostname
3495
+ } catch (e) {
3496
+ console.error('Error converting S3 URI:', e)
3497
+ return null
3498
+ }
3499
+ },
3500
+ /**
3501
+ * Iterates through the file list, constructs full URLs, and checks for simulation content.
3502
+ */
3503
+ async processDatasetFiles(data) {
3504
+ if (!data || data.length === 0) return
3505
+
3506
+ this.simulationInfo = [] // Reset list
3507
+
3508
+ //FIXME: Currently only process the first dataset entry
3509
+ const firstData = data[0]
3510
+ // Base URL for Pennsieve public assets
3511
+ const baseUrl = `${this.sparcAPI}/s3-resource/${firstData.dataset_id}/files`
3512
+ const bucketName = this.extractBucketNameFromS3Uri(firstData.s3uri)
3513
+
3514
+ firstData.urls.map(async (filePath) => {
3515
+ const fullUrl = `${baseUrl}/${filePath}?s3BucketName=${bucketName}`
3516
+ // Add to our list of valid files
3517
+ this.simulationInfo.push({
3518
+ label: firstData.title,
3519
+ s3uri: firstData.s3uri,
3520
+ dataset_id: firstData.dataset_id,
3521
+ version: firstData.version,
3522
+ path: filePath,
3523
+ type: 'Simulation',
3524
+ resource: fullUrl,
3525
+ })
3526
+ })
3527
+ },
3528
+ /**
3529
+ * Retrieve data from session storage if it hasn't expired.
3530
+ */
3531
+ getSessionCache(key) {
3532
+ const itemStr = sessionStorage.getItem(key)
3533
+ if (!itemStr) return null
3534
+
3535
+ try {
3536
+ const item = JSON.parse(itemStr)
3537
+ const now = new Date()
3538
+
3539
+ // Check if expired (compare current time to expiry time)
3540
+ if (now.getTime() > item.expiry) {
3541
+ sessionStorage.removeItem(key)
3542
+ return null
3543
+ }
3544
+ return item.value
3545
+ } catch (e) {
3546
+ return null
3547
+ }
3548
+ },
3549
+
3550
+ /**
3551
+ * Save data to session storage with a 24-hour expiry.
3552
+ */
3553
+ setSessionCache(key, value) {
3554
+ const now = new Date()
3555
+ // 24 hours in milliseconds: 24 * 60 * 60 * 1000 = 86400000
3556
+ const ttl = 86400000
3557
+
3558
+ const item = {
3559
+ value: value,
3560
+ expiry: now.getTime() + ttl,
3561
+ }
3562
+
3563
+ try {
3564
+ sessionStorage.setItem(key, JSON.stringify(item))
3565
+ } catch (e) {
3566
+ console.warn('Session storage full or disabled', e)
3567
+ }
3568
+ },
3569
+ getSimulationLabel(info) {
3570
+ return info.path.split('/').pop()
3571
+ },
3572
+ openSimulation() {
3573
+ if (this.selectedSimulation) {
3574
+ this.$emit('open-simulation', this.selectedSimulation)
3575
+ }
3153
3576
  },
3154
3577
  },
3155
3578
  props: {
@@ -3208,7 +3631,7 @@ export default {
3208
3631
  * On default, `false`, clicking help will show all tooltips.
3209
3632
  * If `true`, clicking help will show the help-mode-dialog.
3210
3633
  */
3211
- helpModeDialog: {
3634
+ helpModeDialog: {
3212
3635
  type: Boolean,
3213
3636
  default: false,
3214
3637
  },
@@ -3342,7 +3765,7 @@ export default {
3342
3765
  /**
3343
3766
  * Flag to disable UIs on Map
3344
3767
  */
3345
- disableUI: {
3768
+ disableUI: {
3346
3769
  type: Boolean,
3347
3770
  default: false,
3348
3771
  },
@@ -3405,12 +3828,14 @@ export default {
3405
3828
  flatmapError: null,
3406
3829
  sensor: null,
3407
3830
  mapManagerRef: undefined,
3831
+ currentFlatmapUuid: undefined,
3408
3832
  flatmapQueries: undefined,
3409
3833
  annotationEntry: [],
3410
3834
  //tooltip display has to be set to false until it is rendered
3411
- //for the first time, otherwise it may display an arrow at a
3835
+ //for the first time, otherwise it may display an arrow at an
3412
3836
  //undesired location.
3413
3837
  tooltipDisplay: false,
3838
+ tooltipTimer: null,
3414
3839
  serverURL: undefined,
3415
3840
  layers: [],
3416
3841
  pathways: [],
@@ -3436,12 +3861,13 @@ export default {
3436
3861
  { value: false, ref: 'warningPopover' }, // 7
3437
3862
  { value: false, ref: 'whatsNewPopover' }, // 8
3438
3863
  { value: false, ref: 'featuredMarkerPopover' }, // 9
3439
- { value: false, refs: "toolbarPopover", ref: "editPopover" }, // 10
3440
- { value: false, refs: "toolbarPopover", ref: "deletePopover" }, // 11
3441
- { value: false, refs: "toolbarPopover", ref: "pointPopover" }, // 12
3442
- { value: false, refs: "toolbarPopover", ref: "lineStringPopover" }, // 13
3443
- { value: false, refs: "toolbarPopover", ref: "polygonPopover" }, // 14
3444
- { value: false, refs: "toolbarPopover", ref: "connectionPopover" }, // 15
3864
+ { value: false, refs: 'toolbarPopover', ref: 'editPopover' }, // 10
3865
+ { value: false, refs: 'toolbarPopover', ref: 'deletePopover' }, // 11
3866
+ { value: false, refs: 'toolbarPopover', ref: 'pointPopover' }, // 12
3867
+ { value: false, refs: 'toolbarPopover', ref: 'lineStringPopover' }, // 13
3868
+ { value: false, refs: 'toolbarPopover', ref: 'polygonPopover' }, // 14
3869
+ { value: false, refs: 'toolbarPopover', ref: 'connectionPopover' }, // 15
3870
+ { value: false, ref: 'simulationPopover' }, // 16
3445
3871
  ],
3446
3872
  helpModeActiveIndex: this.helpModeInitialIndex,
3447
3873
  yellowstar: yellowstar,
@@ -3466,9 +3892,14 @@ export default {
3466
3892
  currentHover: '',
3467
3893
  viewingMode: 'Exploration',
3468
3894
  viewingModes: {
3469
- 'Exploration': 'Find relevant research and view detail of neural pathways by selecting a pathway to view its connections and data sources',
3470
- 'Neuron Connection': 'Discover Neuron connections by selecting a neuron and viewing its associated network connections',
3471
- 'Annotation': ['View feature annotations', 'Add, comment on and view feature annotations']
3895
+ Exploration:
3896
+ 'Find relevant research and view detail of neural pathways by selecting a pathway to view its connections and data sources',
3897
+ 'Neuron Connection':
3898
+ 'Discover Neuron connections by selecting a neuron and viewing its associated network connections',
3899
+ Annotation: [
3900
+ 'View feature annotations',
3901
+ 'Add, comment on and view feature annotations',
3902
+ ],
3472
3903
  },
3473
3904
  connectionType: 'All',
3474
3905
  offlineAnnotationEnabled: false,
@@ -3478,12 +3909,12 @@ export default {
3478
3909
  openMapRef: undefined,
3479
3910
  backgroundIconRef: undefined,
3480
3911
  toolbarOptions: [
3481
- "Edit",
3482
- "Delete",
3483
- "Point",
3484
- "LineString",
3485
- "Polygon",
3486
- "Connection",
3912
+ 'Edit',
3913
+ 'Delete',
3914
+ 'Point',
3915
+ 'LineString',
3916
+ 'Polygon',
3917
+ 'Connection',
3487
3918
  ],
3488
3919
  annotator: undefined,
3489
3920
  authorisedUser: undefined,
@@ -3513,13 +3944,17 @@ export default {
3513
3944
  alert: {
3514
3945
  with: true,
3515
3946
  without: true,
3516
- }
3947
+ },
3517
3948
  }),
3518
- searchTerm: "",
3949
+ searchTerm: '',
3519
3950
  taxonLeaveDelay: undefined,
3520
3951
  connectivityFilters: [],
3521
3952
  flatmapLegends: [],
3522
3953
  lastViewport: undefined,
3954
+ simulationInfo: [],
3955
+ datasetInfo: null,
3956
+ simulationDrawerOpen: false,
3957
+ selectedSimulation: null,
3523
3958
  }
3524
3959
  },
3525
3960
  computed: {
@@ -3527,16 +3962,17 @@ export default {
3527
3962
  isValidDrawnCreated: function () {
3528
3963
  return Object.keys(this.drawnCreatedEvent).length > 0
3529
3964
  },
3530
- requiresDrawer: function() {
3965
+ requiresDrawer: function () {
3531
3966
  if (this.loading) {
3532
3967
  this.drawerOpen = false
3533
3968
  return false
3534
3969
  }
3535
- if ((this.systems?.length > 0) ||
3970
+ if (
3971
+ this.systems?.length > 0 ||
3536
3972
  (this.containsAlert && this.alertOptions) ||
3537
- (this.pathways?.length > 0) ||
3538
- (this.taxonConnectivity?.length > 0) ||
3539
- (this.legendEntry?.length > 0)
3973
+ this.pathways?.length > 0 ||
3974
+ this.taxonConnectivity?.length > 0 ||
3975
+ this.legendEntry?.length > 0
3540
3976
  ) {
3541
3977
  this.drawerOpen = true
3542
3978
  return true
@@ -3558,7 +3994,7 @@ export default {
3558
3994
  return [...this.flatmapLegends, ...this.externalLegends]
3559
3995
  },
3560
3996
  showDatasetMarkerTooltip: function () {
3561
- return this.hoverVisibilities[9].value;
3997
+ return this.hoverVisibilities[9].value
3562
3998
  },
3563
3999
  },
3564
4000
  watch: {
@@ -3574,11 +4010,11 @@ export default {
3574
4010
  // just take the action from helpModeActiveItem
3575
4011
  // work with local value since the indexing is different
3576
4012
  if (this.helpMode) {
3577
- this.helpModeActiveIndex += 1;
3578
- this.setHelpMode(this.helpMode);
4013
+ this.helpModeActiveIndex += 1
4014
+ this.setHelpMode(this.helpMode)
3579
4015
  }
3580
4016
  },
3581
- render: function(val) {
4017
+ render: function (val) {
3582
4018
  if (val) {
3583
4019
  if (this.mapImp && this.mapImp.contextLost && !this.loading) {
3584
4020
  this.$nextTick(() => {
@@ -3613,7 +4049,7 @@ export default {
3613
4049
  this.authorisedUser = undefined
3614
4050
  this.offlineAnnotationEnabled = true
3615
4051
  }
3616
- this.emitOfflineAnnotationUpdate();
4052
+ this.emitOfflineAnnotationUpdate()
3617
4053
  this.setFeatureAnnotated()
3618
4054
  this.addAnnotationFeature()
3619
4055
  this.loading = false
@@ -3626,54 +4062,67 @@ export default {
3626
4062
  }
3627
4063
  },
3628
4064
  activeDrawTool: function (tool) {
3629
- let coordinates = [];
3630
- let lastClick = { x: null, y: null };
3631
- const canvas = this.$el.querySelector('.maplibregl-canvas');
4065
+ let coordinates = []
4066
+ let lastClick = { x: null, y: null }
4067
+ const canvas = this.$el.querySelector('.maplibregl-canvas')
3632
4068
  const removeListeners = () => {
3633
- canvas.removeEventListener('keydown', handleKeyboardEvent);
3634
- canvas.removeEventListener('click', handleMouseEvent);
3635
- };
4069
+ canvas.removeEventListener('keydown', handleKeyboardEvent)
4070
+ canvas.removeEventListener('click', handleMouseEvent)
4071
+ }
3636
4072
  const handleKeyboardEvent = (event) => {
3637
- if (!['Escape', 'Enter'].includes(event.key)) return;
4073
+ if (!['Escape', 'Enter'].includes(event.key)) return
3638
4074
  const isValidDraw =
3639
4075
  (tool === 'Point' && coordinates.length === 1) ||
3640
4076
  (tool === 'LineString' && coordinates.length >= 2) ||
3641
- (tool === 'Polygon' && coordinates.length >= 3);
4077
+ (tool === 'Polygon' && coordinates.length >= 3)
3642
4078
  if (event.key === 'Escape' || (event.key === 'Enter' && !isValidDraw)) {
3643
- this.activeDrawTool = undefined;
4079
+ this.activeDrawTool = undefined
3644
4080
  }
3645
- removeListeners();
3646
- };
4081
+ removeListeners()
4082
+ }
3647
4083
  const handleMouseEvent = (event) => {
3648
- const rect = canvas.getBoundingClientRect();
3649
- const x = event.clientX - rect.left;
3650
- const y = event.clientY - rect.top;
3651
- const distance = Math.sqrt((x - lastClick.x) ** 2 + (y - lastClick.y) ** 2);
4084
+ const rect = canvas.getBoundingClientRect()
4085
+ const x = event.clientX - rect.left
4086
+ const y = event.clientY - rect.top
4087
+ const distance = Math.sqrt(
4088
+ (x - lastClick.x) ** 2 + (y - lastClick.y) ** 2
4089
+ )
3652
4090
  if (distance < 8) {
3653
- if (!this.isValidDrawnCreated) this.activeDrawTool = undefined;
3654
- removeListeners();
3655
- return;
4091
+ if (!this.isValidDrawnCreated) this.activeDrawTool = undefined
4092
+ removeListeners()
4093
+ return
3656
4094
  }
3657
- lastClick = { x, y };
3658
- coordinates.push(lastClick);
3659
- };
4095
+ lastClick = { x, y }
4096
+ coordinates.push(lastClick)
4097
+ }
3660
4098
  if (tool) {
3661
- removeListeners();
3662
- canvas.addEventListener('keydown', handleKeyboardEvent);
3663
- canvas.addEventListener('click', handleMouseEvent);
4099
+ removeListeners()
4100
+ canvas.addEventListener('keydown', handleKeyboardEvent)
4101
+ canvas.addEventListener('click', handleMouseEvent)
3664
4102
  }
3665
- }
4103
+ },
4104
+ currentFlatmapUuid: {
4105
+ handler(newUuid) {
4106
+ if (newUuid) {
4107
+ // console.log('New map loaded with uuid:', newUuid)
4108
+ this.fetchFlatmapProtocols(newUuid)
4109
+ }
4110
+ },
4111
+ // immediate: true,
4112
+ },
3666
4113
  },
3667
4114
  created: function () {
3668
4115
  if (this.mapManager) {
3669
- this.mapManagerRef = this.mapManager;
4116
+ this.mapManagerRef = this.mapManager
3670
4117
  } else {
3671
- this.mapManagerRef = markRaw(new flatmap.MapViewer(this.flatmapAPI, { container: undefined }));
4118
+ this.mapManagerRef = markRaw(
4119
+ new flatmap.MapViewer(this.flatmapAPI, { container: undefined })
4120
+ )
3672
4121
  /**
3673
4122
  * The event emitted after a new mapManager is loaded.
3674
4123
  * This mapManager can be used to create new flatmaps.
3675
4124
  */
3676
- this.$emit('mapmanager-loaded', this.mapManagerRef);
4125
+ this.$emit('mapmanager-loaded', this.mapManagerRef)
3677
4126
  }
3678
4127
  },
3679
4128
  mounted: function () {
@@ -3690,17 +4139,16 @@ export default {
3690
4139
  } else if (this.renderAtMounted) {
3691
4140
  this.createFlatmap()
3692
4141
  }
3693
- refreshFlatmapKnowledgeCache();
4142
+ refreshFlatmapKnowledgeCache()
3694
4143
  },
3695
4144
  }
3696
4145
  </script>
3697
4146
 
3698
4147
  <style lang="scss" scoped>
3699
-
3700
4148
  .beta-popovers {
3701
4149
  position: absolute;
3702
- top: 90px;
3703
- left: 16px;
4150
+ top: 0px;
4151
+ left: 50%;
3704
4152
  text-align: left;
3705
4153
  font-size: 25px;
3706
4154
  }
@@ -3756,6 +4204,32 @@ export default {
3756
4204
  width: 100%;
3757
4205
  }
3758
4206
 
4207
+ .popover-location {
4208
+ position: absolute;
4209
+ left: 0px;
4210
+ transform: translateX(0);
4211
+ transition: all var(--el-transition-duration);
4212
+ z-index: 99;
4213
+ display: flex;
4214
+ flex-direction: row;
4215
+ align-items: center;
4216
+
4217
+ &.open {
4218
+ transform: translateX(0);
4219
+ }
4220
+ &.close {
4221
+ transform: translateX(-100%);
4222
+ }
4223
+ }
4224
+
4225
+ .popover-location.top {
4226
+ top: 5px;
4227
+ }
4228
+
4229
+ .popover-location.bottom {
4230
+ bottom: 0px;
4231
+ }
4232
+
3759
4233
  .pathway-location {
3760
4234
  position: absolute;
3761
4235
  bottom: 0px;
@@ -4002,7 +4476,7 @@ export default {
4002
4476
  }
4003
4477
  }
4004
4478
 
4005
- :deep(.flatmap-marker-popup){
4479
+ :deep(.flatmap-marker-popup) {
4006
4480
  .maplibregl-popup-content {
4007
4481
  padding: 0px;
4008
4482
  }
@@ -4027,7 +4501,9 @@ export default {
4027
4501
  }
4028
4502
  }
4029
4503
 
4030
- .zoomIn, .zoomOut, .fitWindow {
4504
+ .zoomIn,
4505
+ .zoomOut,
4506
+ .fitWindow {
4031
4507
  padding: 4px;
4032
4508
  }
4033
4509
 
@@ -4142,7 +4618,7 @@ export default {
4142
4618
  color: $app-primary-color;
4143
4619
 
4144
4620
  &.open-map-button {
4145
- margin-bottom:4px;
4621
+ margin-bottom: 4px;
4146
4622
  }
4147
4623
 
4148
4624
  &:hover {
@@ -4266,7 +4742,7 @@ export default {
4266
4742
  position: relative;
4267
4743
 
4268
4744
  &::before {
4269
- content: "";
4745
+ content: '';
4270
4746
  display: block;
4271
4747
  width: 0;
4272
4748
  height: 0;
@@ -4395,7 +4871,7 @@ export default {
4395
4871
  background-color: var(--white);
4396
4872
  font-weight: 500;
4397
4873
  color: rgb(48, 49, 51);
4398
- width: 150px!important;
4874
+ width: 150px !important;
4399
4875
  }
4400
4876
 
4401
4877
  :deep(.flatmap_dropdown) {
@@ -4419,11 +4895,10 @@ export default {
4419
4895
  </style>
4420
4896
 
4421
4897
  <style lang="scss">
4422
-
4423
4898
  .flatmap-container {
4424
- --el-color-primary: #8300BF;
4425
- --el-color-primary-light-5: #CD99E5;
4426
- --el-color-primary-light-9: #F3E6F9;
4899
+ --el-color-primary: #8300bf;
4900
+ --el-color-primary-light-5: #cd99e5;
4901
+ --el-color-primary-light-9: #f3e6f9;
4427
4902
  --el-color-primary-dark-2: var(--el-color-primary);
4428
4903
  }
4429
4904
 
@@ -4446,5 +4921,4 @@ export default {
4446
4921
  }
4447
4922
  }
4448
4923
  }
4449
-
4450
4924
  </style>