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