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