@abi-software/flatmapvuer 0.6.3-vue.3.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +120 -120
  3. package/cypress.config.js +23 -23
  4. package/dist/flatmapvuer.js +15894 -16259
  5. package/dist/flatmapvuer.umd.cjs +132 -145
  6. package/dist/index.html +17 -17
  7. package/dist/style.css +1 -1
  8. package/package.json +95 -95
  9. package/public/index.html +17 -17
  10. package/reporter-config.json +9 -9
  11. package/src/App.vue +310 -310
  12. package/src/assets/_variables.scss +43 -43
  13. package/src/assets/styles.scss +5 -5
  14. package/src/components/AnnotationTool.vue +450 -446
  15. package/src/components/EventBus.js +3 -3
  16. package/src/components/ExternalResourceCard.vue +107 -107
  17. package/src/components/FlatmapVuer.vue +2600 -2531
  18. package/src/components/MultiFlatmapVuer.vue +731 -731
  19. package/src/components/ProvenancePopup.vue +503 -495
  20. package/src/components/SelectionsGroup.vue +255 -255
  21. package/src/components/Tooltip.vue +50 -50
  22. package/src/components/TreeControls.vue +231 -231
  23. package/src/components/index.js +7 -7
  24. package/src/components/legends/DynamicLegends.vue +106 -106
  25. package/src/components/legends/SvgLegends.vue +112 -112
  26. package/src/icons/flatmap-marker.js +1 -1
  27. package/src/icons/fonts/mapicon-species.svg +14 -14
  28. package/src/icons/fonts/mapicon-species.ttf +0 -0
  29. package/src/icons/fonts/mapicon-species.woff +0 -0
  30. package/src/icons/mapicon-species-style.css +42 -42
  31. package/src/icons/yellowstar.js +5 -5
  32. package/src/legends/legend.svg +25 -25
  33. package/src/main.js +19 -19
  34. package/src/services/flatmapQueries.js +453 -453
  35. package/src/store/index.js +23 -23
  36. package/vite.config.js +73 -73
  37. package/vite.static-build.js +12 -12
  38. package/vuese-generator.js +64 -64
@@ -1,2532 +1,2601 @@
1
- <template>
2
- <div
3
- class="flatmap-container"
4
- ref="flatmapContainer"
5
- v-loading="loading"
6
- element-loading-text="Loading..."
7
- element-loading-background="rgba(0, 0, 0, 0.3)"
8
- >
9
- <map-svg-sprite-color />
10
- <div
11
- style="height: 100%; width: 100%; position: relative; overflow-y: none"
12
- >
13
- <div style="height: 100%; width: 100%" ref="display"></div>
14
- <div class="beta-popovers" v-show="!disableUI">
15
- <div>
16
- <el-popover
17
- placement="right"
18
- popper-class="warning-popper flatmap-popper"
19
- :teleported="false"
20
- :visible="hoverVisibilities[6].value"
21
- ref="warningPopover"
22
- >
23
- <p
24
- v-if="isLegacy"
25
- @mouseover="showToolitip(6)"
26
- @mouseout="hideToolitip(6)"
27
- >
28
- This is a legacy map, you may view the latest map instead.
29
- </p>
30
- <p
31
- v-else-if="isFC"
32
- @mouseover="showToolitip(6)"
33
- @mouseout="hideToolitip(6)"
34
- >
35
- This map displays the connectivity of individual neurons.
36
- Specifically, those which align with (parts of) the neuron
37
- populations from the
38
- <a
39
- href="https://sparc.science/resources/1ZUKXU2YmLcn2reCyXjlew"
40
- target="_blank"
41
- >
42
- ApiNATOMY
43
- </a>
44
- models available in
45
- <a
46
- href="https://sparc.science/resources/6eg3VpJbwQR4B84CjrvmyD"
47
- target="_blank"
48
- >
49
- SCKAN </a
50
- >.
51
- </p>
52
- <p v-else @mouseover="showToolitip(6)" @mouseout="hideToolitip(6)">
53
- This map displays the connectivity of neuron populations.
54
- Specifically, those from the primarily rat-based
55
- <a
56
- href="https://sparc.science/resources/1ZUKXU2YmLcn2reCyXjlew"
57
- target="_blank"
58
- >
59
- ApiNATOMY
60
- </a>
61
- models available in
62
- <a
63
- href="https://sparc.science/resources/6eg3VpJbwQR4B84CjrvmyD"
64
- target="_blank"
65
- >
66
- SCKAN </a
67
- >. New connectivity and species specificity will be added as the
68
- SPARC program progresses.
69
- </p>
70
- <template #reference>
71
- <div
72
- class="warning-icon"
73
- v-if="displayWarning"
74
- @mouseover="showToolitip(6)"
75
- @mouseout="hideToolitip(6)"
76
- >
77
- <el-icon><el-icon-warning-filled /></el-icon>
78
- <template v-if="isLegacy">
79
- <span class="warning-text">Legacy Map</span>
80
- <div class="latest-map-text" @click="viewLatestMap">
81
- Click here for the latest map
82
- </div>
83
- </template>
84
- <template v-else>
85
- <span class="warning-text">Beta</span>
86
- </template>
87
- </div>
88
- </template>
89
- </el-popover>
90
- </div>
91
- <el-popover
92
- placement="right"
93
- v-if="displayLatestChanges"
94
- :teleported="false"
95
- trigger="manual"
96
- popper-class="warning-popper flatmap-popper"
97
- :visible="hoverVisibilities[7].value"
98
- >
99
- <template #reference>
100
- <div
101
- class="latest-changesicon"
102
- v-if="displayLatestChanges"
103
- @mouseover="showToolitip(7)"
104
- @mouseout="hideToolitip(7)"
105
- >
106
- <el-icon><el-icon-warning-filled /></el-icon>
107
- <span class="warning-text">What's new?</span>
108
- </div>
109
- </template>
110
- <template #default>
111
- <b>Network discovery mode</b>
112
- <p>
113
- You can now view the network of neurons connected to a selected
114
- neuron. This mode is located in the settings at the bottom right.
115
- Once discovery mode is on, click on a neuron to see its
116
- connections.
117
- </p>
118
- <b>Now can display up to 6 panes</b>
119
- <p>
120
- You can now display up to 6 panes in the flatmap. This allows you
121
- to compare between different datasets and/or different views of
122
- the same dataset.
123
- </p>
124
- </template>
125
- </el-popover>
126
- </div>
127
-
128
- <!-- The element below is placed onto the flatmap when it is ready -->
129
- <el-icon
130
- class="minimap-resize"
131
- :class="{ enlarge: minimapSmall, shrink: !minimapSmall }"
132
- ref="minimapResize"
133
- v-show="minimapResizeShow"
134
- @click="closeMinimap"
135
- >
136
- <el-icon-arrow-down />
137
- </el-icon>
138
-
139
- <div class="bottom-right-control" v-show="!disableUI">
140
- <el-popover
141
- content="Zoom in"
142
- placement="left"
143
- :teleported="false"
144
- trigger="manual"
145
- width="70"
146
- popper-class="flatmap-popper"
147
- :visible="hoverVisibilities[0].value"
148
- >
149
- <template #reference>
150
- <map-svg-icon
151
- icon="zoomIn"
152
- class="icon-button zoomIn"
153
- @click="zoomIn()"
154
- @mouseover="showToolitip(0)"
155
- @mouseout="hideToolitip(0)"
156
- />
157
- </template>
158
- </el-popover>
159
- <el-popover
160
- content="Zoom out"
161
- placement="top-end"
162
- :teleported="false"
163
- trigger="manual"
164
- width="70"
165
- popper-class="flatmap-popper popper-zoomout"
166
- :visible="hoverVisibilities[1].value"
167
- >
168
- <template #reference>
169
- <map-svg-icon
170
- icon="zoomOut"
171
- class="icon-button zoomOut"
172
- @click="zoomOut()"
173
- @mouseover="showToolitip(1)"
174
- @mouseout="hideToolitip(1)"
175
- />
176
- </template>
177
- </el-popover>
178
- <el-popover
179
- content="Reset"
180
- placement="top"
181
- :teleported="false"
182
- trigger="manual"
183
- width="70"
184
- popper-class="flatmap-popper"
185
- :visible="hoverVisibilities[2].value"
186
- >
187
- <div>
188
- Fit to
189
- <br />
190
- window
191
- </div>
192
- <template #reference>
193
- <map-svg-icon
194
- icon="fitWindow"
195
- class="icon-button fitWindow"
196
- @click="resetView()"
197
- @mouseover="showToolitip(2)"
198
- @mouseout="hideToolitip(2)"
199
- />
200
- </template>
201
- </el-popover>
202
- </div>
203
- <el-popover
204
- content="Change pathway visibility"
205
- placement="right"
206
- :teleported="false"
207
- trigger="manual"
208
- popper-class="flatmap-popper"
209
- :visible="hoverVisibilities[4].value"
210
- ref="checkBoxPopover"
211
- >
212
- <template #reference>
213
- <div
214
- class="pathway-location"
215
- :class="{ open: drawerOpen, close: !drawerOpen }"
216
- v-show="!disableUI"
217
- >
218
- <div
219
- class="pathway-container"
220
- :class="{ open: drawerOpen, close: !drawerOpen }"
221
- :style="{ 'max-height': pathwaysMaxHeight + 'px' }"
222
- v-popover:checkBoxPopover
223
- >
224
- <svg-legends v-if="!isFC" class="svg-legends-container" />
225
- <el-popover
226
- content="Location of the featured dataset"
227
- placement="right"
228
- :teleported="false"
229
- trigger="hover"
230
- popper-class="flatmap-popper popper-bump-right"
231
- :visible="hoverVisibilities[9].value"
232
- ref="featuredMarkerPopover"
233
- >
234
- <template #reference>
235
- <div
236
- v-show="showStarInLegend"
237
- v-popover:featuredMarkerPopover
238
- class="yellow-star-legend"
239
- v-html="yellowstar"
240
- ></div>
241
- </template>
242
- </el-popover>
243
- <!-- The line below places the yellowstar svg on the left, and the text "Featured markers on the right" with css so they are both centered in the div -->
244
- <el-popover
245
- content="Find these markers for data"
246
- placement="right"
247
- :teleported="false"
248
- trigger="manual"
249
- popper-class="flatmap-popper popper-bump-right"
250
- :visible="hoverVisibilities[5].value"
251
- ref="markerPopover"
252
- >
253
- <template #reference>
254
- <div
255
- v-show="hoverVisibilities[5].value"
256
- class="flatmap-marker-help"
257
- v-html="flatmapMarker"
258
- v-popover:markerPopover
259
- ></div>
260
- </template>
261
- </el-popover>
262
- <tree-controls
263
- v-if="isFC && systems && systems.length > 0"
264
- :active="currentActive"
265
- :hover="currentHover"
266
- :tree-data="systems"
267
- ref="treeControls"
268
- @changed="systemSelected"
269
- @checkAll="checkAllSystems"
270
- @change-active="ftuSelected"
271
- />
272
- <selections-group
273
- v-if="!isFC && centreLines && centreLines.length > 0"
274
- title="Nerves"
275
- labelKey="label"
276
- identifierKey="key"
277
- :selections="centreLines"
278
- @changed="centreLinesSelected"
279
- ref="centrelinesSelection"
280
- key="centrelinesSelection"
281
- />
282
- <!--
283
- <selections-group
284
- v-if="isFC && sckanDisplay && sckanDisplay.length > 0"
285
- title="SCKAN"
286
- labelKey="label"
287
- identifierKey="key"
288
- :selections="sckanDisplay"
289
- @changed="sckanSelected"
290
- @checkAll="checkAllSCKAN"
291
- ref="skcanSelection"
292
- key="skcanSelection"
293
- />
294
- <selections-group
295
- v-if="layers && layers.length > 0"
296
- title="Layers"
297
- labelKey="description"
298
- identifierKey="id"
299
- :selections="layers"
300
- @changed="layersSelected"
301
- @checkAll="checkAllLayers"
302
- ref="layersSelection"
303
- key="layersSelection"
304
- />
305
- -->
306
- <selections-group
307
- v-if="!isFC && taxonConnectivity && taxonConnectivity.length > 0"
308
- title="Observed in"
309
- labelKey="label"
310
- identifierKey="taxon"
311
- :selections="taxonConnectivity"
312
- @changed="taxonsSelected"
313
- @checkAll="checkAllTaxons"
314
- ref="taxonSelection"
315
- key="taxonSelection"
316
- />
317
- <selections-group
318
- v-if="pathways && pathways.length > 0"
319
- title="Pathways"
320
- labelKey="label"
321
- identifierKey="type"
322
- colourStyle="line"
323
- :selections="pathways"
324
- @changed="pathwaysSelected"
325
- @checkAll="checkAllPathways"
326
- ref="pathwaysSelection"
327
- key="pathwaysSelection"
328
- />
329
- </div>
330
- <div
331
- @click="toggleDrawer"
332
- class="drawer-button"
333
- :class="{ open: drawerOpen, close: !drawerOpen }"
334
- >
335
- <el-icon><el-icon-arrow-left /></el-icon>
336
- </div>
337
- </div>
338
- </template>
339
- </el-popover>
340
- <el-popover
341
- v-if="openMapRef"
342
- ref="open-map-popover"
343
- :virtual-ref="openMapRef"
344
- placement="top-start"
345
- width="136"
346
- :teleported="false"
347
- trigger="click"
348
- popper-class="open-map-popper non-selectable"
349
- virtual-triggering
350
- >
351
- <el-row v-for="item in openMapOptions" :key="item.key">
352
- <el-button type="primary" plain
353
- @click="/**
354
- * This event is emitted when the user chooses a different map option
355
- * from ``openMapOptions`` props.
356
- * @arg mapOption.key
357
- * */
358
- $emit('open-map', item.key)"
359
- >
360
- {{ item.display }}
361
- </el-button>
362
- </el-row>
363
- </el-popover>
364
- <el-popover
365
- ref="backgroundPopover"
366
- :virtual-ref="backgroundIconRef"
367
- placement="top-start"
368
- width="200"
369
- :teleported="false"
370
- trigger="click"
371
- popper-class="background-popper h-auto"
372
- virtual-triggering
373
- >
374
- <div>
375
- <el-row class="backgroundText">Viewing Mode</el-row>
376
- <el-row class="backgroundControl">
377
- <el-select
378
- :teleported="false"
379
- v-model="viewingMode"
380
- placeholder="Select"
381
- class="select-box"
382
- popper-class="flatmap_dropdown"
383
- >
384
- <el-option
385
- v-for="(item, i) in viewingModes"
386
- :key="item + i"
387
- :label="item"
388
- :value="item"
389
- >
390
- <el-row>
391
- <el-col :span="12">{{ item }}</el-col>
392
- </el-row>
393
- </el-option>
394
- </el-select>
395
- </el-row>
396
- <el-row class="backgroundSpacer" v-if="displayFlightPathOption"></el-row>
397
- <el-row class="backgroundText" v-if="displayFlightPathOption">Flight path display</el-row>
398
- <el-row class="backgroundControl" v-if="displayFlightPathOption">
399
- <el-radio-group
400
- v-model="flightPath3DRadio"
401
- class="flatmap-radio"
402
- @change="setFlightPath3D"
403
- >
404
- <el-radio :label="false">2D</el-radio>
405
- <el-radio :label="true">3D</el-radio>
406
- </el-radio-group>
407
- </el-row>
408
- <el-row class="backgroundSpacer"></el-row>
409
- <el-row class="backgroundText">Organs display</el-row>
410
- <el-row class="backgroundControl">
411
- <el-radio-group
412
- v-model="colourRadio"
413
- class="flatmap-radio"
414
- @change="setColour"
415
- >
416
- <el-radio :label="true">Colour</el-radio>
417
- <el-radio :label="false">Greyscale</el-radio>
418
- </el-radio-group>
419
- </el-row>
420
- <el-row class="backgroundSpacer"></el-row>
421
- <el-row class="backgroundText">Outlines display</el-row>
422
- <el-row class="backgroundControl">
423
- <el-radio-group
424
- v-model="outlinesRadio"
425
- class="flatmap-radio"
426
- @change="setOutlines"
427
- >
428
- <el-radio :label="true">Show</el-radio>
429
- <el-radio :label="false">Hide</el-radio>
430
- </el-radio-group>
431
- </el-row>
432
- <el-row class="backgroundSpacer"></el-row>
433
- <el-row class="backgroundText">Change background</el-row>
434
- <el-row class="backgroundControl">
435
- <div
436
- v-for="item in availableBackground"
437
- :key="item"
438
- :class="[
439
- 'backgroundChoice',
440
- item,
441
- item == currentBackground ? 'active' : '',
442
- ]"
443
- @click="backgroundChangeCallback(item)"
444
- />
445
- </el-row>
446
- </div>
447
- </el-popover>
448
- <div
449
- class="settings-group"
450
- :class="{ open: drawerOpen, close: !drawerOpen }"
451
- v-show="!disableUI"
452
- >
453
- <el-row>
454
- <el-popover
455
- :visible="hoverVisibilities[8].value"
456
- content="Open new map"
457
- placement="right"
458
- :teleported="false"
459
- popper-class="flatmap-popper"
460
- >
461
- <template #reference>
462
- <map-svg-icon
463
- v-if="enableOpenMapUI && openMapOptions.length > 0"
464
- ref="openMapRef"
465
- icon="openMap"
466
- class="icon-button open-map-button"
467
- @mouseover="showToolitip(8)"
468
- @mouseout="hideToolitip(8)"
469
- />
470
- </template>
471
- </el-popover>
472
- </el-row>
473
- <el-row>
474
- <el-popover
475
- content="Change settings"
476
- placement="right"
477
- :visible="hoverVisibilities[3].value"
478
- :teleported="false"
479
- trigger="manual"
480
- popper-class="flatmap-popper"
481
- >
482
- <template #reference>
483
- <map-svg-icon
484
- ref="backgroundIconRef"
485
- icon="changeBckgd"
486
- class="icon-button"
487
- @mouseover="showToolitip(3)"
488
- @mouseout="hideToolitip(3)"
489
- />
490
- </template>
491
- </el-popover>
492
- </el-row>
493
- </div>
494
- <Tooltip
495
- ref="tooltip"
496
- class="tooltip"
497
- v-show="tooltipDisplay"
498
- :annotationEntry="annotationEntry"
499
- :entry="tooltipEntry"
500
- :annotationDisplay="viewingMode === 'Annotation'"
501
- />
502
- </div>
503
- </div>
504
- </template>
505
-
506
- <script>
507
- import { shallowRef } from 'vue'
508
- import {
509
- WarningFilled as ElIconWarningFilled,
510
- ArrowDown as ElIconArrowDown,
511
- ArrowLeft as ElIconArrowLeft,
512
- } from '@element-plus/icons-vue'
513
- /* eslint-disable no-alert, no-console */
514
- import Tooltip from './Tooltip.vue'
515
- import SelectionsGroup from './SelectionsGroup.vue'
516
- import TreeControls from './TreeControls.vue'
517
- import { MapSvgIcon, MapSvgSpriteColor } from '@abi-software/svg-sprite'
518
- import SvgLegends from './legends/SvgLegends.vue'
519
- import {
520
- ElButton as Button,
521
- ElCol as Col,
522
- ElLoading as Loading,
523
- ElRadio as Radio,
524
- ElRadioGroup as RadioGroup,
525
- ElRow as Row,
526
- ElSelect as Select,
527
- } from 'element-plus'
528
- import flatmapMarker from '../icons/flatmap-marker'
529
- import {
530
- FlatmapQueries,
531
- findTaxonomyLabel,
532
- } from '../services/flatmapQueries.js'
533
- import yellowstar from '../icons/yellowstar'
534
- import ResizeSensor from 'css-element-queries/src/ResizeSensor'
535
- import * as flatmap from '@abi-software/flatmap-viewer'
536
- import { mapState } from 'pinia'
537
- import { useMainStore } from '@/store/index'
538
-
539
-
540
- const processFTUs = (parent, key) => {
541
- const ftus = []
542
- let items = parent.organs ? parent.organs : parent.ftus
543
- const children = items
544
- ? items.filter(
545
- (obj, index) =>
546
- items.findIndex((item) => item.label === obj.label) === index
547
- )
548
- : undefined
549
- if (children) {
550
- children.forEach((child) => {
551
- const data = {
552
- label: child.label,
553
- models: child.models,
554
- key: `${key}.${child.label}`,
555
- }
556
- const grandChildren = processFTUs(child, data.key)
557
- if (grandChildren.length > 0) {
558
- data.children = grandChildren
559
- }
560
- ftus.push(data)
561
- })
562
- }
563
- return ftus
564
- }
565
-
566
- const processSystems = (systems) => {
567
- const allSystems = []
568
- if (systems && systems.length > 0) {
569
- const data = { label: 'All', key: 'All', children: [] }
570
- systems.forEach((system) => {
571
- const child = {
572
- colour: system.colour,
573
- enabled: system.enabled,
574
- label: system.id,
575
- key: system.id,
576
- }
577
- const children = processFTUs(system, child.key)
578
- if (children.length > 0) child.children = children
579
- data.children.push(child)
580
- })
581
-
582
- allSystems.push(data)
583
- }
584
-
585
- return allSystems
586
- }
587
-
588
- const createUnfilledTooltipData = function () {
589
- return {
590
- destinations: [],
591
- origins: [],
592
- components: [],
593
- destinationsWithDatasets: [],
594
- originsWithDatasets: [],
595
- componentsWithDatasets: [],
596
- resource: undefined,
597
- }
598
- }
599
-
600
- /**
601
- * A vue component of the flatmap viewer.
602
- */
603
- export default {
604
- name: 'FlatmapVuer',
605
- components: {
606
- Button,
607
- Col,
608
- Loading,
609
- Radio,
610
- RadioGroup,
611
- Row,
612
- Select,
613
- MapSvgIcon,
614
- MapSvgSpriteColor,
615
- Tooltip,
616
- TreeControls,
617
- SelectionsGroup,
618
- SvgLegends,
619
- ElIconWarningFilled,
620
- ElIconArrowDown,
621
- ElIconArrowLeft,
622
- },
623
- beforeCreate: function () {
624
- this.mapManager = undefined
625
- this.mapImp = undefined
626
- //The state watcher may triggered before
627
- //created causing issue, This flag will
628
- //resolve this issue.
629
- this.setStateRequired = false
630
- },
631
- methods: {
632
- /**
633
- * @vuese
634
- * Function to switch from 2D to 3D
635
- * @arg flag
636
- */
637
- setFlightPath3D: function (flag) {
638
- this.flightPath3DRadio = flag
639
- if (this.mapImp) {
640
- this.mapImp.enableFlightPaths(flag)
641
- }
642
- },
643
- /**
644
- * @vuese
645
- * Function to view the latest map (example when you are on legacy map).
646
- */
647
- viewLatestMap: function () {
648
- let biologicalSex = this.biologicalSex ? this.biologicalSex : undefined
649
- //Human requires special handling
650
- if (this.entry === 'NCBITaxon:9606') {
651
- biologicalSex = 'PATO:0000384'
652
- }
653
- const state = {
654
- entry: this.entry,
655
- biologicalSex,
656
- viewport: this.mapImp.getState(),
657
- }
658
- /**
659
- * The event emitted by ``viewLatestMap`` method.
660
- */
661
- this.$emit('view-latest-map', state)
662
- },
663
- /**
664
- * @vuese
665
- * Function to change the background colour of the map
666
- * by providing the ``colour``.
667
- * @arg colour
668
- */
669
- backgroundChangeCallback: function (colour) {
670
- this.currentBackground = colour
671
- if (this.mapImp) {
672
- this.mapImp.setBackgroundColour(this.currentBackground, 1)
673
- }
674
- },
675
- /**
676
- * @vuese
677
- * Function to process a list of a FC flatmap's systems.
678
- * @arg systems
679
- */
680
- processSystems: function (systems) {
681
- this.systems.length = 0
682
- if (systems && systems.length > 0) {
683
- const data = { label: 'All', key: 'All', children: [] }
684
- systems.forEach((system) => {
685
- const child = {
686
- colour: system.colour,
687
- enabled: system.enabled,
688
- label: system.id,
689
- key: system.id,
690
- }
691
- const children = processFTUs(system, child.key)
692
- if (children.length > 0) child.children = children
693
- data.children.push(child)
694
- })
695
-
696
- this.systems.push(data)
697
- }
698
- },
699
- /**
700
- * @vuese
701
- * Function to add taxon identifiers into the taxon connectivity array,
702
- * by retrieving their corresponding labels using the flatmap API.
703
- * @arg flatmapAPI,
704
- * @arg taxonIdentifiers
705
- */
706
- processTaxon: function (flatmapAPI, taxonIdentifiers) {
707
- this.taxonConnectivity.length = 0
708
- taxonIdentifiers.forEach((taxon) => {
709
- findTaxonomyLabel(flatmapAPI, taxon).then((value) => {
710
- const item = { taxon, label: value }
711
- this.taxonConnectivity.push(item)
712
- })
713
- })
714
- },
715
- /**
716
- * @vuese
717
- * Function to show or hide the display of the bottom-left drawer container.
718
- */
719
- toggleDrawer: function () {
720
- this.drawerOpen = !this.drawerOpen
721
- },
722
- /**
723
- * @vuese
724
- * Function to toggle colour/greyscale of organs.
725
- * The parameter ``flag`` is a boolean, ``true`` (colour) and ``false`` (greyscale).
726
- * @arg flag
727
- */
728
- setColour: function (flag) {
729
- this.colourRadio = flag
730
- if (this.mapImp) {
731
- this.mapImp.setColour({ colour: flag, outline: this.outlinesRadio })
732
- }
733
- },
734
- /**
735
- * @vuese
736
- * Function to toggle outlines f organs.
737
- * The parameter ``flag`` is a boolean, ``true`` to show outlines, ``false`` to hide outlines.
738
- * @arg flag
739
- */
740
- setOutlines: function (flag) {
741
- this.outlineRadio = flag
742
- if (this.mapImp) {
743
- this.mapImp.setColour({ colour: this.colourRadio, outline: flag })
744
- }
745
- },
746
- /**
747
- * @vuese
748
- * Function to toggle paths to default.
749
- * Also called when the associated button is pressed.
750
- */
751
- resetView: function () {
752
- if (this.mapImp) {
753
- this.mapImp.resetMap()
754
- if (this.$refs.centrelinesSelection) {
755
- this.$refs.centrelinesSelection.reset()
756
- }
757
- if (this.$refs.skcanSelection) {
758
- this.$refs.skcanSelection.reset()
759
- }
760
- if (this.$refs.layersSelection) {
761
- this.$refs.layersSelection.reset()
762
- }
763
- if (this.$refs.systemsSelection) {
764
- this.$refs.pathwaysSelection.reset()
765
- }
766
- if (this.$refs.pathwaysSelection) {
767
- this.$refs.pathwaysSelection.reset()
768
- }
769
- }
770
- },
771
- /**
772
- * @vuese
773
- * Function to zoom in.
774
- * Also called when the associated button is pressed.
775
- */
776
- zoomIn: function () {
777
- if (this.mapImp) {
778
- this.mapImp.zoomIn()
779
- }
780
- },
781
- /**
782
- * @vuese
783
- * Function to zoom out.
784
- * Also called when the associated button is pressed.
785
- */
786
- zoomOut: function () {
787
- if (this.mapImp) {
788
- this.mapImp.zoomOut()
789
- }
790
- },
791
- /**
792
- * @vuese
793
- * Function to show or hide centrelines and nodes.
794
- * The parameter ``payload`` is an object with a boolean property, ``value``,
795
- * ``payload.value = true/false``.
796
- * @arg payload
797
- */
798
- centreLinesSelected: function (payload) {
799
- if (this.mapImp) {
800
- this.mapImp.enableCentrelines(payload.value)
801
- }
802
- },
803
- /**
804
- * // Currently not in use
805
- * Function to show or hide paths valid in SCKAN
806
- * by providing ``{key, value}`` pair in ``payload``.
807
- * @arg payload
808
- */
809
- sckanSelected: function (payload) {
810
- if (this.mapImp) {
811
- this.mapImp.enableSckanPath(payload.key, payload.value)
812
- }
813
- },
814
- /**
815
- * // Currently not in use
816
- * Function to show or hide all paths valid in SCKAN.
817
- * @arg payload
818
- */
819
- checkAllSCKAN: function (payload) {
820
- if (this.mapImp) {
821
- payload.keys.forEach((key) =>
822
- this.mapImp.enableSckanPath(key, payload.value)
823
- )
824
- }
825
- },
826
- /**
827
- * @vuese
828
- * Function to highlight the connected paths
829
- * by providing path model identifier, ``pathId``.
830
- * @arg pathId
831
- */
832
- highlightConnectedPaths: function (payload) {
833
- if (this.mapImp) {
834
- let paths = [...this.mapImp.pathModelNodes(payload)]
835
- // The line below matches the paths to the annIdToFeatureId map to get the feature ids
836
-
837
- let pathFeatures = paths.map((p) => this.mapImp.featureProperties(p))
838
- let toHighlight = []
839
- pathFeatures.forEach((p) => {
840
- this.mapImp.nodePathModels(p.featureId).forEach((f) => {
841
- toHighlight.push(f)
842
- })
843
- })
844
- // display connected paths
845
- this.mapImp.zoomToFeatures(toHighlight, { noZoomIn: true })
846
- }
847
- },
848
- /**
849
- * @vuese
850
- * Function to enable/disable (show/hide) the system
851
- * by providing ``kay, value`` ``payload`` object ``{systemId, true/false}``.
852
- * @arg payload
853
- */
854
- systemSelected: function (payload) {
855
- if (this.mapImp) {
856
- this.mapImp.enableSystem(payload.key, payload.value)
857
- }
858
- },
859
- /**
860
- * @vuese
861
- * Function to enable/disable (show/hide) all systems
862
- * by providing ``flag`` (true/false).
863
- * @arg flag
864
- */
865
- checkAllSystems: function (flag) {
866
- if (this.mapImp) {
867
- this.systems[0].children.forEach((key) =>
868
- this.mapImp.enableSystem(key.label, flag)
869
- )
870
- }
871
- },
872
- /**
873
- * @vuese
874
- * Function to display features with annotation matching the provided term.
875
- * @arg models
876
- */
877
- ftuSelected: function (models) {
878
- this.searchAndShowResult(models, true)
879
- },
880
- /**
881
- * @vuese
882
- * Function to show or hide the layer
883
- * by providing ``{layerId, true/false}`` in ``payload``.
884
- * @arg payload
885
- */
886
- layersSelected: function (payload) {
887
- if (this.mapImp) {
888
- this.mapImp.enableLayer(payload.key, payload.value)
889
- }
890
- },
891
- /**
892
- * @vuese
893
- * Function to show or hide all layers
894
- * by providing ``payload`` with ``payload.keys`` array and ``payload.value`` flag.
895
- * @arg payload
896
- */
897
- checkAllLayers: function (payload) {
898
- if (this.mapImp) {
899
- payload.keys.forEach((key) =>
900
- this.mapImp.enableLayer(key, payload.value)
901
- )
902
- }
903
- },
904
- /**
905
- * @vuese
906
- * Function to show or hide connectivity features observed in particular species
907
- * by providing ``{taxonId, true/false}`` in ``payload.key, payload.value``.
908
- * @arg payload
909
- */
910
- taxonsSelected: function (payload) {
911
- if (this.mapImp) {
912
- this.mapImp.enableConnectivityByTaxonIds(payload.key, payload.value)
913
- }
914
- },
915
- /**
916
- * @vuese
917
- * Function to show or hide connectivity features observed in particular species
918
- * by providing ``payload`` with ``payload.keys`` array and ``payload.value`` flag.
919
- * @arg payload
920
- */
921
- checkAllTaxons: function (payload) {
922
- if (this.mapImp) {
923
- payload.keys.forEach((key) =>
924
- this.mapImp.enableConnectivityByTaxonIds(key, payload.value)
925
- )
926
- }
927
- },
928
- /**
929
- * @vuese
930
- * Function to hide or show paths of a given type
931
- * by providing ``{pathType, true/false}`` in ``payload.key, payload.value``.
932
- * @arg payload
933
- */
934
- pathwaysSelected: function (payload) {
935
- if (this.mapImp) {
936
- this.mapImp.enablePath(payload.key, payload.value)
937
- }
938
- },
939
- /**
940
- * @vuese
941
- * Function to hide or show paths of a given type
942
- * by providing ``payload`` with ``payload.keys`` array and ``payload.value`` flag.
943
- * @arg payload
944
- */
945
- checkAllPathways: function (payload) {
946
- if (this.mapImp) {
947
- payload.keys.forEach((key) =>
948
- this.mapImp.enablePath(key, payload.value)
949
- )
950
- }
951
- },
952
- /**
953
- * @vuese
954
- * Function to generate callbacks as a result of panning/zooming the map.
955
- * ``flag`` (boolean) - generate callbacks when ``true``, otherwise disable them.
956
- * @arg flag
957
- */
958
- enablePanZoomEvents: function (flag) {
959
- this.mapImp.enablePanZoomEvents(flag)
960
- },
961
- /**
962
- * @vuese
963
- * A callback function, invoked when events occur with the map.
964
- * The first parameter gives the type of event, the second provides details about the event.
965
- * _(This is the ``callback`` function from ``MapManager.loadMap()``)_.
966
- */
967
- eventCallback: function () {
968
- return (eventType, data, ...args) => {
969
- if (eventType !== 'pan-zoom') {
970
- const label = data.label
971
- const resource = [data.models]
972
- const taxonomy = this.entry
973
- const biologicalSex = this.biologicalSex
974
- let taxons = undefined
975
- if (data.taxons) {
976
- // check if data.taxons is string or array
977
- if (typeof data.taxons !== 'object') {
978
- taxons = JSON.parse(data.taxons)
979
- } else {
980
- taxons = data.taxons
981
- }
982
- }
983
- const payload = {
984
- dataset: data.dataset,
985
- biologicalSex: biologicalSex,
986
- taxonomy: taxonomy,
987
- resource: resource,
988
- label: label,
989
- feature: data,
990
- userData: args,
991
- eventType: eventType,
992
- provenanceTaxonomy: taxons,
993
- }
994
- if (eventType === 'click') {
995
- if (this.viewingMode === 'Network Discovery') {
996
- this.highlightConnectedPaths([data.models])
997
- } else {
998
- this.currentActive = data.models ? data.models : ''
999
- }
1000
- } else if (
1001
- eventType === 'mouseenter' &&
1002
- !(this.viewingMode === 'Network Discovery')
1003
- ) {
1004
- this.currentHover = data.models ? data.models : ''
1005
- }
1006
- if (
1007
- data &&
1008
- data.type !== 'marker' &&
1009
- eventType === 'click' &&
1010
- !(this.viewingMode === 'Network Discovery')
1011
- ) {
1012
- this.checkAndCreatePopups(payload)
1013
- }
1014
- /**
1015
- * The event emitted from the mouse event callbacks that come from flatmap-viewer. The payload
1016
- * argument provides an object with information on the feature where the mouse event takes place.
1017
- * @arg payload
1018
- */
1019
- this.$emit('resource-selected', payload)
1020
- } else {
1021
- /**
1022
- * The event emitted in ``callback`` function from ``MapManager.loadMap()``
1023
- * if ``eventType`` is ``pan-zoom``.
1024
- * @arg data
1025
- */
1026
- this.$emit('pan-zoom-callback', data)
1027
- }
1028
- }
1029
- },
1030
- /**
1031
- * @vuese
1032
- * Function to create/display tooltips from the provided ``data``.
1033
- * _checkNeuronClicked shows a neuron path pop up if a path was recently clicked._
1034
- * @arg data
1035
- */
1036
- checkAndCreatePopups: async function (data) {
1037
- // Call flatmap database to get the connection data
1038
- if (this.viewingMode === 'Annotation') {
1039
- if (data.feature && data.feature.featureId && data.feature.models) {
1040
- this.annotationEntry = {
1041
- ...data.feature,
1042
- resource: this.serverURL,
1043
- resourceId: this.serverUUID,
1044
- }
1045
- this.displayTooltip(data.feature.models)
1046
- } else {
1047
- this.annotation = {}
1048
- }
1049
- } else {
1050
- let results =
1051
- await this.flatmapQueries.retrieveFlatmapKnowledgeForEvent(data)
1052
- // The line below only creates the tooltip if some data was found on the path
1053
- // result 0 is the connection, result 1 is the pubmed results from flatmap
1054
- if (
1055
- results[0] ||
1056
- results[1] ||
1057
- (data.feature.hyperlinks && data.feature.hyperlinks.length > 0)
1058
- ) {
1059
- this.resourceForTooltip = data.resource[0]
1060
- data.resourceForTooltip = this.resourceForTooltip
1061
- this.createTooltipFromNeuronCuration(data)
1062
- }
1063
- }
1064
- },
1065
- /**
1066
- * A hack to remove flatmap tooltips while popup is open
1067
- */
1068
- popUpCssHacks: function () {
1069
- // Below is a hack to remove flatmap tooltips while popup is open
1070
- let ftooltip = document.querySelector('.flatmap-tooltip-popup')
1071
- if (ftooltip) ftooltip.style.display = 'none'
1072
- document.querySelector('.maplibregl-popup-close-button').style.display =
1073
- 'block'
1074
- this.$refs.tooltip.$el.style.display = 'flex'
1075
- document.querySelector('.maplibregl-popup-close-button').onclick = () => {
1076
- document.querySelector('.flatmap-tooltip-popup').style.display = 'block'
1077
- }
1078
- },
1079
- /**
1080
- * @vuese
1081
- * Function to close tooltip.
1082
- */
1083
- closeTooltip: function () {
1084
- this.$refs.tooltip.$el.style.display = 'none'
1085
- document.querySelectorAll('.maplibregl-popup').forEach((item) => {
1086
- item.style.display = 'none'
1087
- })
1088
- },
1089
- /**
1090
- * @vuese
1091
- * Function to create tooltip from Neuron Curation ``data``.
1092
- * @arg data
1093
- */
1094
- createTooltipFromNeuronCuration: async function (data) {
1095
- this.tooltipEntry = await this.flatmapQueries.createTooltipData(data)
1096
- this.displayTooltip(data.resource[0])
1097
- },
1098
- /**
1099
- * @vuese
1100
- * Function to show popup on map.
1101
- * @arg featureId,
1102
- * @arg node,
1103
- * @arg options
1104
- */
1105
- showPopup: function (featureId, node, options) {
1106
- // Keeping this as an API
1107
- let myOptions = options
1108
- if (this.mapImp) {
1109
- if (myOptions) {
1110
- if (!myOptions.className) myOptions.className = 'custom-popup'
1111
- } else {
1112
- myOptions = { className: 'custom-popup', positionAtLastClick: true }
1113
- }
1114
- this.mapImp.showPopup(featureId, node, myOptions)
1115
- }
1116
- },
1117
- /**
1118
- * @vuese
1119
- * Function to show marker popup.
1120
- * @arg featureId,
1121
- * @arg node,
1122
- * @arg options
1123
- */
1124
- showMarkerPopup: function (featureId, node, options) {
1125
- if (this.mapImp) {
1126
- this.mapImp.showMarkerPopup(featureId, node, options)
1127
- }
1128
- },
1129
- /**
1130
- * @vuese
1131
- * Function to close minimap.
1132
- */
1133
- closeMinimap: function () {
1134
- let minimapEl = this.$refs.flatmapContainer.querySelector(
1135
- '.maplibregl-ctrl-minimap'
1136
- ) // find minimap
1137
- if (this.minimapSmall) {
1138
- //switch the classes on the minimap
1139
- minimapEl.classList.add('enlarge')
1140
- minimapEl.classList.remove('shrink')
1141
- } else {
1142
- minimapEl.classList.add('shrink')
1143
- minimapEl.classList.remove('enlarge')
1144
- }
1145
- this.minimapSmall = !this.minimapSmall
1146
- },
1147
- /**
1148
- * Function to add resize button to minimap.
1149
- */
1150
- addResizeButtonToMinimap: function () {
1151
- let minimapEl = this.$refs.flatmapContainer.querySelector(
1152
- '.maplibregl-ctrl-minimap'
1153
- )
1154
- if (minimapEl) {
1155
- if (this.$refs.minimapResize &&
1156
- this.$refs.minimapResize.$el.parentNode) {
1157
- this.$refs.minimapResize.$el.parentNode.removeChild(
1158
- this.$refs.minimapResize.$el)
1159
- }
1160
- minimapEl.appendChild(this.$refs.minimapResize.$el)
1161
- this.minimapResizeShow = true
1162
- }
1163
- },
1164
- /**
1165
- * @vuese
1166
- * Function to set help mode
1167
- * by providing flag ``helpMode`` (true/false).
1168
- * @arg helpMode
1169
- */
1170
- setHelpMode: function (helpMode) {
1171
- if (helpMode) {
1172
- this.inHelp = true
1173
- this.hoverVisibilities.forEach((item) => {
1174
- item.value = true
1175
- })
1176
- this.openFlatmapHelpPopup()
1177
- } else {
1178
- this.inHelp = false
1179
- this.hoverVisibilities.forEach((item) => {
1180
- item.value = false
1181
- })
1182
- this.closeFlatmapHelpPopup()
1183
- }
1184
- },
1185
- /**
1186
- * @vuese
1187
- * Function to show tooltip
1188
- * by providing ``tooltipNumber``.
1189
- * @arg tooltipNumber
1190
- */
1191
- showToolitip: function (tooltipNumber) {
1192
- if (!this.inHelp) {
1193
- clearTimeout(this.tooltipWait[tooltipNumber])
1194
- this.tooltipWait[tooltipNumber] = setTimeout(() => {
1195
- this.hoverVisibilities[tooltipNumber].value = true
1196
- }, 500)
1197
- }
1198
- },
1199
- /**
1200
- * @vuese
1201
- * Function to hide tooltip
1202
- * by providing ``tooltipNumber``.
1203
- * @arg tooltipNumber
1204
- */
1205
- hideToolitip: function (tooltipNumber) {
1206
- if (!this.inHelp) {
1207
- clearTimeout(this.tooltipWait[tooltipNumber])
1208
- this.tooltipWait[tooltipNumber] = setTimeout(() => {
1209
- this.hoverVisibilities[tooltipNumber].value = false
1210
- }, 500)
1211
- }
1212
- },
1213
- /**
1214
- * @vuese
1215
- * Function to display tooltip
1216
- * by providing featureId (``feature``).
1217
- * @arg feature
1218
- */
1219
- displayTooltip: function (feature) {
1220
- this.tooltipDisplay = true
1221
- if (!this.disableUI) {
1222
- this.$nextTick(() => {
1223
- this.displayPopup(feature)
1224
- });
1225
- }
1226
- },
1227
- /**
1228
- * @vuese
1229
- * Function to display popup
1230
- * by providing featureId (``feature``).
1231
- * @arg feature
1232
- */
1233
- displayPopup: function (feature) {
1234
- this.mapImp.showPopup(
1235
- this.mapImp.modelFeatureIds(feature)[0],
1236
- this.$refs.tooltip.$el,
1237
- { className: 'flatmapvuer-popover', positionAtLastClick: true }
1238
- )
1239
- this.popUpCssHacks()
1240
- },
1241
- /**
1242
- * @vuese
1243
- * Function to open Flatmap Help Popup.
1244
- */
1245
- openFlatmapHelpPopup: function () {
1246
- if (this.mapImp) {
1247
- let heartId = this.mapImp.modelFeatureIds('UBERON:0000948')
1248
- if (heartId && heartId.length > 0) {
1249
- const elm = 'Click for more information'
1250
- this.mapImp.showPopup(heartId[0], elm, {
1251
- anchor: 'top',
1252
- className: 'flatmap-popup-popper',
1253
- })
1254
- }
1255
- }
1256
- },
1257
- /**
1258
- * @vuese
1259
- * Function to close Flatmap Help Popup.
1260
- */
1261
- closeFlatmapHelpPopup: function () {
1262
- this.$el
1263
- .querySelectorAll('.maplibregl-popup-close-button')
1264
- .forEach((item) => {
1265
- item.click()
1266
- })
1267
- },
1268
- /**
1269
- * @vuese
1270
- * Function to get annotation labels.
1271
- */
1272
- getLabels: function () {
1273
- let labels = []
1274
- if (this.mapImp) {
1275
- let annotations = this.mapImp.annotations
1276
- for (let value of annotations.values()) {
1277
- if (value.label) labels.push(value.label)
1278
- }
1279
- return Array.from(new Set(labels))
1280
- }
1281
- },
1282
- /**
1283
- * @vuese
1284
- * Function to get the state (object) of the map.
1285
- */
1286
- getState: function () {
1287
- if (this.mapImp) {
1288
- let state = {
1289
- entry: this.entry,
1290
- viewport: this.mapImp.getState(),
1291
- }
1292
- const identifier = this.mapImp.getIdentifier()
1293
- if (this.biologicalSex) state['biologicalSex'] = this.biologicalSex
1294
- else if (identifier && identifier.biologicalSex)
1295
- state['biologicalSex'] = identifier.biologicalSex
1296
- if (identifier && identifier.uuid) state['uuid'] = identifier.uuid
1297
- return state
1298
- }
1299
- return undefined
1300
- },
1301
- /**
1302
- * @vuese
1303
- * Function to set state (object) for the map.
1304
- * @arg state
1305
- */
1306
- setState: function (state) {
1307
- if (state) {
1308
- if (
1309
- this.mapImp &&
1310
- state.entry &&
1311
- this.entry == state.entry &&
1312
- (!state.biologicalSex || state.biologicalSex === this.biologicalSex)
1313
- ) {
1314
- if (state.viewport) {
1315
- this.mapImp.setState(state.viewport)
1316
- }
1317
- } else {
1318
- this.createFlatmap(state)
1319
- }
1320
- this.setStateRequired = false
1321
- }
1322
- },
1323
- /**
1324
- * @vuese
1325
- * Function to restore map's state
1326
- * from the ``state`` provided.
1327
- * @arg state
1328
- */
1329
- restoreMapState: function (state) {
1330
- if (state) {
1331
- if (state.viewport) this.mapImp.setState(state.viewport)
1332
- if (state.searchTerm) this.searchAndShowResult(state.searchTerm, true)
1333
- }
1334
- },
1335
- /**
1336
- * @vuese
1337
- * Function to show flight path option
1338
- * (3D option)
1339
- * based on the map version (currently 1.6 and above).
1340
- * @arg mapVersion
1341
- */
1342
- setFlightPathInfo: function (mapVersion) {
1343
- const mapVersionForFlightPath = 1.6
1344
- if (mapVersion === mapVersionForFlightPath || mapVersion > mapVersionForFlightPath) {
1345
- // Show flight path option UI
1346
- this.displayFlightPathOption = true
1347
- // Show 2D as default on FC type
1348
- this.setFlightPath3D(false)
1349
- }
1350
- },
1351
- /**
1352
- * @vuese
1353
- * Function to create Flatmap
1354
- * by providing the ``state``.
1355
- * @arg state
1356
- */
1357
- createFlatmap: function (state) {
1358
- if (!this.mapImp && !this.loading) {
1359
- this.loading = true
1360
- let minimap = false
1361
- if (this.displayMinimap) {
1362
- minimap = { position: 'top-right' }
1363
- }
1364
-
1365
- //As for flatmap-viewer@2.2.7, see below for the documentation
1366
- //for the identifier:
1367
-
1368
- //@arg identifier {string|Object}
1369
- // A string or object identifying the map to load. If a string its
1370
- // value can be either the map's ``uuid``, assigned at generation time,
1371
- // or taxon and biological sex identifiers of the species that the map
1372
- // represents. The latest version of a map is loaded unless it has been
1373
- // identified using a ``uuid`` (see below).
1374
- // @arg identifier.taxon {string} The taxon identifier of the species
1375
- // represented by the map. This is specified as metadata in the map's source file.
1376
- // @arg identifier.biologicalSex {string} The biological sex of the species
1377
- // represented by the map. This is specified as metadatain the map's source file.
1378
- // @arg identifier.uuid {string} The unique uuid the flatmap. If given then this exact map will
1379
- // be loaded, overriding ``taxon`` and ``biologicalSex``.
1380
-
1381
- let identifier = { taxon: this.entry }
1382
- if (this.uuid) {
1383
- identifier.uuid = this.uuid
1384
- }
1385
- //This now handle the uses of uuid when resuming states
1386
- if (state) {
1387
- if (state.uuid) {
1388
- identifier = { uuid: state.uuid }
1389
- } else if (state.entry) {
1390
- identifier.taxon = state.entry
1391
- if (state.biologicalSex) {
1392
- identifier['biologicalSex'] = state.biologicalSex
1393
- } else if (identifier.taxon === 'NCBITaxon:9606') {
1394
- //For backward compatibility
1395
- identifier['biologicalSex'] = 'PATO:0000384'
1396
- }
1397
- }
1398
- } else {
1399
- // Set the bioloicalSex now if map is not resumed from
1400
- // a saved state
1401
- if (this.biologicalSex) {
1402
- identifier['biologicalSex'] = this.biologicalSex
1403
- }
1404
- }
1405
-
1406
- let promise1 = this.mapManager.loadMap(
1407
- identifier,
1408
- this.$refs.display,
1409
- this.eventCallback(),
1410
- {
1411
- //fullscreenControl: false,
1412
- //annotatable: false,
1413
- //debug: true,
1414
- minZoom: this.minZoom,
1415
- tooltips: this.tooltips,
1416
- minimap: minimap,
1417
- }
1418
- )
1419
- promise1.then((returnedObject) => {
1420
- this.mapImp = returnedObject
1421
- this.serverUUID = this.mapImp.getIdentifier().uuid
1422
- this.serverURL = this.mapImp.makeServerUrl('').slice(0, -1)
1423
- let mapVersion = this.mapImp.details.version
1424
- this.setFlightPathInfo(mapVersion)
1425
- this.onFlatmapReady()
1426
- if (this._stateToBeSet) this.restoreMapState(this._stateToBeSet)
1427
- else {
1428
- this.restoreMapState(state)
1429
- }
1430
- })
1431
- } else if (state) {
1432
- this._stateToBeSet = {
1433
- viewport: state.viewport,
1434
- searchTerm: state.searchTerm,
1435
- }
1436
- if (this.mapImp && !this.loading)
1437
- this.restoreMapState(this._stateToBeSet)
1438
- }
1439
- },
1440
- /**
1441
- * @vuese
1442
- * Function to compute path controls maximum height.
1443
- */
1444
- computePathControlsMaximumHeight() {
1445
- const elem = this.$refs.display
1446
- if (elem) {
1447
- const computed = getComputedStyle(elem)
1448
- const padding =
1449
- parseInt(computed.paddingTop) + parseInt(computed.paddingBottom)
1450
- const height = elem.clientHeight - padding
1451
- this.pathwaysMaxHeight = height - 170
1452
- }
1453
- },
1454
- /**
1455
- * @vuese
1456
- * Function to resize the map.
1457
- */
1458
- mapResize: function () {
1459
- try {
1460
- this.computePathControlsMaximumHeight()
1461
- if (this.mapImp) {
1462
- this.mapImp.resize()
1463
- this.showMinimap(this.displayMinimap)
1464
- if (this.mapImp._minimap) {
1465
- this.mapImp._minimap._miniMap.resize()
1466
- }
1467
- }
1468
- } catch {
1469
- console.error('Map resize error')
1470
- }
1471
- },
1472
- /**
1473
- * @vuese
1474
- * This function is used for functions that need to run immediately after the flatmap is loaded.
1475
- */
1476
- onFlatmapReady: function () {
1477
- // onFlatmapReady is used for functions that need to run immediately after the flatmap is loaded
1478
- this.sensor = new ResizeSensor(this.$refs.display, this.mapResize)
1479
- if (this.mapImp.options && this.mapImp.options.style === 'functional') {
1480
- this.isFC = true
1481
- }
1482
- this.mapImp.setBackgroundOpacity(1)
1483
- this.backgroundChangeCallback(this.currentBackground)
1484
- this.pathways = this.mapImp.pathTypes()
1485
- this.mapImp.enableCentrelines(false)
1486
- //Disable layers for now
1487
- //this.layers = this.mapImp.getLayers();
1488
- this.processSystems(this.mapImp.getSystems())
1489
- this.processTaxon(this.flatmapAPI, this.mapImp.taxonIdentifiers)
1490
- this.addResizeButtonToMinimap()
1491
- this.loading = false
1492
- this.computePathControlsMaximumHeight()
1493
- this.drawerOpen = true
1494
- this.mapResize()
1495
- /**
1496
- * This is ``onFlatmapReady`` event.
1497
- * @arg ``this`` (Component Vue Instance)
1498
- */
1499
- this.$emit('ready', this)
1500
- },
1501
- /**
1502
- * @vuese
1503
- * Function to show or hide the minimap
1504
- * by providing ``flag`` (boolean) value.
1505
- * @arg flag
1506
- */
1507
- showMinimap: function (flag) {
1508
- if (this.mapImp) this.mapImp.showMinimap(flag)
1509
- },
1510
- /**
1511
- * @vuese
1512
- * Function to show or hide the pathways drawer
1513
- * by providing ``flag`` (boolean) value.
1514
- * @arg flag
1515
- */
1516
- showPathwaysDrawer: function (flag) {
1517
- this.drawerOpen = flag
1518
- },
1519
- /**
1520
- * @vuese
1521
- * Function to display features with annotation matching the provided term,
1522
- * with the option to display the label using displayLabel flag.
1523
- * @arg term,
1524
- * @arg displayLabel
1525
- */
1526
- searchAndShowResult: function (term, displayLabel) {
1527
- if (this.mapImp) {
1528
- if (term === undefined || term === '') {
1529
- this.mapImp.clearSearchResults()
1530
- return true
1531
- } else {
1532
- const searchResults = this.mapImp.search(term)
1533
- if (
1534
- searchResults &&
1535
- searchResults.results &&
1536
- searchResults.results.length > 0
1537
- ) {
1538
- this.mapImp.showSearchResults(searchResults)
1539
- if (
1540
- displayLabel &&
1541
- searchResults.results[0].featureId &&
1542
- searchResults.results[0].text
1543
- ) {
1544
- const annotation = this.mapImp.annotation(
1545
- searchResults.results[0].featureId
1546
- )
1547
- this.mapImp.showPopup(
1548
- searchResults.results[0].featureId,
1549
- annotation.label,
1550
- {
1551
- className: 'custom-popup',
1552
- positionAtLastClick: false,
1553
- preserveSelection: true,
1554
- }
1555
- )
1556
- }
1557
- return true
1558
- } else this.mapImp.clearSearchResults()
1559
- }
1560
- }
1561
- return false
1562
- },
1563
- /**
1564
- * @vuese
1565
- * Function to show search suggestions
1566
- * from the ``term`` provided.
1567
- * @arg term
1568
- */
1569
- searchSuggestions: function (term) {
1570
- if (this.mapImp) return this.mapImp.search(term)
1571
- return []
1572
- },
1573
- },
1574
- props: {
1575
- /**
1576
- * The taxon identifier of the species represented by the map.
1577
- */
1578
- entry: {
1579
- type: String,
1580
- required: true,
1581
- },
1582
- /**
1583
- * The unique ``uuid`` of the flatmap.
1584
- * If given then this exact map will be loaded,
1585
- * overriding ``taxon`` and ``biologicalSex``.
1586
- */
1587
- uuid: String,
1588
- /**
1589
- * The biological sex of the species represented by the map.
1590
- * This is specified as metadata in the map's source file.
1591
- */
1592
- biologicalSex: {
1593
- type: String,
1594
- default: '',
1595
- },
1596
- /**
1597
- * The minimum zoom level of the map.
1598
- */
1599
- minZoom: {
1600
- type: Number,
1601
- default: 4,
1602
- },
1603
- /**
1604
- * The option to add another feature label _(`FeatureSmallSymbolLayer`)_
1605
- * when this `tooltips` is set to `false`.
1606
- */
1607
- tooltips: {
1608
- type: Boolean,
1609
- default: true,
1610
- },
1611
- /**
1612
- * The option to show tooltips for help mode.
1613
- */
1614
- helpMode: {
1615
- type: Boolean,
1616
- default: false,
1617
- },
1618
- /**
1619
- * The option to create map on component mounted.
1620
- */
1621
- renderAtMounted: {
1622
- type: Boolean,
1623
- default: true,
1624
- },
1625
- /**
1626
- * The option to display minimap at the top-right corner of the map.
1627
- */
1628
- displayMinimap: {
1629
- type: Boolean,
1630
- default: false,
1631
- },
1632
- /**
1633
- * The option to show warning. Example for legacy or beta maps.
1634
- */
1635
- displayWarning: {
1636
- type: Boolean,
1637
- default: false,
1638
- },
1639
- /**
1640
- * Flag to determine rather open map UI should be
1641
- * presented or not.
1642
- */
1643
- enableOpenMapUI: {
1644
- type: Boolean,
1645
- default: false,
1646
- },
1647
- /**
1648
- * The data to show different map options.
1649
- * Available at the bottom-left corner ("Open new map" tooltip).
1650
- */
1651
- openMapOptions: {
1652
- type: Array,
1653
- /**
1654
- * ```[
1655
- {
1656
- display: 'Open AC Map',
1657
- key: 'AC',
1658
- },
1659
- {
1660
- display: 'Open FC Map',
1661
- key: 'FC',
1662
- },
1663
- {
1664
- display: 'Open 3D Human Map',
1665
- key: '3D',
1666
- },
1667
- ]```
1668
- */
1669
- default: function () {
1670
- return [
1671
- {
1672
- display: 'Open AC Map',
1673
- key: 'AC',
1674
- },
1675
- {
1676
- display: 'Open FC Map',
1677
- key: 'FC',
1678
- },
1679
- {
1680
- display: 'Open 3D Human Map',
1681
- key: '3D',
1682
- },
1683
- ]
1684
- },
1685
- },
1686
- /**
1687
- * The option to show star in legend area.
1688
- */
1689
- showStarInLegend: {
1690
- type: Boolean,
1691
- default: false,
1692
- },
1693
- /**
1694
- * Flag to determine whether this is legacy map or not.
1695
- * ``displayWarning`` should be shown for legacy map.
1696
- */
1697
- isLegacy: {
1698
- type: Boolean,
1699
- default: false,
1700
- },
1701
- /**
1702
- * The option to show the latest changes.
1703
- */
1704
- displayLatestChanges: {
1705
- type: Boolean,
1706
- default: false,
1707
- },
1708
- /**
1709
- * State containing state of the flatmap.
1710
- */
1711
- state: {
1712
- type: Object,
1713
- default: undefined,
1714
- },
1715
- /**
1716
- * Specify the endpoint of the flatmap server.
1717
- */
1718
- flatmapAPI: {
1719
- type: String,
1720
- default: 'https://mapcore-demo.org/current/flatmap/v3/',
1721
- },
1722
- /**
1723
- * Specify the endpoint of the SPARC API.
1724
- */
1725
- sparcAPI: {
1726
- type: String,
1727
- default: 'https://api.sparc.science/',
1728
- },
1729
- /**
1730
- * Flag to disable UIs on Map
1731
- */
1732
- disableUI: {
1733
- type: Boolean,
1734
- default: false,
1735
- }
1736
- },
1737
- provide() {
1738
- return {
1739
- flatmapAPI: this.flatmapAPI,
1740
- sparcAPI: this.sparcAPI,
1741
- userApiKey: this.userToken
1742
- }
1743
- },
1744
- data: function () {
1745
- return {
1746
- annotationEntry: {},
1747
- //tooltip display has to be set to false until it is rendered
1748
- //for the first time, otherwise it may display an arrow at a
1749
- //undesired location.
1750
- tooltipDisplay: false,
1751
- serverUUID: undefined,
1752
- serverURL: undefined,
1753
- layers: [],
1754
- pathways: [],
1755
- sckanDisplay: [
1756
- {
1757
- label: 'Display Path with SCKAN',
1758
- key: 'VALID',
1759
- },
1760
- ],
1761
- centreLines: [
1762
- {
1763
- label: 'Display Nerves',
1764
- key: 'centrelines',
1765
- enabled: false,
1766
- },
1767
- ],
1768
- systems: [],
1769
- taxonConnectivity: [],
1770
- pathwaysMaxHeight: 1000,
1771
- hoverVisibilities: [
1772
- { value: false },
1773
- { value: false },
1774
- { value: false },
1775
- { value: false },
1776
- { value: false },
1777
- { value: false },
1778
- { value: false },
1779
- { value: false },
1780
- { value: false },
1781
- { value: false },
1782
- ],
1783
- yellowstar: yellowstar,
1784
- isFC: false,
1785
- inHelp: false,
1786
- currentBackground: 'white',
1787
- availableBackground: ['white', 'lightskyblue', 'black'],
1788
- loading: false,
1789
- flatmapMarker: flatmapMarker,
1790
- tooltipEntry: createUnfilledTooltipData(),
1791
- connectivityTooltipVisible: false,
1792
- drawerOpen: false,
1793
- annotationRadio: false,
1794
- flightPath3DRadio: false,
1795
- displayFlightPathOption: false,
1796
- colourRadio: true,
1797
- outlinesRadio: true,
1798
- minimapResizeShow: false,
1799
- minimapSmall: false,
1800
- currentActive: '',
1801
- currentHover: '',
1802
- viewingMode: 'Exploration',
1803
- viewingModes: ['Annotation', 'Exploration', 'Network Discovery'],
1804
- openMapRef: undefined,
1805
- backgroundIconRef: undefined,
1806
- }
1807
- },
1808
- computed: {
1809
- ...mapState(useMainStore, ['userToken']),
1810
- },
1811
- watch: {
1812
- entry: function () {
1813
- if (!this.state) this.createFlatmap()
1814
- },
1815
- helpMode: function (newVal, oldVal) {
1816
- if (newVal !== oldVal) {
1817
- this.setHelpMode(val)
1818
- }
1819
- },
1820
- state: {
1821
- handler: function (state, oldVal) {
1822
- if (state !== oldVal) {
1823
- if (this.mapManager) {
1824
- this.setState(state)
1825
- } else {
1826
- //this component has not been mounted yet
1827
- this.setStateRequired = true
1828
- }
1829
- }
1830
- },
1831
- immediate: true,
1832
- deep: true,
1833
- },
1834
- disableUI: function (isUIDisabled) {
1835
- if (isUIDisabled) {
1836
- this.closeTooltip()
1837
- }
1838
- }
1839
- },
1840
- mounted: function () {
1841
- this.openMapRef = shallowRef(this.$refs.openMapRef)
1842
- this.backgroundIconRef = shallowRef(this.$refs.backgroundIconRef)
1843
- this.tooltipWait = []
1844
- this.tooltipWait.length = this.hoverVisibilities.length
1845
- this.mapManager = new flatmap.MapManager(this.flatmapAPI)
1846
- this.flatmapQueries = new FlatmapQueries()
1847
- this.flatmapQueries.initialise(this.flatmapAPI)
1848
- if (this.state) {
1849
- //State is set and require to set the state
1850
- if (this.setStateRequired) {
1851
- this.setState(this.state)
1852
- }
1853
- } else if (this.renderAtMounted) {
1854
- this.createFlatmap()
1855
- }
1856
- },
1857
- }
1858
- </script>
1859
-
1860
- <style lang="scss" scoped>
1861
-
1862
- .beta-popovers {
1863
- position: absolute;
1864
- top: 90px;
1865
- left: 16px;
1866
- text-align: left;
1867
- font-size: 25px;
1868
- }
1869
-
1870
- .warning-icon {
1871
- color: $warning;
1872
-
1873
- &:hover {
1874
- cursor: pointer;
1875
- }
1876
- }
1877
-
1878
- .warning-text {
1879
- font-family: Asap, sans-serif;
1880
- font-size: 15px;
1881
- vertical-align: 5px;
1882
- }
1883
-
1884
- .latest-map-text {
1885
- color: $app-primary-color;
1886
- font-family: Asap, sans-serif;
1887
- font-size: 12px;
1888
- margin-top: 5px;
1889
- vertical-align: 10px;
1890
- cursor: pointer;
1891
- }
1892
-
1893
- .latest-changesicon {
1894
- color: $success;
1895
-
1896
- &:hover {
1897
- cursor: pointer;
1898
- }
1899
- }
1900
-
1901
- .latest-changestext {
1902
- font-family: Asap, sans-serif;
1903
- font-size: 15px;
1904
- vertical-align: 5px;
1905
- }
1906
-
1907
- .flatmap-container {
1908
- height: 100%;
1909
- width: 100%;
1910
- }
1911
-
1912
- .pathway-location {
1913
- position: absolute;
1914
- bottom: 0px;
1915
- transition: all 1s ease;
1916
- &.open {
1917
- left: 0px;
1918
- }
1919
- &.close {
1920
- left: -298px;
1921
- }
1922
- }
1923
-
1924
- .svg-legends-container {
1925
- width: 70%;
1926
- height: auto;
1927
- position: relative;
1928
- max-height: 140px;
1929
- }
1930
-
1931
- .pathway-container {
1932
- float: left;
1933
- padding-left: 16px;
1934
- padding-right: 18px;
1935
- text-align: left;
1936
- overflow: auto;
1937
- border: 1px solid rgb(220, 223, 230);
1938
- padding-bottom: 16px;
1939
- background: #ffffff;
1940
- overflow-x: hidden;
1941
- scrollbar-width: thin;
1942
-
1943
- transition: all 1s ease;
1944
- &.open {
1945
- opacity: 1;
1946
- position: relative;
1947
- z-index: 2;
1948
- }
1949
- &.close {
1950
- opacity: 0;
1951
- }
1952
-
1953
- &::-webkit-scrollbar {
1954
- width: 4px;
1955
- }
1956
-
1957
- &::-webkit-scrollbar-thumb {
1958
- border-radius: 10px;
1959
- box-shadow: inset 0 0 6px #c0c4cc;
1960
- }
1961
- }
1962
-
1963
- .flatmap-marker-help {
1964
- display: inline-block;
1965
- }
1966
-
1967
- :deep(.popper-bump-right) {
1968
- left: 30px;
1969
- }
1970
-
1971
- .el-dropdown-link {
1972
- cursor: pointer;
1973
- color: #409eff;
1974
- }
1975
- .el-icon-arrow-down {
1976
- font-size: 12px;
1977
- }
1978
- .demonstration {
1979
- display: block;
1980
- color: #8492a6;
1981
- font-size: 14px;
1982
- margin-bottom: 20px;
1983
- }
1984
-
1985
- .tooltip {
1986
- display: none;
1987
- }
1988
-
1989
- :deep(.maplibregl-popup) {
1990
- max-width: 300px !important;
1991
- }
1992
-
1993
- :deep(.flatmap-tooltip-popup) {
1994
- &.maplibregl-popup-anchor-bottom {
1995
- .maplibregl-popup-content {
1996
- margin-bottom: 12px;
1997
- &::after,
1998
- &::before {
1999
- top: 100%;
2000
- border-width: 12px;
2001
- }
2002
- /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
2003
- &::after {
2004
- margin-top: -1px;
2005
- border-color: rgb(255, 255, 255) transparent transparent transparent;
2006
- }
2007
- /* this border color controlls the outside, thin border */
2008
- &::before {
2009
- margin: 0 auto;
2010
- border-color: $app-primary-color transparent transparent transparent;
2011
- }
2012
- }
2013
- }
2014
- &.maplibregl-popup-anchor-top {
2015
- .maplibregl-popup-content {
2016
- margin-top: 18px;
2017
- &::after,
2018
- &::before {
2019
- top: calc(-100% + 6px);
2020
- border-width: 12px;
2021
- }
2022
- /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
2023
- &::after {
2024
- margin-top: 1px;
2025
- border-color: transparent transparent rgb(255, 255, 255) transparent;
2026
- }
2027
- &::before {
2028
- margin: 0 auto;
2029
- border-color: transparent transparent $app-primary-color transparent;
2030
- }
2031
- }
2032
- }
2033
- .maplibregl-popup-content {
2034
- border-radius: 4px;
2035
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
2036
- pointer-events: none;
2037
- display: none;
2038
- background: #fff;
2039
- border: 1px solid $app-primary-color;
2040
- padding-left: 6px;
2041
- padding-right: 6px;
2042
- display: flex;
2043
- justify-content: center;
2044
- align-items: center;
2045
- &::after,
2046
- &::before {
2047
- content: '';
2048
- display: block;
2049
- position: absolute;
2050
- width: 0;
2051
- height: 0;
2052
- border-style: solid;
2053
- flex-shrink: 0;
2054
- }
2055
- }
2056
- .maplibregl-popup-tip {
2057
- display: none;
2058
- }
2059
- }
2060
-
2061
- :deep(.maplibregl-popup) {
2062
- &.flatmap-marker-popup {
2063
- box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
2064
- pointer-events: auto;
2065
- background: #fff;
2066
- }
2067
- }
2068
-
2069
- /* Fix for chrome bug where under triangle pops up above one on top of it */
2070
- .selector:not(*:root),
2071
- :deep(.flatmap-tooltip-popup) {
2072
- .maplibregl-popup-content::after {
2073
- top: 99.9%;
2074
- }
2075
- }
2076
-
2077
- :deep(.flatmap-tooltip-dialog) {
2078
- .maplibregl-popup-tip {
2079
- display: none;
2080
- }
2081
- }
2082
-
2083
- :deep(.flatmap-marker-popup){
2084
- .maplibregl-popup-content {
2085
- padding: 0px;
2086
- }
2087
- }
2088
-
2089
- :deep(.flatmapvuer-popover) {
2090
- .maplibregl-popup-close-button {
2091
- position: absolute;
2092
- right: 0.5em;
2093
- top: 0;
2094
- border: 0;
2095
- border-radius: 0 3px 0 0;
2096
- cursor: pointer;
2097
- background-color: transparent;
2098
- font-size: 2.5em;
2099
- color: grey;
2100
- top: 0.95em;
2101
- }
2102
- }
2103
-
2104
- .zoomOut {
2105
- padding-left: 8px;
2106
- }
2107
-
2108
- .fitWindow {
2109
- padding-left: 8px;
2110
- }
2111
-
2112
- .yellow-star-legend {
2113
- width: 130px;
2114
- cursor: pointer;
2115
- }
2116
-
2117
- .settings-group {
2118
- bottom: 16px;
2119
- position: absolute;
2120
- transition: all 1s ease;
2121
- &.open {
2122
- left: 322px;
2123
- }
2124
- &.close {
2125
- left: 24px;
2126
- }
2127
- }
2128
-
2129
- :deep(.background-popper.el-popover.el-popper) {
2130
- padding: 5px 12px;
2131
- background-color: #ffffff;
2132
- border: 1px solid $app-primary-color;
2133
- box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.06);
2134
- height: 290px;
2135
- min-width: 200px;
2136
- .el-popper__arrow {
2137
- &:before {
2138
- border-color: $app-primary-color;
2139
- }
2140
- }
2141
- }
2142
-
2143
- :deep(.background-popper.el-popover.el-popper.h-auto) {
2144
- height: auto !important;
2145
- }
2146
-
2147
- :deep(.open-map-popper.el-popover.el-popper) {
2148
- padding-top: 5px;
2149
- padding-bottom: 5px;
2150
- background-color: #ffffff;
2151
- border: 1px solid $app-primary-color;
2152
- box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.06);
2153
- min-width: 188px;
2154
-
2155
- .el-row ~ .el-row {
2156
- margin-top: 8px;
2157
- }
2158
-
2159
- .el-button {
2160
- padding-top: 5px;
2161
- padding-bottom: 5px;
2162
- background: #f3e6f9;
2163
- border-color: $app-primary-color;
2164
- color: $app-primary-color;
2165
- }
2166
-
2167
- .el-popper__arrow {
2168
- &:before {
2169
- border-color: $app-primary-color;
2170
- }
2171
- }
2172
- }
2173
-
2174
- .backgroundText {
2175
- color: rgb(48, 49, 51);
2176
- font-size: 14px;
2177
- font-weight: normal;
2178
- line-height: 20px;
2179
- }
2180
-
2181
- .backgroundControl {
2182
- display: flex;
2183
- }
2184
-
2185
- .backgroundChoice {
2186
- width: 20px;
2187
- height: 20px;
2188
- border: 1px solid rgb(144, 147, 153);
2189
- margin-left: 20px;
2190
- &.active {
2191
- border: 2px solid $app-primary-color;
2192
- }
2193
- &:hover {
2194
- cursor: pointer;
2195
- }
2196
- &.white {
2197
- background-color: white;
2198
- margin-left: 10px;
2199
- }
2200
- &.black {
2201
- background-color: black;
2202
- }
2203
- &.lightskyblue {
2204
- background-color: lightskyblue;
2205
- }
2206
- }
2207
-
2208
- .icon-button {
2209
- height: 24px !important;
2210
- width: 24px !important;
2211
- color: $app-primary-color;
2212
-
2213
- &.open-map-button {
2214
- margin-bottom:4px;
2215
- }
2216
-
2217
- &:hover {
2218
- cursor: pointer;
2219
- }
2220
- }
2221
-
2222
- :deep(.maplibregl-ctrl-minimap) {
2223
- transform-origin: top right;
2224
- @media (max-width: 1250px) {
2225
- height: 125px !important; // important is needed here as we are over-riding the style set by the flatmap
2226
- width: 180px !important;
2227
- :deep(.maplibregl-canvas .maplibregl-canvas) {
2228
- height: 125px !important;
2229
- width: 180px !important;
2230
- }
2231
- }
2232
- @media (min-width: 1251px) {
2233
- height: 190px !important;
2234
- width: 300px !important;
2235
- :deep(.maplibregl-canvas .maplibregl-canvas) {
2236
- height: 190px !important;
2237
- width: 300px !important;
2238
- }
2239
- }
2240
- transition: all 1s ease;
2241
- &.shrink {
2242
- transform: scale(0.5);
2243
- transform: scale(0.5);
2244
- }
2245
- }
2246
-
2247
- .minimap-resize {
2248
- position: absolute;
2249
- pointer-events: all;
2250
- cursor: pointer;
2251
- top: 0;
2252
- right: 0;
2253
- padding-top: 3px; // needed as icon is offset
2254
- width: 20px;
2255
- height: 14px;
2256
- z-index: 9;
2257
- transition: all 1s ease;
2258
- &.shrink {
2259
- transform: rotate(0deg);
2260
- }
2261
- &.enlarge {
2262
- transform: rotate(180deg) scale(2);
2263
- padding-bottom: 5px; // note padding is added to the opposite side since it is rotated
2264
- padding-left: 5px;
2265
- }
2266
- }
2267
-
2268
- :deep(.flatmap-popper.el-popper) {
2269
- padding: 6px 4px;
2270
- font-size: 12px;
2271
- color: rgb(48, 49, 51);
2272
- background-color: #f3ecf6;
2273
- border: 1px solid $app-primary-color;
2274
- white-space: nowrap;
2275
- min-width: unset;
2276
- &.warning-popper {
2277
- min-width: 150px;
2278
- max-width: 400px;
2279
- word-break: keep-all;
2280
- white-space: unset;
2281
- }
2282
- .el-popper__arrow {
2283
- &:before {
2284
- border-color: $app-primary-color;
2285
- background-color: #f3ecf6;
2286
- }
2287
- }
2288
- }
2289
-
2290
- :deep(.el-loading-spinner) {
2291
- .path {
2292
- stroke: $app-primary-color;
2293
- }
2294
- .el-loading-text {
2295
- color: $app-primary-color;
2296
- }
2297
- }
2298
-
2299
- :deep(.flatmap-popup-popper) {
2300
- .maplibregl-popup-tip {
2301
- border-bottom-color: $app-primary-color;
2302
- }
2303
- .maplibregl-popup-content {
2304
- padding: 6px 4px;
2305
- font-size: 12px;
2306
- color: rgb(48, 49, 51);
2307
- background-color: #f3ecf6;
2308
- border: 1px solid $app-primary-color;
2309
- white-space: nowrap;
2310
- min-width: unset;
2311
- .maplibregl-popup-close-button {
2312
- display: none;
2313
- }
2314
- }
2315
- }
2316
-
2317
- :deep(.popper-zoomout) {
2318
- padding-right: 13px !important;
2319
- left: -21px !important;
2320
- }
2321
-
2322
- :deep(.popper-zoomout) {
2323
- .popper__arrow {
2324
- left: 53px !important;
2325
- }
2326
- }
2327
-
2328
- :deep(.maplibregl-popup-content) {
2329
- padding: 0px;
2330
- }
2331
-
2332
- .bottom-right-control {
2333
- position: absolute;
2334
- right: 16px;
2335
- bottom: 16px;
2336
- }
2337
-
2338
- :deep(.my-drawer) {
2339
- background: rgba(0, 0, 0, 0);
2340
- box-shadow: none;
2341
- }
2342
-
2343
- .drawer {
2344
- :deep(.el-drawer:focus) {
2345
- outline: none;
2346
- }
2347
- }
2348
-
2349
- .open-drawer,
2350
- .drawer-button {
2351
- z-index: 8;
2352
- width: 20px;
2353
- height: 40px;
2354
- border: solid 1px $app-primary-color;
2355
- text-align: center;
2356
- vertical-align: middle;
2357
- cursor: pointer;
2358
- pointer-events: auto;
2359
- }
2360
-
2361
- .open-drawer {
2362
- position: absolute;
2363
- left: 0px;
2364
- background-color: #f7faff;
2365
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
2366
- }
2367
-
2368
- .drawer-button {
2369
- float: left;
2370
- margin-top: calc(50% - 36px);
2371
- background-color: #f9f2fc;
2372
-
2373
- i {
2374
- font-weight: 600;
2375
- margin-top: 12px;
2376
- color: $app-primary-color;
2377
- transition-delay: 0.9s;
2378
- }
2379
- &.open {
2380
- i {
2381
- transform: rotate(0deg) scaleY(2);
2382
- }
2383
- }
2384
- &.close {
2385
- i {
2386
- transform: rotate(180deg) scaleY(2);
2387
- }
2388
- }
2389
- }
2390
-
2391
- :deep(.maplibregl-canvas-container) {
2392
- canvas {
2393
- outline: none;
2394
- }
2395
- }
2396
-
2397
- .backgroundSpacer {
2398
- border-bottom: 1px solid #e4e7ed;
2399
- margin-bottom: 10px;
2400
- }
2401
-
2402
- .flatmap-radio {
2403
- :deep(label) {
2404
- margin-right: 20px;
2405
- &:last-child {
2406
- margin-right: 0px;
2407
- }
2408
- }
2409
- :deep(.el-radio__input) {
2410
- &.is-checked {
2411
- & + .el-radio__label {
2412
- color: $app-primary-color;
2413
- }
2414
- .el-radio__inner {
2415
- border-color: $app-primary-color;
2416
- background: $app-primary-color;
2417
- }
2418
- }
2419
- .el-radio__inner:hover {
2420
- border-color: $app-primary-color;
2421
- }
2422
- }
2423
- }
2424
-
2425
- :deep(.custom-popup) {
2426
- .maplibregl-popup-tip {
2427
- display: none;
2428
- }
2429
- .maplibregl-popup-content {
2430
- border-radius: 4px;
2431
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
2432
- pointer-events: none;
2433
- display: none;
2434
- background: #fff;
2435
- font-family: 'Asap', sans-serif;
2436
- font-size: 12pt;
2437
- color: $app-primary-color;
2438
- border: 1px solid $app-primary-color;
2439
- padding-left: 6px;
2440
- padding-right: 6px;
2441
- padding-top: 6px;
2442
- padding-bottom: 6px;
2443
- display: flex;
2444
- justify-content: center;
2445
- align-items: center;
2446
- &::after,
2447
- &::before {
2448
- content: '';
2449
- display: block;
2450
- position: absolute;
2451
- width: 0;
2452
- height: 0;
2453
- border-style: solid;
2454
- flex-shrink: 0;
2455
- }
2456
- .maplibregl-popup-close-button {
2457
- display: none;
2458
- }
2459
- }
2460
- &.maplibregl-popup-anchor-bottom {
2461
- .maplibregl-popup-content {
2462
- margin-bottom: 12px;
2463
- &::after,
2464
- &::before {
2465
- top: 100%;
2466
- border-width: 12px;
2467
- }
2468
- /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
2469
- &::after {
2470
- margin-top: -1px;
2471
- border-color: rgb(255, 255, 255) transparent transparent transparent;
2472
- }
2473
- /* this border color controlls the outside, thin border */
2474
- &::before {
2475
- margin: 0 auto;
2476
- border-color: $app-primary-color transparent transparent transparent;
2477
- }
2478
- }
2479
- }
2480
- &.maplibregl-popup-anchor-top {
2481
- .maplibregl-popup-content {
2482
- margin-top: 18px;
2483
- &::after,
2484
- &::before {
2485
- top: calc(-100% + 6px);
2486
- border-width: 12px;
2487
- }
2488
- /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
2489
- &::after {
2490
- margin-top: 1px;
2491
- border-color: transparent transparent rgb(255, 255, 255) transparent;
2492
- }
2493
- &::before {
2494
- margin: 0 auto;
2495
- border-color: transparent transparent $app-primary-color transparent;
2496
- }
2497
- }
2498
- }
2499
- }
2500
-
2501
- .select-box {
2502
- border-radius: 4px;
2503
- border: 1px solid rgb(144, 147, 153);
2504
- background-color: var(--white);
2505
- font-weight: 500;
2506
- color: rgb(48, 49, 51);
2507
- width: 150px!important;
2508
- }
2509
-
2510
- :deep(.flatmap_dropdown) {
2511
- min-width: 160px !important;
2512
- .el-select-dropdown__item {
2513
- white-space: nowrap;
2514
- text-align: left;
2515
- &.is-selected {
2516
- color: $app-primary-color;
2517
- font-weight: normal;
2518
- }
2519
- }
2520
- }
2521
- </style>
2522
-
2523
- <style lang="scss">
2524
-
2525
- .flatmap-container {
2526
- --el-color-primary: #8300BF;
2527
- --el-color-primary-light-5: #CD99E5;
2528
- --el-color-primary-light-9: #F3E6F9;
2529
- --el-color-primary-dark-2: var(--el-color-primary);
2530
- }
2531
-
1
+ <template>
2
+ <div
3
+ class="flatmap-container"
4
+ ref="flatmapContainer"
5
+ v-loading="loading"
6
+ element-loading-text="Loading..."
7
+ element-loading-background="rgba(0, 0, 0, 0.3)"
8
+ >
9
+ <map-svg-sprite-color />
10
+ <div
11
+ style="height: 100%; width: 100%; position: relative; overflow-y: none"
12
+ >
13
+ <div style="height: 100%; width: 100%" ref="display"></div>
14
+ <div class="beta-popovers" v-show="!disableUI">
15
+ <div>
16
+ <el-popover
17
+ placement="right"
18
+ popper-class="warning-popper flatmap-popper"
19
+ :teleported="false"
20
+ :visible="hoverVisibilities[6].value"
21
+ ref="warningPopover"
22
+ >
23
+ <p
24
+ v-if="isLegacy"
25
+ @mouseover="showToolitip(6)"
26
+ @mouseout="hideToolitip(6)"
27
+ >
28
+ This is a legacy map, you may view the latest map instead.
29
+ </p>
30
+ <p
31
+ v-else-if="isFC"
32
+ @mouseover="showToolitip(6)"
33
+ @mouseout="hideToolitip(6)"
34
+ >
35
+ This map displays the connectivity of individual neurons.
36
+ Specifically, those which align with (parts of) the neuron
37
+ populations from the
38
+ <a
39
+ href="https://sparc.science/resources/1ZUKXU2YmLcn2reCyXjlew"
40
+ target="_blank"
41
+ >
42
+ ApiNATOMY
43
+ </a>
44
+ models available in
45
+ <a
46
+ href="https://sparc.science/resources/6eg3VpJbwQR4B84CjrvmyD"
47
+ target="_blank"
48
+ >
49
+ SCKAN </a
50
+ >.
51
+ </p>
52
+ <p v-else @mouseover="showToolitip(6)" @mouseout="hideToolitip(6)">
53
+ This map displays the connectivity of neuron populations.
54
+ Specifically, those from the primarily rat-based
55
+ <a
56
+ href="https://sparc.science/resources/1ZUKXU2YmLcn2reCyXjlew"
57
+ target="_blank"
58
+ >
59
+ ApiNATOMY
60
+ </a>
61
+ models available in
62
+ <a
63
+ href="https://sparc.science/resources/6eg3VpJbwQR4B84CjrvmyD"
64
+ target="_blank"
65
+ >
66
+ SCKAN </a
67
+ >. New connectivity and species specificity will be added as the
68
+ SPARC program progresses.
69
+ </p>
70
+ <template #reference>
71
+ <div
72
+ class="warning-icon"
73
+ v-if="displayWarning"
74
+ @mouseover="showToolitip(6)"
75
+ @mouseout="hideToolitip(6)"
76
+ >
77
+ <el-icon><el-icon-warning-filled /></el-icon>
78
+ <template v-if="isLegacy">
79
+ <span class="warning-text">Legacy Map</span>
80
+ <div class="latest-map-text" @click="viewLatestMap">
81
+ Click here for the latest map
82
+ </div>
83
+ </template>
84
+ <template v-else>
85
+ <span class="warning-text">Beta</span>
86
+ </template>
87
+ </div>
88
+ </template>
89
+ </el-popover>
90
+ </div>
91
+ <el-popover
92
+ placement="right"
93
+ v-if="displayLatestChanges"
94
+ :teleported="false"
95
+ trigger="manual"
96
+ popper-class="warning-popper flatmap-popper"
97
+ :visible="hoverVisibilities[7].value"
98
+ >
99
+ <template #reference>
100
+ <div
101
+ class="latest-changesicon"
102
+ v-if="displayLatestChanges"
103
+ @mouseover="showToolitip(7)"
104
+ @mouseout="hideToolitip(7)"
105
+ >
106
+ <el-icon><el-icon-warning-filled /></el-icon>
107
+ <span class="warning-text">What's new?</span>
108
+ </div>
109
+ </template>
110
+ <template #default>
111
+ <b>Network discovery mode</b>
112
+ <p>
113
+ You can now view the network of neurons connected to a selected
114
+ neuron. This mode is located in the settings at the bottom right.
115
+ Once discovery mode is on, click on a neuron to see its
116
+ connections.
117
+ </p>
118
+ <b>Now can display up to 6 panes</b>
119
+ <p>
120
+ You can now display up to 6 panes in the flatmap. This allows you
121
+ to compare between different datasets and/or different views of
122
+ the same dataset.
123
+ </p>
124
+ </template>
125
+ </el-popover>
126
+ </div>
127
+
128
+ <!-- The element below is placed onto the flatmap when it is ready -->
129
+ <el-icon
130
+ class="minimap-resize"
131
+ :class="{ enlarge: minimapSmall, shrink: !minimapSmall }"
132
+ ref="minimapResize"
133
+ v-show="minimapResizeShow"
134
+ @click="closeMinimap"
135
+ >
136
+ <el-icon-arrow-down />
137
+ </el-icon>
138
+
139
+ <div class="bottom-right-control" v-show="!disableUI">
140
+ <el-popover
141
+ content="Zoom in"
142
+ placement="left"
143
+ :teleported="false"
144
+ trigger="manual"
145
+ width="70"
146
+ popper-class="flatmap-popper"
147
+ :visible="hoverVisibilities[0].value"
148
+ >
149
+ <template #reference>
150
+ <map-svg-icon
151
+ icon="zoomIn"
152
+ class="icon-button zoomIn"
153
+ @click="zoomIn()"
154
+ @mouseover="showToolitip(0)"
155
+ @mouseout="hideToolitip(0)"
156
+ />
157
+ </template>
158
+ </el-popover>
159
+ <el-popover
160
+ content="Zoom out"
161
+ placement="top-end"
162
+ :teleported="false"
163
+ trigger="manual"
164
+ width="70"
165
+ popper-class="flatmap-popper popper-zoomout"
166
+ :visible="hoverVisibilities[1].value"
167
+ >
168
+ <template #reference>
169
+ <map-svg-icon
170
+ icon="zoomOut"
171
+ class="icon-button zoomOut"
172
+ @click="zoomOut()"
173
+ @mouseover="showToolitip(1)"
174
+ @mouseout="hideToolitip(1)"
175
+ />
176
+ </template>
177
+ </el-popover>
178
+ <el-popover
179
+ content="Reset"
180
+ placement="top"
181
+ :teleported="false"
182
+ trigger="manual"
183
+ width="70"
184
+ popper-class="flatmap-popper"
185
+ :visible="hoverVisibilities[2].value"
186
+ >
187
+ <div>
188
+ Fit to
189
+ <br />
190
+ window
191
+ </div>
192
+ <template #reference>
193
+ <map-svg-icon
194
+ icon="fitWindow"
195
+ class="icon-button fitWindow"
196
+ @click="resetView()"
197
+ @mouseover="showToolitip(2)"
198
+ @mouseout="hideToolitip(2)"
199
+ />
200
+ </template>
201
+ </el-popover>
202
+ </div>
203
+ <el-popover
204
+ content="Change pathway visibility"
205
+ placement="right"
206
+ :teleported="false"
207
+ trigger="manual"
208
+ popper-class="flatmap-popper"
209
+ :visible="hoverVisibilities[4].value"
210
+ ref="checkBoxPopover"
211
+ >
212
+ <template #reference>
213
+ <div
214
+ class="pathway-location"
215
+ :class="{ open: drawerOpen, close: !drawerOpen }"
216
+ v-show="!disableUI"
217
+ >
218
+ <div
219
+ class="pathway-container"
220
+ :class="{ open: drawerOpen, close: !drawerOpen }"
221
+ :style="{ 'max-height': pathwaysMaxHeight + 'px' }"
222
+ v-popover:checkBoxPopover
223
+ >
224
+ <svg-legends v-if="!isFC" class="svg-legends-container" />
225
+ <el-popover
226
+ content="Location of the featured dataset"
227
+ placement="right"
228
+ :teleported="false"
229
+ trigger="hover"
230
+ popper-class="flatmap-popper popper-bump-right"
231
+ :visible="hoverVisibilities[9].value"
232
+ ref="featuredMarkerPopover"
233
+ >
234
+ <template #reference>
235
+ <div
236
+ v-show="showStarInLegend"
237
+ v-popover:featuredMarkerPopover
238
+ class="yellow-star-legend"
239
+ v-html="yellowstar"
240
+ ></div>
241
+ </template>
242
+ </el-popover>
243
+ <!-- The line below places the yellowstar svg on the left, and the text "Featured markers on the right" with css so they are both centered in the div -->
244
+ <el-popover
245
+ content="Find these markers for data"
246
+ placement="right"
247
+ :teleported="false"
248
+ trigger="manual"
249
+ popper-class="flatmap-popper popper-bump-right"
250
+ :visible="hoverVisibilities[5].value"
251
+ ref="markerPopover"
252
+ >
253
+ <template #reference>
254
+ <div
255
+ v-show="hoverVisibilities[5].value"
256
+ class="flatmap-marker-help"
257
+ v-html="flatmapMarker"
258
+ v-popover:markerPopover
259
+ ></div>
260
+ </template>
261
+ </el-popover>
262
+ <tree-controls
263
+ v-if="isFC && systems && systems.length > 0"
264
+ :active="currentActive"
265
+ :hover="currentHover"
266
+ :tree-data="systems"
267
+ ref="treeControls"
268
+ @changed="systemSelected"
269
+ @checkAll="checkAllSystems"
270
+ @change-active="ftuSelected"
271
+ />
272
+ <selections-group
273
+ v-if="!isFC && centreLines && centreLines.length > 0"
274
+ title="Nerves"
275
+ labelKey="label"
276
+ identifierKey="key"
277
+ :selections="centreLines"
278
+ @changed="centreLinesSelected"
279
+ ref="centrelinesSelection"
280
+ key="centrelinesSelection"
281
+ />
282
+ <!--
283
+ <selections-group
284
+ v-if="isFC && sckanDisplay && sckanDisplay.length > 0"
285
+ title="SCKAN"
286
+ labelKey="label"
287
+ identifierKey="key"
288
+ :selections="sckanDisplay"
289
+ @changed="sckanSelected"
290
+ @checkAll="checkAllSCKAN"
291
+ ref="skcanSelection"
292
+ key="skcanSelection"
293
+ />
294
+ <selections-group
295
+ v-if="layers && layers.length > 0"
296
+ title="Layers"
297
+ labelKey="description"
298
+ identifierKey="id"
299
+ :selections="layers"
300
+ @changed="layersSelected"
301
+ @checkAll="checkAllLayers"
302
+ ref="layersSelection"
303
+ key="layersSelection"
304
+ />
305
+ -->
306
+ <selections-group
307
+ v-if="!isFC && taxonConnectivity && taxonConnectivity.length > 0"
308
+ title="Observed in"
309
+ labelKey="label"
310
+ identifierKey="taxon"
311
+ :selections="taxonConnectivity"
312
+ @changed="taxonsSelected"
313
+ @checkAll="checkAllTaxons"
314
+ ref="taxonSelection"
315
+ key="taxonSelection"
316
+ />
317
+ <selections-group
318
+ v-if="pathways && pathways.length > 0"
319
+ title="Pathways"
320
+ labelKey="label"
321
+ identifierKey="type"
322
+ colourStyle="line"
323
+ :selections="pathways"
324
+ @changed="pathwaysSelected"
325
+ @checkAll="checkAllPathways"
326
+ ref="pathwaysSelection"
327
+ key="pathwaysSelection"
328
+ />
329
+ </div>
330
+ <div
331
+ @click="toggleDrawer"
332
+ class="drawer-button"
333
+ :class="{ open: drawerOpen, close: !drawerOpen }"
334
+ >
335
+ <el-icon><el-icon-arrow-left /></el-icon>
336
+ </div>
337
+ </div>
338
+ </template>
339
+ </el-popover>
340
+ <el-popover
341
+ v-if="openMapRef"
342
+ ref="open-map-popover"
343
+ :virtual-ref="openMapRef"
344
+ placement="top-start"
345
+ width="136"
346
+ :teleported="false"
347
+ trigger="click"
348
+ popper-class="open-map-popper non-selectable"
349
+ virtual-triggering
350
+ >
351
+ <el-row v-for="item in openMapOptions" :key="item.key">
352
+ <el-button type="primary" plain
353
+ @click="/**
354
+ * This event is emitted when the user chooses a different map option
355
+ * from ``openMapOptions`` props.
356
+ * @arg mapOption.key
357
+ * */
358
+ $emit('open-map', item.key)"
359
+ >
360
+ {{ item.display }}
361
+ </el-button>
362
+ </el-row>
363
+ </el-popover>
364
+ <el-popover
365
+ ref="backgroundPopover"
366
+ :virtual-ref="backgroundIconRef"
367
+ placement="top-start"
368
+ width="200"
369
+ :teleported="false"
370
+ trigger="click"
371
+ popper-class="background-popper h-auto"
372
+ virtual-triggering
373
+ >
374
+ <div>
375
+ <el-row class="backgroundText">Viewing Mode</el-row>
376
+ <el-row class="backgroundControl">
377
+ <el-select
378
+ :teleported="false"
379
+ v-model="viewingMode"
380
+ @change="changeViewingMode"
381
+ placeholder="Select"
382
+ class="select-box"
383
+ popper-class="flatmap_dropdown"
384
+ >
385
+ <el-option
386
+ v-for="(item, i) in viewingModes"
387
+ :key="item + i"
388
+ :label="item"
389
+ :value="item"
390
+ >
391
+ <el-row>
392
+ <el-col :span="12">{{ item }}</el-col>
393
+ </el-row>
394
+ </el-option>
395
+ </el-select>
396
+ </el-row>
397
+ <el-row class="backgroundSpacer" v-if="displayFlightPathOption"></el-row>
398
+ <el-row class="backgroundText" v-if="displayFlightPathOption">Flight path display</el-row>
399
+ <el-row class="backgroundControl" v-if="displayFlightPathOption">
400
+ <el-radio-group
401
+ v-model="flightPath3DRadio"
402
+ class="flatmap-radio"
403
+ @change="setFlightPath3D"
404
+ >
405
+ <el-radio :label="false">2D</el-radio>
406
+ <el-radio :label="true">3D</el-radio>
407
+ </el-radio-group>
408
+ </el-row>
409
+ <el-row class="backgroundSpacer"></el-row>
410
+ <el-row class="backgroundText">Organs display</el-row>
411
+ <el-row class="backgroundControl">
412
+ <el-radio-group
413
+ v-model="colourRadio"
414
+ class="flatmap-radio"
415
+ @change="setColour"
416
+ >
417
+ <el-radio :label="true">Colour</el-radio>
418
+ <el-radio :label="false">Greyscale</el-radio>
419
+ </el-radio-group>
420
+ </el-row>
421
+ <el-row class="backgroundSpacer"></el-row>
422
+ <el-row class="backgroundText">Outlines display</el-row>
423
+ <el-row class="backgroundControl">
424
+ <el-radio-group
425
+ v-model="outlinesRadio"
426
+ class="flatmap-radio"
427
+ @change="setOutlines"
428
+ >
429
+ <el-radio :label="true">Show</el-radio>
430
+ <el-radio :label="false">Hide</el-radio>
431
+ </el-radio-group>
432
+ </el-row>
433
+ <el-row class="backgroundSpacer"></el-row>
434
+ <el-row class="backgroundText">Change background</el-row>
435
+ <el-row class="backgroundControl">
436
+ <div
437
+ v-for="item in availableBackground"
438
+ :key="item"
439
+ :class="[
440
+ 'backgroundChoice',
441
+ item,
442
+ item == currentBackground ? 'active' : '',
443
+ ]"
444
+ @click="backgroundChangeCallback(item)"
445
+ />
446
+ </el-row>
447
+ </div>
448
+ </el-popover>
449
+ <div
450
+ class="settings-group"
451
+ :class="{ open: drawerOpen, close: !drawerOpen }"
452
+ v-show="!disableUI"
453
+ >
454
+ <el-row>
455
+ <el-popover
456
+ :visible="hoverVisibilities[8].value"
457
+ content="Open new map"
458
+ placement="right"
459
+ :teleported="false"
460
+ popper-class="flatmap-popper"
461
+ >
462
+ <template #reference>
463
+ <map-svg-icon
464
+ v-if="enableOpenMapUI && openMapOptions.length > 0"
465
+ ref="openMapRef"
466
+ icon="openMap"
467
+ class="icon-button open-map-button"
468
+ @mouseover="showToolitip(8)"
469
+ @mouseout="hideToolitip(8)"
470
+ />
471
+ </template>
472
+ </el-popover>
473
+ </el-row>
474
+ <el-row>
475
+ <el-popover
476
+ content="Change settings"
477
+ placement="right"
478
+ :visible="hoverVisibilities[3].value"
479
+ :teleported="false"
480
+ trigger="manual"
481
+ popper-class="flatmap-popper"
482
+ >
483
+ <template #reference>
484
+ <map-svg-icon
485
+ ref="backgroundIconRef"
486
+ icon="changeBckgd"
487
+ class="icon-button"
488
+ @mouseover="showToolitip(3)"
489
+ @mouseout="hideToolitip(3)"
490
+ />
491
+ </template>
492
+ </el-popover>
493
+ </el-row>
494
+ </div>
495
+ <Tooltip
496
+ ref="tooltip"
497
+ class="tooltip"
498
+ v-show="tooltipDisplay"
499
+ :annotationEntry="annotationEntry"
500
+ :entry="tooltipEntry"
501
+ :annotationDisplay="viewingMode === 'Annotation'"
502
+ />
503
+ </div>
504
+ </div>
505
+ </template>
506
+
507
+ <script>
508
+ import { shallowRef } from 'vue'
509
+ import {
510
+ WarningFilled as ElIconWarningFilled,
511
+ ArrowDown as ElIconArrowDown,
512
+ ArrowLeft as ElIconArrowLeft,
513
+ } from '@element-plus/icons-vue'
514
+ /* eslint-disable no-alert, no-console */
515
+ import Tooltip from './Tooltip.vue'
516
+ import SelectionsGroup from './SelectionsGroup.vue'
517
+ import TreeControls from './TreeControls.vue'
518
+ import { MapSvgIcon, MapSvgSpriteColor } from '@abi-software/svg-sprite'
519
+ import SvgLegends from './legends/SvgLegends.vue'
520
+ import {
521
+ ElButton as Button,
522
+ ElCol as Col,
523
+ ElLoading as Loading,
524
+ ElRadio as Radio,
525
+ ElRadioGroup as RadioGroup,
526
+ ElRow as Row,
527
+ ElSelect as Select,
528
+ } from 'element-plus'
529
+ import flatmapMarker from '../icons/flatmap-marker'
530
+ import {
531
+ FlatmapQueries,
532
+ findTaxonomyLabel,
533
+ } from '../services/flatmapQueries.js'
534
+ import yellowstar from '../icons/yellowstar'
535
+ import ResizeSensor from 'css-element-queries/src/ResizeSensor'
536
+ import * as flatmap from '@abi-software/flatmap-viewer'
537
+ import { mapState } from 'pinia'
538
+ import { useMainStore } from '@/store/index'
539
+
540
+
541
+ const processFTUs = (parent, key) => {
542
+ const ftus = []
543
+ let items = parent.organs ? parent.organs : parent.ftus
544
+ const children = items
545
+ ? items.filter(
546
+ (obj, index) =>
547
+ items.findIndex((item) => item.label === obj.label) === index
548
+ )
549
+ : undefined
550
+ if (children) {
551
+ children.forEach((child) => {
552
+ const data = {
553
+ label: child.label,
554
+ models: child.models,
555
+ key: `${key}.${child.label}`,
556
+ }
557
+ const grandChildren = processFTUs(child, data.key)
558
+ if (grandChildren.length > 0) {
559
+ data.children = grandChildren
560
+ }
561
+ ftus.push(data)
562
+ })
563
+ }
564
+ return ftus
565
+ }
566
+
567
+ const processSystems = (systems) => {
568
+ const allSystems = []
569
+ if (systems && systems.length > 0) {
570
+ const data = { label: 'All', key: 'All', children: [] }
571
+ systems.forEach((system) => {
572
+ const child = {
573
+ colour: system.colour,
574
+ enabled: system.enabled,
575
+ label: system.id,
576
+ key: system.id,
577
+ }
578
+ const children = processFTUs(system, child.key)
579
+ if (children.length > 0) child.children = children
580
+ data.children.push(child)
581
+ })
582
+
583
+ allSystems.push(data)
584
+ }
585
+
586
+ return allSystems
587
+ }
588
+
589
+ const createUnfilledTooltipData = function () {
590
+ return {
591
+ destinations: [],
592
+ origins: [],
593
+ components: [],
594
+ destinationsWithDatasets: [],
595
+ originsWithDatasets: [],
596
+ componentsWithDatasets: [],
597
+ resource: undefined,
598
+ }
599
+ }
600
+
601
+ /**
602
+ * A vue component of the flatmap viewer.
603
+ */
604
+ export default {
605
+ name: 'FlatmapVuer',
606
+ components: {
607
+ Button,
608
+ Col,
609
+ Loading,
610
+ Radio,
611
+ RadioGroup,
612
+ Row,
613
+ Select,
614
+ MapSvgIcon,
615
+ MapSvgSpriteColor,
616
+ Tooltip,
617
+ TreeControls,
618
+ SelectionsGroup,
619
+ SvgLegends,
620
+ ElIconWarningFilled,
621
+ ElIconArrowDown,
622
+ ElIconArrowLeft,
623
+ },
624
+ beforeCreate: function () {
625
+ this.mapManager = undefined
626
+ this.mapImp = undefined
627
+ //The state watcher may triggered before
628
+ //created causing issue, This flag will
629
+ //resolve this issue.
630
+ this.setStateRequired = false
631
+ },
632
+ methods: {
633
+ /**
634
+ * @vuese
635
+ * Function to switch from 2D to 3D
636
+ * @arg flag
637
+ */
638
+ setFlightPath3D: function (flag) {
639
+ this.flightPath3DRadio = flag
640
+ if (this.mapImp) {
641
+ this.mapImp.enableFlightPaths(flag)
642
+ }
643
+ },
644
+ /**
645
+ * @vuese
646
+ * Function to view the latest map (example when you are on legacy map).
647
+ */
648
+ viewLatestMap: function () {
649
+ let biologicalSex = this.biologicalSex ? this.biologicalSex : undefined
650
+ //Human requires special handling
651
+ if (this.entry === 'NCBITaxon:9606') {
652
+ biologicalSex = 'PATO:0000384'
653
+ }
654
+ const state = {
655
+ entry: this.entry,
656
+ biologicalSex,
657
+ viewport: this.mapImp.getState(),
658
+ }
659
+ /**
660
+ * The event emitted by ``viewLatestMap`` method.
661
+ */
662
+ this.$emit('view-latest-map', state)
663
+ },
664
+ /**
665
+ * @vuese
666
+ * Function to change the background colour of the map
667
+ * by providing the ``colour``.
668
+ * @arg colour
669
+ */
670
+ backgroundChangeCallback: function (colour) {
671
+ this.currentBackground = colour
672
+ if (this.mapImp) {
673
+ this.mapImp.setBackgroundColour(this.currentBackground, 1)
674
+ }
675
+ },
676
+ /**
677
+ * @vuese
678
+ * Function to process a list of a FC flatmap's systems.
679
+ * @arg systems
680
+ */
681
+ processSystems: function (systems) {
682
+ this.systems.length = 0
683
+ if (systems && systems.length > 0) {
684
+ const data = { label: 'All', key: 'All', children: [] }
685
+ systems.forEach((system) => {
686
+ const child = {
687
+ colour: system.colour,
688
+ enabled: system.enabled,
689
+ label: system.id,
690
+ key: system.id,
691
+ }
692
+ const children = processFTUs(system, child.key)
693
+ if (children.length > 0) child.children = children
694
+ data.children.push(child)
695
+ })
696
+
697
+ this.systems.push(data)
698
+ }
699
+ },
700
+ /**
701
+ * @vuese
702
+ * Function to add taxon identifiers into the taxon connectivity array,
703
+ * by retrieving their corresponding labels using the flatmap API.
704
+ * @arg flatmapAPI,
705
+ * @arg taxonIdentifiers
706
+ */
707
+ processTaxon: function (flatmapAPI, taxonIdentifiers) {
708
+ this.taxonConnectivity.length = 0
709
+ taxonIdentifiers.forEach((taxon) => {
710
+ findTaxonomyLabel(flatmapAPI, taxon).then((value) => {
711
+ const item = { taxon, label: value }
712
+ this.taxonConnectivity.push(item)
713
+ })
714
+ })
715
+ },
716
+ /**
717
+ * @vuese
718
+ * Function to show or hide the display of the bottom-left drawer container.
719
+ */
720
+ toggleDrawer: function () {
721
+ this.drawerOpen = !this.drawerOpen
722
+ },
723
+ /**
724
+ * @vuese
725
+ * Function to toggle colour/greyscale of organs.
726
+ * The parameter ``flag`` is a boolean, ``true`` (colour) and ``false`` (greyscale).
727
+ * @arg flag
728
+ */
729
+ setColour: function (flag) {
730
+ this.colourRadio = flag
731
+ if (this.mapImp) {
732
+ this.mapImp.setColour({ colour: flag, outline: this.outlinesRadio })
733
+ }
734
+ },
735
+ /**
736
+ * @vuese
737
+ * Function to toggle outlines f organs.
738
+ * The parameter ``flag`` is a boolean, ``true`` to show outlines, ``false`` to hide outlines.
739
+ * @arg flag
740
+ */
741
+ setOutlines: function (flag) {
742
+ this.outlineRadio = flag
743
+ if (this.mapImp) {
744
+ this.mapImp.setColour({ colour: this.colourRadio, outline: flag })
745
+ }
746
+ },
747
+ /**
748
+ * @vuese
749
+ * Function to toggle paths to default.
750
+ * Also called when the associated button is pressed.
751
+ */
752
+ resetView: function () {
753
+ if (this.mapImp) {
754
+ this.mapImp.resetMap()
755
+ if (this.$refs.centrelinesSelection) {
756
+ this.$refs.centrelinesSelection.reset()
757
+ }
758
+ if (this.$refs.skcanSelection) {
759
+ this.$refs.skcanSelection.reset()
760
+ }
761
+ if (this.$refs.layersSelection) {
762
+ this.$refs.layersSelection.reset()
763
+ }
764
+ if (this.$refs.systemsSelection) {
765
+ this.$refs.pathwaysSelection.reset()
766
+ }
767
+ if (this.$refs.pathwaysSelection) {
768
+ this.$refs.pathwaysSelection.reset()
769
+ }
770
+ }
771
+ },
772
+ /**
773
+ * @vuese
774
+ * Function to zoom in.
775
+ * Also called when the associated button is pressed.
776
+ */
777
+ zoomIn: function () {
778
+ if (this.mapImp) {
779
+ this.mapImp.zoomIn()
780
+ }
781
+ },
782
+ /**
783
+ * @vuese
784
+ * Function to zoom out.
785
+ * Also called when the associated button is pressed.
786
+ */
787
+ zoomOut: function () {
788
+ if (this.mapImp) {
789
+ this.mapImp.zoomOut()
790
+ }
791
+ },
792
+ /**
793
+ * @vuese
794
+ * Function to show or hide centrelines and nodes.
795
+ * The parameter ``payload`` is an object with a boolean property, ``value``,
796
+ * ``payload.value = true/false``.
797
+ * @arg payload
798
+ */
799
+ centreLinesSelected: function (payload) {
800
+ if (this.mapImp) {
801
+ this.mapImp.enableCentrelines(payload.value)
802
+ }
803
+ },
804
+ /**
805
+ * // Currently not in use
806
+ * Function to show or hide paths valid in SCKAN
807
+ * by providing ``{key, value}`` pair in ``payload``.
808
+ * @arg payload
809
+ */
810
+ sckanSelected: function (payload) {
811
+ if (this.mapImp) {
812
+ this.mapImp.enableSckanPath(payload.key, payload.value)
813
+ }
814
+ },
815
+ /**
816
+ * // Currently not in use
817
+ * Function to show or hide all paths valid in SCKAN.
818
+ * @arg payload
819
+ */
820
+ checkAllSCKAN: function (payload) {
821
+ if (this.mapImp) {
822
+ payload.keys.forEach((key) =>
823
+ this.mapImp.enableSckanPath(key, payload.value)
824
+ )
825
+ }
826
+ },
827
+ /**
828
+ * @vuese
829
+ * Function to highlight the connected paths
830
+ * by providing path model identifier, ``pathId``.
831
+ * @arg pathId
832
+ */
833
+ highlightConnectedPaths: function (payload) {
834
+ if (this.mapImp) {
835
+ let paths = [...this.mapImp.pathModelNodes(payload)]
836
+ // The line below matches the paths to the annIdToFeatureId map to get the feature ids
837
+
838
+ let pathFeatures = paths.map((p) => this.mapImp.featureProperties(p))
839
+ let toHighlight = []
840
+ pathFeatures.forEach((p) => {
841
+ this.mapImp.nodePathModels(p.featureId).forEach((f) => {
842
+ toHighlight.push(f)
843
+ })
844
+ })
845
+ // display connected paths
846
+ this.mapImp.zoomToFeatures(toHighlight, { noZoomIn: true })
847
+ }
848
+ },
849
+ /**
850
+ * @vuese
851
+ * Function to enable/disable (show/hide) the system
852
+ * by providing ``kay, value`` ``payload`` object ``{systemId, true/false}``.
853
+ * @arg payload
854
+ */
855
+ systemSelected: function (payload) {
856
+ if (this.mapImp) {
857
+ this.mapImp.enableSystem(payload.key, payload.value)
858
+ }
859
+ },
860
+ /**
861
+ * @vuese
862
+ * Function to enable/disable (show/hide) all systems
863
+ * by providing ``flag`` (true/false).
864
+ * @arg flag
865
+ */
866
+ checkAllSystems: function (flag) {
867
+ if (this.mapImp) {
868
+ this.systems[0].children.forEach((key) =>
869
+ this.mapImp.enableSystem(key.label, flag)
870
+ )
871
+ }
872
+ },
873
+ /**
874
+ * @vuese
875
+ * Function to display features with annotation matching the provided term.
876
+ * @arg models
877
+ */
878
+ ftuSelected: function (models) {
879
+ this.searchAndShowResult(models, true)
880
+ },
881
+ /**
882
+ * @vuese
883
+ * Function to show or hide the layer
884
+ * by providing ``{layerId, true/false}`` in ``payload``.
885
+ * @arg payload
886
+ */
887
+ layersSelected: function (payload) {
888
+ if (this.mapImp) {
889
+ this.mapImp.enableLayer(payload.key, payload.value)
890
+ }
891
+ },
892
+ /**
893
+ * @vuese
894
+ * Function to show or hide all layers
895
+ * by providing ``payload`` with ``payload.keys`` array and ``payload.value`` flag.
896
+ * @arg payload
897
+ */
898
+ checkAllLayers: function (payload) {
899
+ if (this.mapImp) {
900
+ payload.keys.forEach((key) =>
901
+ this.mapImp.enableLayer(key, payload.value)
902
+ )
903
+ }
904
+ },
905
+ /**
906
+ * @vuese
907
+ * Function to show or hide connectivity features observed in particular species
908
+ * by providing ``{taxonId, true/false}`` in ``payload.key, payload.value``.
909
+ * @arg payload
910
+ */
911
+ taxonsSelected: function (payload) {
912
+ if (this.mapImp) {
913
+ this.mapImp.enableConnectivityByTaxonIds(payload.key, payload.value)
914
+ }
915
+ },
916
+ /**
917
+ * @vuese
918
+ * Function to show or hide connectivity features observed in particular species
919
+ * by providing ``payload`` with ``payload.keys`` array and ``payload.value`` flag.
920
+ * @arg payload
921
+ */
922
+ checkAllTaxons: function (payload) {
923
+ if (this.mapImp) {
924
+ payload.keys.forEach((key) =>
925
+ this.mapImp.enableConnectivityByTaxonIds(key, payload.value)
926
+ )
927
+ }
928
+ },
929
+ /**
930
+ * @vuese
931
+ * Function to hide or show paths of a given type
932
+ * by providing ``{pathType, true/false}`` in ``payload.key, payload.value``.
933
+ * @arg payload
934
+ */
935
+ pathwaysSelected: function (payload) {
936
+ if (this.mapImp) {
937
+ this.mapImp.enablePath(payload.key, payload.value)
938
+ }
939
+ },
940
+ /**
941
+ * @vuese
942
+ * Function to hide or show paths of a given type
943
+ * by providing ``payload`` with ``payload.keys`` array and ``payload.value`` flag.
944
+ * @arg payload
945
+ */
946
+ checkAllPathways: function (payload) {
947
+ if (this.mapImp) {
948
+ payload.keys.forEach((key) =>
949
+ this.mapImp.enablePath(key, payload.value)
950
+ )
951
+ }
952
+ },
953
+ /**
954
+ * @vuese
955
+ * Function to generate callbacks as a result of panning/zooming the map.
956
+ * ``flag`` (boolean) - generate callbacks when ``true``, otherwise disable them.
957
+ * @arg flag
958
+ */
959
+ enablePanZoomEvents: function (flag) {
960
+ this.mapImp.enablePanZoomEvents(flag)
961
+ },
962
+ /**
963
+ * @vuese
964
+ * A callback function, invoked when events occur with the map.
965
+ * The first parameter gives the type of event, the second provides details about the event.
966
+ * _(This is the ``callback`` function from ``MapManager.loadMap()``)_.
967
+ */
968
+ eventCallback: function () {
969
+ return (eventType, data, ...args) => {
970
+ if (eventType !== 'pan-zoom') {
971
+ const label = data.label
972
+ const resource = [data.models]
973
+ const taxonomy = this.entry
974
+ const biologicalSex = this.biologicalSex
975
+ let taxons = undefined
976
+ if (data.taxons) {
977
+ // check if data.taxons is string or array
978
+ if (typeof data.taxons !== 'object') {
979
+ taxons = JSON.parse(data.taxons)
980
+ } else {
981
+ taxons = data.taxons
982
+ }
983
+ }
984
+ const payload = {
985
+ dataset: data.dataset,
986
+ biologicalSex: biologicalSex,
987
+ taxonomy: taxonomy,
988
+ resource: resource,
989
+ label: label,
990
+ feature: data,
991
+ userData: args,
992
+ eventType: eventType,
993
+ provenanceTaxonomy: taxons,
994
+ }
995
+ if (eventType === 'click') {
996
+ if (this.viewingMode === 'Network Discovery') {
997
+ this.highlightConnectedPaths([data.models])
998
+ } else {
999
+ this.currentActive = data.models ? data.models : ''
1000
+ }
1001
+ } else if (
1002
+ eventType === 'mouseenter' &&
1003
+ !(this.viewingMode === 'Network Discovery')
1004
+ ) {
1005
+ this.currentHover = data.models ? data.models : ''
1006
+ }
1007
+ if (
1008
+ data &&
1009
+ data.type !== 'marker' &&
1010
+ eventType === 'click' &&
1011
+ !(this.viewingMode === 'Network Discovery')
1012
+ ) {
1013
+ this.checkAndCreatePopups(payload)
1014
+ }
1015
+ /**
1016
+ * The event emitted from the mouse event callbacks that come from flatmap-viewer. The payload
1017
+ * argument provides an object with information on the feature where the mouse event takes place.
1018
+ * @arg payload
1019
+ */
1020
+ this.$emit('resource-selected', payload)
1021
+ } else {
1022
+ /**
1023
+ * The event emitted in ``callback`` function from ``MapManager.loadMap()``
1024
+ * if ``eventType`` is ``pan-zoom``.
1025
+ * @arg data
1026
+ */
1027
+ this.$emit('pan-zoom-callback', data)
1028
+ }
1029
+ }
1030
+ },
1031
+ /**
1032
+ * @vuese
1033
+ * Function triggered by viewing mode change.
1034
+ * (e.g., from 'Exploration' to 'Annotation')
1035
+ * All tooltips and popups currently showing on map will be closed
1036
+ * when this function is triggered.
1037
+ */
1038
+ changeViewingMode: function () {
1039
+ this.closeTooltip()
1040
+ },
1041
+ /**
1042
+ * @vuese
1043
+ * Function to create/display tooltips from the provided ``data``.
1044
+ * _checkNeuronClicked shows a neuron path pop up if a path was recently clicked._
1045
+ * @arg data
1046
+ */
1047
+ checkAndCreatePopups: async function (data) {
1048
+ // Call flatmap database to get the connection data
1049
+ if (this.viewingMode === 'Annotation') {
1050
+ if (data.feature && data.feature.featureId && data.feature.models) {
1051
+ this.annotationEntry = {
1052
+ ...data.feature,
1053
+ resource: this.serverURL,
1054
+ resourceId: this.serverUUID,
1055
+ }
1056
+ this.displayTooltip(data.feature.models)
1057
+ } else {
1058
+ this.annotation = {}
1059
+ }
1060
+ } else {
1061
+ let results =
1062
+ await this.flatmapQueries.retrieveFlatmapKnowledgeForEvent(data)
1063
+ // The line below only creates the tooltip if some data was found on the path
1064
+ // result 0 is the connection, result 1 is the pubmed results from flatmap
1065
+ if (
1066
+ results[0] ||
1067
+ results[1] ||
1068
+ (data.feature.hyperlinks && data.feature.hyperlinks.length > 0)
1069
+ ) {
1070
+ this.resourceForTooltip = data.resource[0]
1071
+ data.resourceForTooltip = this.resourceForTooltip
1072
+ this.createTooltipFromNeuronCuration(data)
1073
+ }
1074
+ }
1075
+ },
1076
+ /**
1077
+ * A hack to remove flatmap tooltips while popup is open
1078
+ */
1079
+ popUpCssHacks: function () {
1080
+ // Below is a hack to remove flatmap tooltips while popup is open
1081
+ const ftooltip = document.querySelector('.flatmap-tooltip-popup')
1082
+ const popupCloseButton = document.querySelector('.maplibregl-popup-close-button')
1083
+ if (ftooltip) ftooltip.style.display = 'none'
1084
+ popupCloseButton.style.display = 'block'
1085
+ this.$refs.tooltip.$el.style.display = 'flex'
1086
+ popupCloseButton.onclick = () => {
1087
+ if (ftooltip) ftooltip.style.display = 'block'
1088
+ }
1089
+ },
1090
+ /**
1091
+ * @vuese
1092
+ * Function to close tooltip.
1093
+ */
1094
+ closeTooltip: function () {
1095
+ this.$refs.tooltip.$el.style.display = 'none'
1096
+ document.querySelectorAll('.maplibregl-popup').forEach((item) => {
1097
+ item.style.display = 'none'
1098
+ })
1099
+ },
1100
+ /**
1101
+ * @vuese
1102
+ * Function to create tooltip from Neuron Curation ``data``.
1103
+ * @arg data
1104
+ */
1105
+ createTooltipFromNeuronCuration: async function (data) {
1106
+ this.tooltipEntry = await this.flatmapQueries.createTooltipData(data)
1107
+ this.displayTooltip(data.resource[0])
1108
+ },
1109
+ /**
1110
+ * @vuese
1111
+ * Function to show popup on map.
1112
+ * @arg featureId,
1113
+ * @arg node,
1114
+ * @arg options
1115
+ */
1116
+ showPopup: function (featureId, node, options) {
1117
+ // Keeping this as an API
1118
+ let myOptions = options
1119
+ if (this.mapImp) {
1120
+ if (myOptions) {
1121
+ if (!myOptions.className) myOptions.className = 'custom-popup'
1122
+ } else {
1123
+ myOptions = { className: 'custom-popup', positionAtLastClick: true }
1124
+ }
1125
+ this.mapImp.showPopup(featureId, node, myOptions)
1126
+ }
1127
+ },
1128
+ /**
1129
+ * @vuese
1130
+ * Function to show marker popup.
1131
+ * @arg featureId,
1132
+ * @arg node,
1133
+ * @arg options
1134
+ */
1135
+ showMarkerPopup: function (featureId, node, options) {
1136
+ if (this.mapImp) {
1137
+ this.mapImp.showMarkerPopup(featureId, node, options)
1138
+ }
1139
+ },
1140
+ /**
1141
+ * @vuese
1142
+ * Function to close minimap.
1143
+ */
1144
+ closeMinimap: function () {
1145
+ let minimapEl = this.$refs.flatmapContainer.querySelector(
1146
+ '.maplibregl-ctrl-minimap'
1147
+ ) // find minimap
1148
+ if (this.minimapSmall) {
1149
+ //switch the classes on the minimap
1150
+ minimapEl.classList.add('enlarge')
1151
+ minimapEl.classList.remove('shrink')
1152
+ } else {
1153
+ minimapEl.classList.add('shrink')
1154
+ minimapEl.classList.remove('enlarge')
1155
+ }
1156
+ this.minimapSmall = !this.minimapSmall
1157
+ },
1158
+ /**
1159
+ * Function to add resize button to minimap.
1160
+ */
1161
+ addResizeButtonToMinimap: function () {
1162
+ let minimapEl = this.$refs.flatmapContainer.querySelector(
1163
+ '.maplibregl-ctrl-minimap'
1164
+ )
1165
+ if (minimapEl) {
1166
+ if (this.$refs.minimapResize &&
1167
+ this.$refs.minimapResize.$el.parentNode) {
1168
+ this.$refs.minimapResize.$el.parentNode.removeChild(
1169
+ this.$refs.minimapResize.$el)
1170
+ }
1171
+ minimapEl.appendChild(this.$refs.minimapResize.$el)
1172
+ this.minimapResizeShow = true
1173
+ }
1174
+ },
1175
+ /**
1176
+ * @vuese
1177
+ * Function to set help mode
1178
+ * by providing flag ``helpMode`` (true/false).
1179
+ * @arg helpMode
1180
+ */
1181
+ setHelpMode: function (helpMode) {
1182
+ if (helpMode) {
1183
+ this.inHelp = true
1184
+ this.hoverVisibilities.forEach((item) => {
1185
+ item.value = true
1186
+ })
1187
+ this.openFlatmapHelpPopup()
1188
+ } else {
1189
+ this.inHelp = false
1190
+ this.hoverVisibilities.forEach((item) => {
1191
+ item.value = false
1192
+ })
1193
+ this.closeFlatmapHelpPopup()
1194
+ }
1195
+ },
1196
+ /**
1197
+ * @vuese
1198
+ * Function to show tooltip
1199
+ * by providing ``tooltipNumber``.
1200
+ * @arg tooltipNumber
1201
+ */
1202
+ showToolitip: function (tooltipNumber) {
1203
+ if (!this.inHelp) {
1204
+ clearTimeout(this.tooltipWait[tooltipNumber])
1205
+ this.tooltipWait[tooltipNumber] = setTimeout(() => {
1206
+ this.hoverVisibilities[tooltipNumber].value = true
1207
+ }, 500)
1208
+ }
1209
+ },
1210
+ /**
1211
+ * @vuese
1212
+ * Function to hide tooltip
1213
+ * by providing ``tooltipNumber``.
1214
+ * @arg tooltipNumber
1215
+ */
1216
+ hideToolitip: function (tooltipNumber) {
1217
+ if (!this.inHelp) {
1218
+ clearTimeout(this.tooltipWait[tooltipNumber])
1219
+ this.tooltipWait[tooltipNumber] = setTimeout(() => {
1220
+ this.hoverVisibilities[tooltipNumber].value = false
1221
+ }, 500)
1222
+ }
1223
+ },
1224
+ /**
1225
+ * @vuese
1226
+ * Function to display tooltip
1227
+ * by providing featureId (``feature``).
1228
+ * @arg feature
1229
+ */
1230
+ displayTooltip: function (feature) {
1231
+ this.tooltipDisplay = true
1232
+ if (!this.disableUI) {
1233
+ this.$nextTick(() => {
1234
+ this.displayPopup(feature)
1235
+ });
1236
+ }
1237
+ },
1238
+ /**
1239
+ * @vuese
1240
+ * Function to display popup
1241
+ * by providing featureId (``feature``).
1242
+ * @arg feature
1243
+ */
1244
+ displayPopup: function (feature) {
1245
+ this.mapImp.showPopup(
1246
+ this.mapImp.modelFeatureIds(feature)[0],
1247
+ this.$refs.tooltip.$el,
1248
+ { className: 'flatmapvuer-popover', positionAtLastClick: true }
1249
+ )
1250
+ this.popUpCssHacks()
1251
+ },
1252
+ /**
1253
+ * @vuese
1254
+ * Function to open Flatmap Help Popup.
1255
+ */
1256
+ openFlatmapHelpPopup: function () {
1257
+ if (this.mapImp) {
1258
+ let heartId = this.mapImp.modelFeatureIds('UBERON:0000948')
1259
+ if (heartId && heartId.length > 0) {
1260
+ const elm = 'Click for more information'
1261
+ this.mapImp.showPopup(heartId[0], elm, {
1262
+ anchor: 'top',
1263
+ className: 'flatmap-popup-popper',
1264
+ })
1265
+ }
1266
+ }
1267
+ },
1268
+ /**
1269
+ * @vuese
1270
+ * Function to close Flatmap Help Popup.
1271
+ */
1272
+ closeFlatmapHelpPopup: function () {
1273
+ this.$el
1274
+ .querySelectorAll('.maplibregl-popup-close-button')
1275
+ .forEach((item) => {
1276
+ item.click()
1277
+ })
1278
+ },
1279
+ /**
1280
+ * @vuese
1281
+ * Function to get annotation labels.
1282
+ */
1283
+ getLabels: function () {
1284
+ let labels = []
1285
+ if (this.mapImp) {
1286
+ let annotations = this.mapImp.annotations
1287
+ for (let value of annotations.values()) {
1288
+ if (value.label) labels.push(value.label)
1289
+ }
1290
+ return Array.from(new Set(labels))
1291
+ }
1292
+ },
1293
+ /**
1294
+ * @vuese
1295
+ * Function to get the state (object) of the map.
1296
+ */
1297
+ getState: function () {
1298
+ if (this.mapImp) {
1299
+ let state = {
1300
+ entry: this.entry,
1301
+ viewport: this.mapImp.getState(),
1302
+ }
1303
+ const identifier = this.mapImp.getIdentifier()
1304
+ if (this.biologicalSex) state['biologicalSex'] = this.biologicalSex
1305
+ else if (identifier && identifier.biologicalSex)
1306
+ state['biologicalSex'] = identifier.biologicalSex
1307
+ if (identifier && identifier.uuid) state['uuid'] = identifier.uuid
1308
+ return state
1309
+ }
1310
+ return undefined
1311
+ },
1312
+ /**
1313
+ * @vuese
1314
+ * Function to set state (object) for the map.
1315
+ * @arg state
1316
+ */
1317
+ setState: function (state) {
1318
+ if (state) {
1319
+ if (
1320
+ this.mapImp &&
1321
+ state.entry &&
1322
+ this.entry == state.entry &&
1323
+ (!state.biologicalSex || state.biologicalSex === this.biologicalSex)
1324
+ ) {
1325
+ if (state.viewport) {
1326
+ this.mapImp.setState(state.viewport)
1327
+ }
1328
+ } else {
1329
+ this.createFlatmap(state)
1330
+ }
1331
+ this.setStateRequired = false
1332
+ }
1333
+ },
1334
+ /**
1335
+ * @vuese
1336
+ * Function to restore map's state
1337
+ * from the ``state`` provided.
1338
+ * @arg state
1339
+ */
1340
+ restoreMapState: function (state) {
1341
+ if (state) {
1342
+ if (state.viewport) this.mapImp.setState(state.viewport)
1343
+ if (state.searchTerm) this.searchAndShowResult(state.searchTerm, true)
1344
+ }
1345
+ },
1346
+ /**
1347
+ * @vuese
1348
+ * Function to show flight path option
1349
+ * (3D option)
1350
+ * based on the map version (currently 1.6 and above).
1351
+ * @arg mapVersion
1352
+ */
1353
+ setFlightPathInfo: function (mapVersion) {
1354
+ const mapVersionForFlightPath = 1.6
1355
+ if (mapVersion === mapVersionForFlightPath || mapVersion > mapVersionForFlightPath) {
1356
+ // Show flight path option UI
1357
+ this.displayFlightPathOption = true
1358
+ // Show 2D as default on FC type
1359
+ this.setFlightPath3D(false)
1360
+ }
1361
+ },
1362
+ /**
1363
+ * @vuese
1364
+ * Function to create Flatmap
1365
+ * by providing the ``state``.
1366
+ * @arg state
1367
+ */
1368
+ createFlatmap: function (state) {
1369
+ if (!this.mapImp && !this.loading) {
1370
+ this.loading = true
1371
+ let minimap = false
1372
+ if (this.displayMinimap) {
1373
+ minimap = { position: 'top-right' }
1374
+ }
1375
+
1376
+ //As for flatmap-viewer@2.2.7, see below for the documentation
1377
+ //for the identifier:
1378
+
1379
+ //@arg identifier {string|Object}
1380
+ // A string or object identifying the map to load. If a string its
1381
+ // value can be either the map's ``uuid``, assigned at generation time,
1382
+ // or taxon and biological sex identifiers of the species that the map
1383
+ // represents. The latest version of a map is loaded unless it has been
1384
+ // identified using a ``uuid`` (see below).
1385
+ // @arg identifier.taxon {string} The taxon identifier of the species
1386
+ // represented by the map. This is specified as metadata in the map's source file.
1387
+ // @arg identifier.biologicalSex {string} The biological sex of the species
1388
+ // represented by the map. This is specified as metadatain the map's source file.
1389
+ // @arg identifier.uuid {string} The unique uuid the flatmap. If given then this exact map will
1390
+ // be loaded, overriding ``taxon`` and ``biologicalSex``.
1391
+
1392
+ let identifier = { taxon: this.entry }
1393
+ if (this.uuid) {
1394
+ identifier.uuid = this.uuid
1395
+ }
1396
+ //This now handle the uses of uuid when resuming states
1397
+ if (state) {
1398
+ if (state.uuid) {
1399
+ identifier = { uuid: state.uuid }
1400
+ } else if (state.entry) {
1401
+ identifier.taxon = state.entry
1402
+ if (state.biologicalSex) {
1403
+ identifier['biologicalSex'] = state.biologicalSex
1404
+ } else if (identifier.taxon === 'NCBITaxon:9606') {
1405
+ //For backward compatibility
1406
+ identifier['biologicalSex'] = 'PATO:0000384'
1407
+ }
1408
+ }
1409
+ } else {
1410
+ // Set the bioloicalSex now if map is not resumed from
1411
+ // a saved state
1412
+ if (this.biologicalSex) {
1413
+ identifier['biologicalSex'] = this.biologicalSex
1414
+ }
1415
+ }
1416
+
1417
+ let promise1 = this.mapManager.loadMap(
1418
+ identifier,
1419
+ this.$refs.display,
1420
+ this.eventCallback(),
1421
+ {
1422
+ //fullscreenControl: false,
1423
+ //annotatable: false,
1424
+ //debug: true,
1425
+ minZoom: this.minZoom,
1426
+ tooltips: this.tooltips,
1427
+ minimap: minimap,
1428
+ }
1429
+ )
1430
+ promise1.then((returnedObject) => {
1431
+ this.mapImp = returnedObject
1432
+ this.serverUUID = this.mapImp.getIdentifier().uuid
1433
+ this.serverURL = this.mapImp.makeServerUrl('').slice(0, -1)
1434
+ let mapVersion = this.mapImp.details.version
1435
+ this.setFlightPathInfo(mapVersion)
1436
+ this.onFlatmapReady()
1437
+ if (this._stateToBeSet) this.restoreMapState(this._stateToBeSet)
1438
+ else {
1439
+ this.restoreMapState(state)
1440
+ }
1441
+ })
1442
+ } else if (state) {
1443
+ this._stateToBeSet = {
1444
+ viewport: state.viewport,
1445
+ searchTerm: state.searchTerm,
1446
+ }
1447
+ if (this.mapImp && !this.loading)
1448
+ this.restoreMapState(this._stateToBeSet)
1449
+ }
1450
+ },
1451
+ /**
1452
+ * @vuese
1453
+ * Function to compute path controls maximum height.
1454
+ */
1455
+ computePathControlsMaximumHeight() {
1456
+ const elem = this.$refs.display
1457
+ if (elem) {
1458
+ const computed = getComputedStyle(elem)
1459
+ const padding =
1460
+ parseInt(computed.paddingTop) + parseInt(computed.paddingBottom)
1461
+ const height = elem.clientHeight - padding
1462
+ this.pathwaysMaxHeight = height - 170
1463
+ }
1464
+ },
1465
+ /**
1466
+ * @vuese
1467
+ * Function to resize the map.
1468
+ */
1469
+ mapResize: function () {
1470
+ try {
1471
+ this.computePathControlsMaximumHeight()
1472
+ if (this.mapImp) {
1473
+ this.mapImp.resize()
1474
+ this.showMinimap(this.displayMinimap)
1475
+ if (this.mapImp._minimap) {
1476
+ this.mapImp._minimap._miniMap.resize()
1477
+ }
1478
+ }
1479
+ } catch {
1480
+ console.error('Map resize error')
1481
+ }
1482
+ },
1483
+ /**
1484
+ * @vuese
1485
+ * This function is used for functions that need to run immediately after the flatmap is loaded.
1486
+ */
1487
+ onFlatmapReady: function () {
1488
+ // onFlatmapReady is used for functions that need to run immediately after the flatmap is loaded
1489
+ this.sensor = new ResizeSensor(this.$refs.display, this.mapResize)
1490
+ if (this.mapImp.options && this.mapImp.options.style === 'functional') {
1491
+ this.isFC = true
1492
+ }
1493
+ this.mapImp.setBackgroundOpacity(1)
1494
+ this.backgroundChangeCallback(this.currentBackground)
1495
+ this.pathways = this.mapImp.pathTypes()
1496
+ this.mapImp.enableCentrelines(false)
1497
+ //Disable layers for now
1498
+ //this.layers = this.mapImp.getLayers();
1499
+ this.processSystems(this.mapImp.getSystems())
1500
+ this.processTaxon(this.flatmapAPI, this.mapImp.taxonIdentifiers)
1501
+ this.addResizeButtonToMinimap()
1502
+ this.loading = false
1503
+ this.computePathControlsMaximumHeight()
1504
+ this.drawerOpen = true
1505
+ this.mapResize()
1506
+ /**
1507
+ * This is ``onFlatmapReady`` event.
1508
+ * @arg ``this`` (Component Vue Instance)
1509
+ */
1510
+ this.$emit('ready', this)
1511
+ },
1512
+ /**
1513
+ * @vuese
1514
+ * Function to show or hide the minimap
1515
+ * by providing ``flag`` (boolean) value.
1516
+ * @arg flag
1517
+ */
1518
+ showMinimap: function (flag) {
1519
+ if (this.mapImp) this.mapImp.showMinimap(flag)
1520
+ },
1521
+ /**
1522
+ * @vuese
1523
+ * Function to show or hide the pathways drawer
1524
+ * by providing ``flag`` (boolean) value.
1525
+ * @arg flag
1526
+ */
1527
+ showPathwaysDrawer: function (flag) {
1528
+ this.drawerOpen = flag
1529
+ },
1530
+ /**
1531
+ * @vuese
1532
+ * Function to display features with annotation matching the provided term,
1533
+ * with the option to display the label using displayLabel flag.
1534
+ * @arg term,
1535
+ * @arg displayLabel
1536
+ */
1537
+ searchAndShowResult: function (term, displayLabel) {
1538
+ if (this.mapImp) {
1539
+ if (term === undefined || term === '') {
1540
+ this.mapImp.clearSearchResults()
1541
+ return true
1542
+ } else {
1543
+ const searchResults = this.mapImp.search(term)
1544
+ if (
1545
+ searchResults &&
1546
+ searchResults.results &&
1547
+ searchResults.results.length > 0
1548
+ ) {
1549
+ this.mapImp.showSearchResults(searchResults)
1550
+ if (
1551
+ displayLabel &&
1552
+ searchResults.results[0].featureId &&
1553
+ searchResults.results[0].text
1554
+ ) {
1555
+ const annotation = this.mapImp.annotation(
1556
+ searchResults.results[0].featureId
1557
+ )
1558
+ this.mapImp.showPopup(
1559
+ searchResults.results[0].featureId,
1560
+ annotation.label,
1561
+ {
1562
+ className: 'custom-popup',
1563
+ positionAtLastClick: false,
1564
+ preserveSelection: true,
1565
+ }
1566
+ )
1567
+ }
1568
+ return true
1569
+ } else this.mapImp.clearSearchResults()
1570
+ }
1571
+ }
1572
+ return false
1573
+ },
1574
+ /**
1575
+ * @vuese
1576
+ * Function to show search suggestions
1577
+ * from the ``term`` provided.
1578
+ * @arg term
1579
+ */
1580
+ searchSuggestions: function (term) {
1581
+ if (this.mapImp) return this.mapImp.search(term)
1582
+ return []
1583
+ },
1584
+ },
1585
+ props: {
1586
+ /**
1587
+ * The taxon identifier of the species represented by the map.
1588
+ */
1589
+ entry: {
1590
+ type: String,
1591
+ required: true,
1592
+ },
1593
+ /**
1594
+ * The unique ``uuid`` of the flatmap.
1595
+ * If given then this exact map will be loaded,
1596
+ * overriding ``taxon`` and ``biologicalSex``.
1597
+ */
1598
+ uuid: String,
1599
+ /**
1600
+ * The biological sex of the species represented by the map.
1601
+ * This is specified as metadata in the map's source file.
1602
+ */
1603
+ biologicalSex: {
1604
+ type: String,
1605
+ default: '',
1606
+ },
1607
+ /**
1608
+ * The minimum zoom level of the map.
1609
+ */
1610
+ minZoom: {
1611
+ type: Number,
1612
+ default: 4,
1613
+ },
1614
+ /**
1615
+ * The option to add another feature label _(`FeatureSmallSymbolLayer`)_
1616
+ * when this `tooltips` is set to `false`.
1617
+ */
1618
+ tooltips: {
1619
+ type: Boolean,
1620
+ default: true,
1621
+ },
1622
+ /**
1623
+ * The option to show tooltips for help mode.
1624
+ */
1625
+ helpMode: {
1626
+ type: Boolean,
1627
+ default: false,
1628
+ },
1629
+ /**
1630
+ * The option to create map on component mounted.
1631
+ */
1632
+ renderAtMounted: {
1633
+ type: Boolean,
1634
+ default: true,
1635
+ },
1636
+ /**
1637
+ * The option to display minimap at the top-right corner of the map.
1638
+ */
1639
+ displayMinimap: {
1640
+ type: Boolean,
1641
+ default: false,
1642
+ },
1643
+ /**
1644
+ * The option to show warning. Example for legacy or beta maps.
1645
+ */
1646
+ displayWarning: {
1647
+ type: Boolean,
1648
+ default: false,
1649
+ },
1650
+ /**
1651
+ * Flag to determine rather open map UI should be
1652
+ * presented or not.
1653
+ */
1654
+ enableOpenMapUI: {
1655
+ type: Boolean,
1656
+ default: false,
1657
+ },
1658
+ /**
1659
+ * The data to show different map options.
1660
+ * Available at the bottom-left corner ("Open new map" tooltip).
1661
+ */
1662
+ openMapOptions: {
1663
+ type: Array,
1664
+ /**
1665
+ * ```[
1666
+ {
1667
+ display: 'Open AC Map',
1668
+ key: 'AC',
1669
+ },
1670
+ {
1671
+ display: 'Open FC Map',
1672
+ key: 'FC',
1673
+ },
1674
+ {
1675
+ display: 'Open 3D Human Map',
1676
+ key: '3D',
1677
+ },
1678
+ ]```
1679
+ */
1680
+ default: function () {
1681
+ return [
1682
+ {
1683
+ display: 'Open AC Map',
1684
+ key: 'AC',
1685
+ },
1686
+ {
1687
+ display: 'Open FC Map',
1688
+ key: 'FC',
1689
+ },
1690
+ {
1691
+ display: 'Open 3D Human Map',
1692
+ key: '3D',
1693
+ },
1694
+ ]
1695
+ },
1696
+ },
1697
+ /**
1698
+ * The option to show star in legend area.
1699
+ */
1700
+ showStarInLegend: {
1701
+ type: Boolean,
1702
+ default: false,
1703
+ },
1704
+ /**
1705
+ * Flag to determine whether this is legacy map or not.
1706
+ * ``displayWarning`` should be shown for legacy map.
1707
+ */
1708
+ isLegacy: {
1709
+ type: Boolean,
1710
+ default: false,
1711
+ },
1712
+ /**
1713
+ * The option to show the latest changes.
1714
+ */
1715
+ displayLatestChanges: {
1716
+ type: Boolean,
1717
+ default: false,
1718
+ },
1719
+ /**
1720
+ * State containing state of the flatmap.
1721
+ */
1722
+ state: {
1723
+ type: Object,
1724
+ default: undefined,
1725
+ },
1726
+ /**
1727
+ * Specify the endpoint of the flatmap server.
1728
+ */
1729
+ flatmapAPI: {
1730
+ type: String,
1731
+ default: 'https://mapcore-demo.org/current/flatmap/v3/',
1732
+ },
1733
+ /**
1734
+ * Specify the endpoint of the SPARC API.
1735
+ */
1736
+ sparcAPI: {
1737
+ type: String,
1738
+ default: 'https://api.sparc.science/',
1739
+ },
1740
+ /**
1741
+ * Flag to disable UIs on Map
1742
+ */
1743
+ disableUI: {
1744
+ type: Boolean,
1745
+ default: false,
1746
+ }
1747
+ },
1748
+ provide() {
1749
+ return {
1750
+ flatmapAPI: this.flatmapAPI,
1751
+ sparcAPI: this.sparcAPI,
1752
+ userApiKey: this.userToken
1753
+ }
1754
+ },
1755
+ data: function () {
1756
+ return {
1757
+ annotationEntry: {},
1758
+ //tooltip display has to be set to false until it is rendered
1759
+ //for the first time, otherwise it may display an arrow at a
1760
+ //undesired location.
1761
+ tooltipDisplay: false,
1762
+ serverUUID: undefined,
1763
+ serverURL: undefined,
1764
+ layers: [],
1765
+ pathways: [],
1766
+ sckanDisplay: [
1767
+ {
1768
+ label: 'Display Path with SCKAN',
1769
+ key: 'VALID',
1770
+ },
1771
+ ],
1772
+ centreLines: [
1773
+ {
1774
+ label: 'Display Nerves',
1775
+ key: 'centrelines',
1776
+ enabled: false,
1777
+ },
1778
+ ],
1779
+ systems: [],
1780
+ taxonConnectivity: [],
1781
+ pathwaysMaxHeight: 1000,
1782
+ hoverVisibilities: [
1783
+ { value: false },
1784
+ { value: false },
1785
+ { value: false },
1786
+ { value: false },
1787
+ { value: false },
1788
+ { value: false },
1789
+ { value: false },
1790
+ { value: false },
1791
+ { value: false },
1792
+ { value: false },
1793
+ ],
1794
+ yellowstar: yellowstar,
1795
+ isFC: false,
1796
+ inHelp: false,
1797
+ currentBackground: 'white',
1798
+ availableBackground: ['white', 'lightskyblue', 'black'],
1799
+ loading: false,
1800
+ flatmapMarker: flatmapMarker,
1801
+ tooltipEntry: createUnfilledTooltipData(),
1802
+ connectivityTooltipVisible: false,
1803
+ drawerOpen: false,
1804
+ annotationRadio: false,
1805
+ flightPath3DRadio: false,
1806
+ displayFlightPathOption: false,
1807
+ colourRadio: true,
1808
+ outlinesRadio: true,
1809
+ minimapResizeShow: false,
1810
+ minimapSmall: false,
1811
+ currentActive: '',
1812
+ currentHover: '',
1813
+ viewingMode: 'Exploration',
1814
+ viewingModes: ['Annotation', 'Exploration', 'Network Discovery'],
1815
+ openMapRef: undefined,
1816
+ backgroundIconRef: undefined,
1817
+ }
1818
+ },
1819
+ computed: {
1820
+ ...mapState(useMainStore, ['userToken']),
1821
+ },
1822
+ watch: {
1823
+ entry: function () {
1824
+ if (!this.state) this.createFlatmap()
1825
+ },
1826
+ helpMode: function (newVal, oldVal) {
1827
+ if (newVal !== oldVal) {
1828
+ this.setHelpMode(val)
1829
+ }
1830
+ },
1831
+ state: {
1832
+ handler: function (state, oldVal) {
1833
+ if (state !== oldVal) {
1834
+ if (this.mapManager) {
1835
+ this.setState(state)
1836
+ } else {
1837
+ //this component has not been mounted yet
1838
+ this.setStateRequired = true
1839
+ }
1840
+ }
1841
+ },
1842
+ immediate: true,
1843
+ deep: true,
1844
+ },
1845
+ disableUI: function (isUIDisabled) {
1846
+ if (isUIDisabled) {
1847
+ this.closeTooltip()
1848
+ }
1849
+ }
1850
+ },
1851
+ mounted: function () {
1852
+ this.openMapRef = shallowRef(this.$refs.openMapRef)
1853
+ this.backgroundIconRef = shallowRef(this.$refs.backgroundIconRef)
1854
+ this.tooltipWait = []
1855
+ this.tooltipWait.length = this.hoverVisibilities.length
1856
+ this.mapManager = new flatmap.MapManager(this.flatmapAPI)
1857
+ this.flatmapQueries = new FlatmapQueries()
1858
+ this.flatmapQueries.initialise(this.flatmapAPI)
1859
+ if (this.state) {
1860
+ //State is set and require to set the state
1861
+ if (this.setStateRequired) {
1862
+ this.setState(this.state)
1863
+ }
1864
+ } else if (this.renderAtMounted) {
1865
+ this.createFlatmap()
1866
+ }
1867
+ },
1868
+ }
1869
+ </script>
1870
+
1871
+ <style lang="scss" scoped>
1872
+
1873
+ .beta-popovers {
1874
+ position: absolute;
1875
+ top: 90px;
1876
+ left: 16px;
1877
+ text-align: left;
1878
+ font-size: 25px;
1879
+ }
1880
+
1881
+ .warning-icon {
1882
+ color: $warning;
1883
+
1884
+ &:hover {
1885
+ cursor: pointer;
1886
+ }
1887
+ }
1888
+
1889
+ .warning-text {
1890
+ font-family: Asap, sans-serif;
1891
+ font-size: 15px;
1892
+ vertical-align: 5px;
1893
+ }
1894
+
1895
+ .latest-map-text {
1896
+ color: $app-primary-color;
1897
+ font-family: Asap, sans-serif;
1898
+ font-size: 12px;
1899
+ margin-top: 5px;
1900
+ vertical-align: 10px;
1901
+ cursor: pointer;
1902
+ }
1903
+
1904
+ .latest-changesicon {
1905
+ color: $success;
1906
+
1907
+ &:hover {
1908
+ cursor: pointer;
1909
+ }
1910
+ }
1911
+
1912
+ .latest-changestext {
1913
+ font-family: Asap, sans-serif;
1914
+ font-size: 15px;
1915
+ vertical-align: 5px;
1916
+ }
1917
+
1918
+ .flatmap-container {
1919
+ height: 100%;
1920
+ width: 100%;
1921
+ }
1922
+
1923
+ .pathway-location {
1924
+ position: absolute;
1925
+ bottom: 0px;
1926
+ transition: all 1s ease;
1927
+ &.open {
1928
+ left: 0px;
1929
+ }
1930
+ &.close {
1931
+ left: -298px;
1932
+ }
1933
+ }
1934
+
1935
+ .svg-legends-container {
1936
+ width: 70%;
1937
+ height: auto;
1938
+ position: relative;
1939
+ max-height: 140px;
1940
+ }
1941
+
1942
+ .pathway-container {
1943
+ float: left;
1944
+ padding-left: 16px;
1945
+ padding-right: 18px;
1946
+ text-align: left;
1947
+ overflow: auto;
1948
+ border: 1px solid rgb(220, 223, 230);
1949
+ padding-bottom: 16px;
1950
+ background: #ffffff;
1951
+ overflow-x: hidden;
1952
+ scrollbar-width: thin;
1953
+
1954
+ transition: all 1s ease;
1955
+ &.open {
1956
+ opacity: 1;
1957
+ position: relative;
1958
+ z-index: 2;
1959
+ }
1960
+ &.close {
1961
+ opacity: 0;
1962
+ }
1963
+
1964
+ &::-webkit-scrollbar {
1965
+ width: 4px;
1966
+ }
1967
+
1968
+ &::-webkit-scrollbar-thumb {
1969
+ border-radius: 10px;
1970
+ box-shadow: inset 0 0 6px #c0c4cc;
1971
+ }
1972
+ }
1973
+
1974
+ .flatmap-marker-help {
1975
+ display: inline-block;
1976
+ }
1977
+
1978
+ :deep(.popper-bump-right) {
1979
+ left: 30px;
1980
+ }
1981
+
1982
+ .el-dropdown-link {
1983
+ cursor: pointer;
1984
+ color: #409eff;
1985
+ }
1986
+ .el-icon-arrow-down {
1987
+ font-size: 12px;
1988
+ }
1989
+ .demonstration {
1990
+ display: block;
1991
+ color: #8492a6;
1992
+ font-size: 14px;
1993
+ margin-bottom: 20px;
1994
+ }
1995
+
1996
+ .tooltip {
1997
+ display: none;
1998
+ }
1999
+
2000
+ :deep(.maplibregl-popup) {
2001
+ max-width: 300px !important;
2002
+ }
2003
+
2004
+ :deep(.flatmap-tooltip-popup) {
2005
+ &.maplibregl-popup-anchor-bottom {
2006
+ .maplibregl-popup-content {
2007
+ margin-bottom: 12px;
2008
+ &::after,
2009
+ &::before {
2010
+ top: 100%;
2011
+ border-width: 12px;
2012
+ }
2013
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
2014
+ &::after {
2015
+ margin-top: -1px;
2016
+ border-color: rgb(255, 255, 255) transparent transparent transparent;
2017
+ }
2018
+ /* this border color controlls the outside, thin border */
2019
+ &::before {
2020
+ margin: 0 auto;
2021
+ border-color: $app-primary-color transparent transparent transparent;
2022
+ }
2023
+ }
2024
+ }
2025
+ &.maplibregl-popup-anchor-top {
2026
+ .maplibregl-popup-content {
2027
+ margin-top: 12px;
2028
+ &::after,
2029
+ &::before {
2030
+ top: auto;
2031
+ bottom: 100%;
2032
+ border-width: 12px;
2033
+ }
2034
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
2035
+ &::after {
2036
+ border-color: transparent transparent rgb(255, 255, 255) transparent;
2037
+ }
2038
+ &::before {
2039
+ margin: 0 auto;
2040
+ margin-bottom: 1px;
2041
+ border-color: transparent transparent $app-primary-color transparent;
2042
+ }
2043
+ }
2044
+ }
2045
+ &.maplibregl-popup-anchor-left {
2046
+ margin-left: 8px;
2047
+ .maplibregl-popup-content {
2048
+ &::after,
2049
+ &::before {
2050
+ top: 50%;
2051
+ left: 0;
2052
+ border-width: 8px;
2053
+ margin-top: -8px;
2054
+ margin-left: -16px;
2055
+ }
2056
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
2057
+ &::after {
2058
+ transform: translateX(1px);
2059
+ border-color: transparent rgb(255, 255, 255) transparent transparent;
2060
+ }
2061
+ &::before {
2062
+ border-color: transparent $app-primary-color transparent transparent;
2063
+ }
2064
+ }
2065
+ }
2066
+ &.maplibregl-popup-anchor-right {
2067
+ margin-right: 8px;
2068
+ .maplibregl-popup-content {
2069
+ &::after,
2070
+ &::before {
2071
+ top: 50%;
2072
+ right: 0;
2073
+ border-width: 8px;
2074
+ margin-top: -8px;
2075
+ margin-right: -16px;
2076
+ }
2077
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
2078
+ &::after {
2079
+ transform: translateX(-1px);
2080
+ border-color: transparent transparent transparent rgb(255, 255, 255);
2081
+ }
2082
+ &::before {
2083
+ border-color: transparent transparent transparent $app-primary-color;
2084
+ }
2085
+ }
2086
+ }
2087
+ &.maplibregl-popup-anchor-top-left,
2088
+ &.maplibregl-popup-anchor-top-right,
2089
+ &.maplibregl-popup-anchor-bottom-left,
2090
+ &.maplibregl-popup-anchor-bottom-right {
2091
+ .maplibregl-popup-content {
2092
+ &::after,
2093
+ &::before {
2094
+ display: none;
2095
+ }
2096
+ }
2097
+ }
2098
+ .maplibregl-popup-content {
2099
+ border-radius: 4px;
2100
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
2101
+ pointer-events: none;
2102
+ display: none;
2103
+ background: #fff;
2104
+ border: 1px solid $app-primary-color;
2105
+ padding-left: 6px;
2106
+ padding-right: 6px;
2107
+ display: flex;
2108
+ justify-content: center;
2109
+ align-items: center;
2110
+ &::after,
2111
+ &::before {
2112
+ content: '';
2113
+ display: block;
2114
+ position: absolute;
2115
+ width: 0;
2116
+ height: 0;
2117
+ border-style: solid;
2118
+ flex-shrink: 0;
2119
+ }
2120
+ }
2121
+ .maplibregl-popup-tip {
2122
+ display: none;
2123
+ }
2124
+ }
2125
+
2126
+ :deep(.maplibregl-popup) {
2127
+ &.flatmap-marker-popup {
2128
+ box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
2129
+ pointer-events: auto;
2130
+ background: #fff;
2131
+ }
2132
+ }
2133
+
2134
+ /* Fix for chrome bug where under triangle pops up above one on top of it */
2135
+ .selector:not(*:root),
2136
+ :deep(.flatmap-tooltip-popup) {
2137
+ .maplibregl-popup-content::after {
2138
+ top: 99.9%;
2139
+ }
2140
+ }
2141
+
2142
+ :deep(.flatmap-tooltip-dialog) {
2143
+ .maplibregl-popup-tip {
2144
+ display: none;
2145
+ }
2146
+ }
2147
+
2148
+ :deep(.flatmap-marker-popup){
2149
+ .maplibregl-popup-content {
2150
+ padding: 0px;
2151
+ }
2152
+ }
2153
+
2154
+ :deep(.flatmapvuer-popover) {
2155
+ .maplibregl-popup-close-button {
2156
+ position: absolute;
2157
+ right: 0;
2158
+ top: 0;
2159
+ border: 0;
2160
+ border-radius: 0 3px 0 0;
2161
+ cursor: pointer;
2162
+ background-color: transparent;
2163
+ font-size: 2.5em;
2164
+ color: grey;
2165
+ transition: color 0.3s ease;
2166
+
2167
+ &:hover {
2168
+ color: $app-primary-color;
2169
+ }
2170
+ }
2171
+ }
2172
+
2173
+ .zoomOut {
2174
+ padding-left: 8px;
2175
+ }
2176
+
2177
+ .fitWindow {
2178
+ padding-left: 8px;
2179
+ }
2180
+
2181
+ .yellow-star-legend {
2182
+ width: 130px;
2183
+ cursor: pointer;
2184
+ }
2185
+
2186
+ .settings-group {
2187
+ bottom: 16px;
2188
+ position: absolute;
2189
+ transition: all 1s ease;
2190
+ &.open {
2191
+ left: 322px;
2192
+ }
2193
+ &.close {
2194
+ left: 24px;
2195
+ }
2196
+ }
2197
+
2198
+ :deep(.background-popper.el-popover.el-popper) {
2199
+ padding: 5px 12px;
2200
+ background-color: #ffffff;
2201
+ border: 1px solid $app-primary-color;
2202
+ box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.06);
2203
+ height: 290px;
2204
+ min-width: 200px;
2205
+ .el-popper__arrow {
2206
+ &:before {
2207
+ border-color: $app-primary-color;
2208
+ }
2209
+ }
2210
+ }
2211
+
2212
+ :deep(.background-popper.el-popover.el-popper.h-auto) {
2213
+ height: auto !important;
2214
+ }
2215
+
2216
+ :deep(.open-map-popper.el-popover.el-popper) {
2217
+ padding-top: 5px;
2218
+ padding-bottom: 5px;
2219
+ background-color: #ffffff;
2220
+ border: 1px solid $app-primary-color;
2221
+ box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.06);
2222
+ min-width: 188px;
2223
+
2224
+ .el-row ~ .el-row {
2225
+ margin-top: 8px;
2226
+ }
2227
+
2228
+ .el-button {
2229
+ padding-top: 5px;
2230
+ padding-bottom: 5px;
2231
+ background: #f3e6f9;
2232
+ border-color: $app-primary-color;
2233
+ color: $app-primary-color;
2234
+ }
2235
+
2236
+ .el-popper__arrow {
2237
+ &:before {
2238
+ border-color: $app-primary-color;
2239
+ }
2240
+ }
2241
+ }
2242
+
2243
+ .backgroundText {
2244
+ color: rgb(48, 49, 51);
2245
+ font-size: 14px;
2246
+ font-weight: normal;
2247
+ line-height: 20px;
2248
+ }
2249
+
2250
+ .backgroundControl {
2251
+ display: flex;
2252
+ }
2253
+
2254
+ .backgroundChoice {
2255
+ width: 20px;
2256
+ height: 20px;
2257
+ border: 1px solid rgb(144, 147, 153);
2258
+ margin-left: 20px;
2259
+ &.active {
2260
+ border: 2px solid $app-primary-color;
2261
+ }
2262
+ &:hover {
2263
+ cursor: pointer;
2264
+ }
2265
+ &.white {
2266
+ background-color: white;
2267
+ margin-left: 10px;
2268
+ }
2269
+ &.black {
2270
+ background-color: black;
2271
+ }
2272
+ &.lightskyblue {
2273
+ background-color: lightskyblue;
2274
+ }
2275
+ }
2276
+
2277
+ .icon-button {
2278
+ height: 24px !important;
2279
+ width: 24px !important;
2280
+ color: $app-primary-color;
2281
+
2282
+ &.open-map-button {
2283
+ margin-bottom:4px;
2284
+ }
2285
+
2286
+ &:hover {
2287
+ cursor: pointer;
2288
+ }
2289
+ }
2290
+
2291
+ :deep(.maplibregl-ctrl-minimap) {
2292
+ transform-origin: top right;
2293
+ @media (max-width: 1250px) {
2294
+ height: 125px !important; // important is needed here as we are over-riding the style set by the flatmap
2295
+ width: 180px !important;
2296
+ :deep(.maplibregl-canvas .maplibregl-canvas) {
2297
+ height: 125px !important;
2298
+ width: 180px !important;
2299
+ }
2300
+ }
2301
+ @media (min-width: 1251px) {
2302
+ height: 190px !important;
2303
+ width: 300px !important;
2304
+ :deep(.maplibregl-canvas .maplibregl-canvas) {
2305
+ height: 190px !important;
2306
+ width: 300px !important;
2307
+ }
2308
+ }
2309
+ transition: all 1s ease;
2310
+ &.shrink {
2311
+ transform: scale(0.5);
2312
+ transform: scale(0.5);
2313
+ }
2314
+ }
2315
+
2316
+ .minimap-resize {
2317
+ position: absolute;
2318
+ pointer-events: all;
2319
+ cursor: pointer;
2320
+ top: 0;
2321
+ right: 0;
2322
+ padding-top: 3px; // needed as icon is offset
2323
+ width: 20px;
2324
+ height: 14px;
2325
+ z-index: 9;
2326
+ transition: all 1s ease;
2327
+ &.shrink {
2328
+ transform: rotate(0deg);
2329
+ }
2330
+ &.enlarge {
2331
+ transform: rotate(180deg) scale(2);
2332
+ padding-bottom: 5px; // note padding is added to the opposite side since it is rotated
2333
+ padding-left: 5px;
2334
+ }
2335
+ }
2336
+
2337
+ :deep(.flatmap-popper.el-popper) {
2338
+ padding: 6px 4px;
2339
+ font-size: 12px;
2340
+ color: rgb(48, 49, 51);
2341
+ background-color: #f3ecf6;
2342
+ border: 1px solid $app-primary-color;
2343
+ white-space: nowrap;
2344
+ min-width: unset;
2345
+ &.warning-popper {
2346
+ min-width: 150px;
2347
+ max-width: 400px;
2348
+ word-break: keep-all;
2349
+ white-space: unset;
2350
+ }
2351
+ .el-popper__arrow {
2352
+ &:before {
2353
+ border-color: $app-primary-color;
2354
+ background-color: #f3ecf6;
2355
+ }
2356
+ }
2357
+ }
2358
+
2359
+ :deep(.el-loading-spinner) {
2360
+ .path {
2361
+ stroke: $app-primary-color;
2362
+ }
2363
+ .el-loading-text {
2364
+ color: $app-primary-color;
2365
+ }
2366
+ }
2367
+
2368
+ :deep(.flatmap-popup-popper) {
2369
+ .maplibregl-popup-tip {
2370
+ border-bottom-color: $app-primary-color;
2371
+ }
2372
+ .maplibregl-popup-content {
2373
+ padding: 6px 4px;
2374
+ font-size: 12px;
2375
+ color: rgb(48, 49, 51);
2376
+ background-color: #f3ecf6;
2377
+ border: 1px solid $app-primary-color;
2378
+ white-space: nowrap;
2379
+ min-width: unset;
2380
+ .maplibregl-popup-close-button {
2381
+ display: none;
2382
+ }
2383
+ }
2384
+ }
2385
+
2386
+ :deep(.popper-zoomout) {
2387
+ padding-right: 13px !important;
2388
+ left: -21px !important;
2389
+ }
2390
+
2391
+ :deep(.popper-zoomout) {
2392
+ .popper__arrow {
2393
+ left: 53px !important;
2394
+ }
2395
+ }
2396
+
2397
+ :deep(.maplibregl-popup-content) {
2398
+ padding: 0px;
2399
+ }
2400
+
2401
+ .bottom-right-control {
2402
+ position: absolute;
2403
+ right: 16px;
2404
+ bottom: 16px;
2405
+ }
2406
+
2407
+ :deep(.my-drawer) {
2408
+ background: rgba(0, 0, 0, 0);
2409
+ box-shadow: none;
2410
+ }
2411
+
2412
+ .drawer {
2413
+ :deep(.el-drawer:focus) {
2414
+ outline: none;
2415
+ }
2416
+ }
2417
+
2418
+ .open-drawer,
2419
+ .drawer-button {
2420
+ z-index: 8;
2421
+ width: 20px;
2422
+ height: 40px;
2423
+ border: solid 1px $app-primary-color;
2424
+ text-align: center;
2425
+ vertical-align: middle;
2426
+ cursor: pointer;
2427
+ pointer-events: auto;
2428
+ }
2429
+
2430
+ .open-drawer {
2431
+ position: absolute;
2432
+ left: 0px;
2433
+ background-color: #f7faff;
2434
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
2435
+ }
2436
+
2437
+ .drawer-button {
2438
+ float: left;
2439
+ margin-top: calc(50% - 36px);
2440
+ background-color: #f9f2fc;
2441
+
2442
+ i {
2443
+ font-weight: 600;
2444
+ margin-top: 12px;
2445
+ color: $app-primary-color;
2446
+ transition-delay: 0.9s;
2447
+ }
2448
+ &.open {
2449
+ i {
2450
+ transform: rotate(0deg) scaleY(2);
2451
+ }
2452
+ }
2453
+ &.close {
2454
+ i {
2455
+ transform: rotate(180deg) scaleY(2);
2456
+ }
2457
+ }
2458
+ }
2459
+
2460
+ :deep(.maplibregl-canvas-container) {
2461
+ canvas {
2462
+ outline: none;
2463
+ }
2464
+ }
2465
+
2466
+ .backgroundSpacer {
2467
+ border-bottom: 1px solid #e4e7ed;
2468
+ margin-bottom: 10px;
2469
+ }
2470
+
2471
+ .flatmap-radio {
2472
+ :deep(label) {
2473
+ margin-right: 20px;
2474
+ &:last-child {
2475
+ margin-right: 0px;
2476
+ }
2477
+ }
2478
+ :deep(.el-radio__input) {
2479
+ &.is-checked {
2480
+ & + .el-radio__label {
2481
+ color: $app-primary-color;
2482
+ }
2483
+ .el-radio__inner {
2484
+ border-color: $app-primary-color;
2485
+ background: $app-primary-color;
2486
+ }
2487
+ }
2488
+ .el-radio__inner:hover {
2489
+ border-color: $app-primary-color;
2490
+ }
2491
+ }
2492
+ }
2493
+
2494
+ :deep(.custom-popup) {
2495
+ .maplibregl-popup-tip {
2496
+ display: none;
2497
+ }
2498
+ .maplibregl-popup-content {
2499
+ border-radius: 4px;
2500
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
2501
+ pointer-events: none;
2502
+ display: none;
2503
+ background: #fff;
2504
+ font-family: 'Asap', sans-serif;
2505
+ font-size: 12pt;
2506
+ color: $app-primary-color;
2507
+ border: 1px solid $app-primary-color;
2508
+ padding-left: 6px;
2509
+ padding-right: 6px;
2510
+ padding-top: 6px;
2511
+ padding-bottom: 6px;
2512
+ display: flex;
2513
+ justify-content: center;
2514
+ align-items: center;
2515
+ &::after,
2516
+ &::before {
2517
+ content: '';
2518
+ display: block;
2519
+ position: absolute;
2520
+ width: 0;
2521
+ height: 0;
2522
+ border-style: solid;
2523
+ flex-shrink: 0;
2524
+ }
2525
+ .maplibregl-popup-close-button {
2526
+ display: none;
2527
+ }
2528
+ }
2529
+ &.maplibregl-popup-anchor-bottom {
2530
+ .maplibregl-popup-content {
2531
+ margin-bottom: 12px;
2532
+ &::after,
2533
+ &::before {
2534
+ top: 100%;
2535
+ border-width: 12px;
2536
+ }
2537
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
2538
+ &::after {
2539
+ margin-top: -1px;
2540
+ border-color: rgb(255, 255, 255) transparent transparent transparent;
2541
+ }
2542
+ /* this border color controlls the outside, thin border */
2543
+ &::before {
2544
+ margin: 0 auto;
2545
+ border-color: $app-primary-color transparent transparent transparent;
2546
+ }
2547
+ }
2548
+ }
2549
+ &.maplibregl-popup-anchor-top {
2550
+ .maplibregl-popup-content {
2551
+ margin-top: 18px;
2552
+ &::after,
2553
+ &::before {
2554
+ top: calc(-100% + 6px);
2555
+ border-width: 12px;
2556
+ }
2557
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
2558
+ &::after {
2559
+ margin-top: 1px;
2560
+ border-color: transparent transparent rgb(255, 255, 255) transparent;
2561
+ }
2562
+ &::before {
2563
+ margin: 0 auto;
2564
+ border-color: transparent transparent $app-primary-color transparent;
2565
+ }
2566
+ }
2567
+ }
2568
+ }
2569
+
2570
+ .select-box {
2571
+ border-radius: 4px;
2572
+ border: 1px solid rgb(144, 147, 153);
2573
+ background-color: var(--white);
2574
+ font-weight: 500;
2575
+ color: rgb(48, 49, 51);
2576
+ width: 150px!important;
2577
+ }
2578
+
2579
+ :deep(.flatmap_dropdown) {
2580
+ min-width: 160px !important;
2581
+ .el-select-dropdown__item {
2582
+ white-space: nowrap;
2583
+ text-align: left;
2584
+ &.is-selected {
2585
+ color: $app-primary-color;
2586
+ font-weight: normal;
2587
+ }
2588
+ }
2589
+ }
2590
+ </style>
2591
+
2592
+ <style lang="scss">
2593
+
2594
+ .flatmap-container {
2595
+ --el-color-primary: #8300BF;
2596
+ --el-color-primary-light-5: #CD99E5;
2597
+ --el-color-primary-light-9: #F3E6F9;
2598
+ --el-color-primary-dark-2: var(--el-color-primary);
2599
+ }
2600
+
2532
2601
  </style>