@abi-software/flatmapvuer 0.4.2 → 0.4.4

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.
@@ -1,1627 +1,1627 @@
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 style="height:100%;width:100%;position:relative;overflow-y:none">
12
- <div style="height:100%;width:100%;" ref="display"></div>
13
- <div class="beta-popovers">
14
- <div>
15
- <el-popover
16
- :content="getWarningMessage"
17
- placement="right"
18
- :appendToBody="false"
19
- trigger="manual"
20
- popper-class="warning-popper flatmap-popper right-popper"
21
- v-model="hoverVisibilities[6].value"
22
- ref="warningPopover"
23
- ></el-popover>
24
- <i
25
- class="el-icon-warning warning-icon"
26
- v-if="displayWarning"
27
- @mouseover="showToolitip(6)"
28
- @mouseout="hideToolitip(6)"
29
- v-popover:warningPopover
30
- >
31
- <template v-if="isLegacy">
32
- <span class="warning-text">Legacy Map</span>
33
- <div class="latest-map-text" @click="viewLatestMap">Click here for the latest map</div>
34
- </template>
35
- <template v-else>
36
- <span class="warning-text">Beta</span>
37
- </template>
38
- </i>
39
- </div>
40
- <el-popover
41
- :content="latestChangesMessage"
42
- placement="right"
43
- v-if="displayLatestChanges"
44
- :appendToBody="false"
45
- trigger="manual"
46
- popper-class="warning-popper flatmap-popper right-popper"
47
- v-model="hoverVisibilities[7].value"
48
- ref="latestChangesPopover"
49
- ></el-popover>
50
- <i
51
- class="el-icon-warning latest-changesicon"
52
- v-if="displayLatestChanges && latestChangesMessage"
53
- @mouseover="showToolitip(7)"
54
- @mouseout="hideToolitip(7)"
55
- v-popover:latestChangesPopover
56
- >
57
- <span class="warning-text">What's new?</span>
58
- </i>
59
- </div>
60
-
61
- <!-- The element below is placed onto the flatmap when it is ready -->
62
- <i class="el-icon-arrow-down minimap-resize" :class="{ enlarge: minimapSmall, shrink: !minimapSmall}" ref="minimapResize" v-show="minimapResizeShow" @click="closeMinimap"></i>
63
-
64
- <div class="bottom-right-control">
65
- <el-popover
66
- content="Zoom in"
67
- placement="left"
68
- :appendToBody="false"
69
- trigger="manual"
70
- popper-class="flatmap-popper left-popper"
71
- v-model="hoverVisibilities[0].value"
72
- >
73
- <map-svg-icon
74
- icon="zoomIn"
75
- class="icon-button zoomIn"
76
- slot="reference"
77
- @click.native="zoomIn()"
78
- @mouseover.native="showToolitip(0)"
79
- @mouseout.native="hideToolitip(0)"
80
- />
81
- </el-popover>
82
- <el-popover
83
- content="Zoom out"
84
- placement="top-end"
85
- :appendToBody="false"
86
- trigger="manual"
87
- popper-class="flatmap-popper popper-zoomout"
88
- v-model="hoverVisibilities[1].value"
89
- >
90
- <map-svg-icon
91
- icon="zoomOut"
92
- class="icon-button zoomOut"
93
- slot="reference"
94
- @click.native="zoomOut()"
95
- @mouseover.native="showToolitip(1)"
96
- @mouseout.native="hideToolitip(1)"
97
- />
98
- </el-popover>
99
- <el-popover
100
- content="Reset"
101
- placement="top"
102
- :appendToBody="false"
103
- trigger="manual"
104
- popper-class="flatmap-popper"
105
- v-model="hoverVisibilities[2].value"
106
- >
107
- <div>
108
- Fit to
109
- <br>
110
- window
111
- </div>
112
- <map-svg-icon
113
- slot="reference"
114
- icon="fitWindow"
115
- class="icon-button fitWindow"
116
- @click.native="resetView()"
117
- @mouseover.native="showToolitip(2)"
118
- @mouseout.native="hideToolitip(2)"
119
- />
120
- </el-popover>
121
- </div>
122
- <el-popover
123
- content="Change pathway visibility"
124
- placement="right"
125
- :appendToBody="false"
126
- trigger="manual"
127
- popper-class="flatmap-popper right-popper"
128
- v-model="hoverVisibilities[4].value"
129
- ref="checkBoxPopover"
130
- />
131
- <div class="pathway-location" :class="{ open: drawerOpen, close: !drawerOpen }">
132
- <div
133
- class="pathway-container"
134
- :style="{'max-height': pathwaysMaxHeight + 'px'}"
135
- v-if="pathControls"
136
- v-popover:checkBoxPopover
137
- >
138
- <svg-legends v-if="!isFC" class="svg-legends-container"/>
139
- <el-popover
140
- content="Find these markers for data"
141
- placement="right"
142
- :appendToBody="false"
143
- trigger="manual"
144
- popper-class="flatmap-popper popper-bump-right right-popper"
145
- v-model="hoverVisibilities[5].value"
146
- ref="markerPopover"
147
- ></el-popover>
148
- <div
149
- v-show="hoverVisibilities[5].value"
150
- class="flatmap-marker-help"
151
- v-html="flatmapMarker"
152
- v-popover:markerPopover
153
- ></div>
154
- <selections-group
155
- v-if="isFC && systems && systems.length > 0"
156
- title="Systems"
157
- labelKey="name"
158
- identifierKey="id"
159
- :selections="systems"
160
- colourStyle="background"
161
- @changed="systemSelected"
162
- @checkAll="checkAllSystems"
163
- ref="systemsSelection"
164
- key="systemsSelection"
165
- />
166
- <!--
167
- <selections-group
168
- v-if="!isFC && centreLines && centreLines.length > 0"
169
- title="Nerves"
170
- labelKey="label"
171
- identifierKey="key"
172
- :selections="centreLines"
173
- @changed="centreLinesSelected"
174
- ref="centrelinesSelection"
175
- key="centrelinesSelection"
176
- />
177
- <selections-group
178
- v-if="isFC && sckanDisplay && sckanDisplay.length > 0"
179
- title="SCKAN"
180
- labelKey="label"
181
- identifierKey="key"
182
- :selections="sckanDisplay"
183
- @changed="sckanSelected"
184
- @checkAll="checkAllSCKAN"
185
- ref="skcanSelection"
186
- key="skcanSelection"
187
- />
188
- <selections-group
189
- v-if="layers && layers.length > 0"
190
- title="Layers"
191
- labelKey="description"
192
- identifierKey="id"
193
- :selections="layers"
194
- @changed="layersSelected"
195
- @checkAll="checkAllLayers"
196
- ref="layersSelection"
197
- key="layersSelection"
198
- />
199
- -->
200
- <selections-group
201
- v-if="pathways && pathways.length > 0"
202
- title="Pathways"
203
- labelKey="label"
204
- identifierKey="type"
205
- colourStyle="line"
206
- :selections="pathways"
207
- @changed="pathwaysSelected"
208
- @checkAll="checkAllPathways"
209
- ref="pathwaysSelection"
210
- key="pathwaysSelection"
211
- />
212
- </div>
213
- <div
214
- @click="toggleDrawer"
215
- class="drawer-button"
216
- :class="{ open: drawerOpen, close: !drawerOpen }"
217
- >
218
- <i class="el-icon-arrow-left"></i>
219
- </div>
220
- </div>
221
- <el-popover
222
- ref="backgroundPopover"
223
- placement="top-start"
224
- width="175"
225
- :appendToBody="false"
226
- trigger="click"
227
-
228
- popper-class="background-popper"
229
- >
230
- <el-row class="backgroundText">Organs display</el-row>
231
- <el-row class="backgroundControl">
232
- <el-radio-group v-model="colourRadio" class="flatmap-radio" @change="setColour">
233
- <el-radio :label="true">Colour</el-radio>
234
- <el-radio :label="false">Greyscale</el-radio>
235
- </el-radio-group>
236
- </el-row>
237
- <el-row class="backgroundSpacer"></el-row>
238
- <el-row class="backgroundText">Outlines display</el-row>
239
- <el-row class="backgroundControl">
240
- <el-radio-group v-model="outlinesRadio" class="flatmap-radio" @change="setOutlines">
241
- <el-radio :label="true">Show</el-radio>
242
- <el-radio :label="false">Hide</el-radio>
243
- </el-radio-group>
244
- </el-row>
245
- <el-row class="backgroundSpacer"></el-row>
246
- <el-row class="backgroundText">Change background</el-row>
247
- <el-row class="backgroundControl">
248
- <div
249
- v-for="item in availableBackground"
250
- :key="item"
251
- :class="['backgroundChoice', item, item == currentBackground ? 'active' :'']"
252
- @click="backgroundChangeCallback(item)"
253
- />
254
- </el-row>
255
- </el-popover>
256
- <el-popover
257
- content="Change settings"
258
- placement="right"
259
- v-model="hoverVisibilities[3].value"
260
- :appendToBody="false"
261
- trigger="manual"
262
- popper-class="flatmap-popper right-popper"
263
- >
264
- <map-svg-icon
265
- v-popover:backgroundPopover
266
- icon="changeBckgd"
267
- class="icon-button background-colour"
268
- :class="{ open: drawerOpen, close: !drawerOpen }"
269
- slot="reference"
270
- @mouseover.native="showToolitip(3)"
271
- @mouseout.native="hideToolitip(3)"
272
- />
273
- </el-popover>
274
- <Tooltip
275
- ref="tooltip"
276
- class="tooltip"
277
- :entry="tooltipEntry"
278
- @resource-selected="resourceSelected"
279
- />
280
- </div>
281
- </div>
282
- </template>
283
-
284
- <script>
285
- /* eslint-disable no-alert, no-console */
286
- import Vue from "vue";
287
- import Tooltip from "./Tooltip";
288
- import SelectionsGroup from "./SelectionsGroup.vue";
289
- import { MapSvgIcon, MapSvgSpriteColor } from "@abi-software/svg-sprite";
290
- import SvgLegends from "./legends/SvgLegends";
291
- import {
292
- Col,
293
- Loading,
294
- Radio,
295
- RadioGroup,
296
- Row
297
- } from "element-ui";
298
- import lang from "element-ui/lib/locale/lang/en";
299
- import locale from "element-ui/lib/locale";
300
- import flatmapMarker from "../icons/flatmap-marker";
301
- import {FlatmapQueries} from "../services/flatmapQueries.js";
302
-
303
- locale.use(lang);
304
- Vue.use(Col);
305
- Vue.use(Loading.directive);
306
- Vue.use(Radio);
307
- Vue.use(RadioGroup);
308
- Vue.use(Row);
309
- const ResizeSensor = require("css-element-queries/src/ResizeSensor");
310
-
311
- const createUnfilledTooltipData = function (){
312
- return {
313
- destinations: [],
314
- origins: [],
315
- components: [],
316
- destinationsWithDatasets: [],
317
- originsWithDatasets: [],
318
- componentsWithDatasets: [],
319
- resource: undefined
320
- }
321
- }
322
-
323
- export default {
324
- name: "FlatmapVuer",
325
- components: {
326
- MapSvgIcon,
327
- MapSvgSpriteColor,
328
- Tooltip,
329
- SelectionsGroup,
330
- SvgLegends
331
- },
332
- beforeCreate: function() {
333
- this.mapManager = undefined;
334
- this.mapImp = undefined;
335
- //The state watcher may triggered before
336
- //created causing issue, This flag will
337
- //resolve this issue.
338
- this.setStateRequired = false;
339
- },
340
- methods: {
341
- viewLatestMap: function() {
342
- let biologicalSex = this.biologicalSex ? this.biologicalSex : undefined;
343
- //Human requires special handling
344
- if (this.entry === "NCBITaxon:9606") {
345
- biologicalSex = "PATO:0000384";
346
- }
347
- const state = {
348
- entry: this.entry,
349
- biologicalSex,
350
- viewport: this.mapImp.getState()
351
- };
352
- this.$emit("view-latest-map", state);
353
- },
354
- backgroundChangeCallback: function(colour) {
355
- this.currentBackground = colour;
356
- if (this.mapImp) {
357
- this.mapImp.setBackgroundColour(this.currentBackground, 1);
358
- }
359
- },
360
- toggleDrawer: function() {
361
- this.drawerOpen = !this.drawerOpen;
362
- },
363
- /**
364
- * Function to toggle colour/greyscale of organs.
365
- */
366
- setColour: function(flag) {
367
- this.colourRadio = flag;
368
- if (this.mapImp) {
369
- this.mapImp.setColour({ colour: flag, outline: this.outlinesRadio });
370
- }
371
- },
372
- /**
373
- * Function to toggle outlines f organs.
374
- */
375
- setOutlines: function(flag) {
376
- this.outlineRadio = flag;
377
- if (this.mapImp) {
378
- this.mapImp.setColour({ colour: this.colourRadio, outline: flag });
379
- }
380
- },
381
- /**
382
- * Function to toggle paths to default.
383
- * Also called when the associated button is pressed.
384
- */
385
- resetView: function() {
386
- if (this.mapImp) {
387
- this.mapImp.resetMap();
388
- if (this.$refs.centrelinesSelection) {
389
- this.$refs.centrelinesSelection.reset();
390
- }
391
- if (this.$refs.skcanSelection) {
392
- this.$refs.skcanSelection.reset();
393
- }
394
- if (this.$refs.layersSelection) {
395
- this.$refs.layersSelection.reset();
396
- }
397
- if (this.$refs.systemsSelection) {
398
- this.$refs.pathwaysSelection.reset();
399
- }
400
- if (this.$refs.pathwaysSelection) {
401
- this.$refs.pathwaysSelection.reset();
402
- }
403
- }
404
- },
405
- /**
406
- * Function to zoom in.
407
- * Also called when the associated button is pressed.
408
- */
409
- zoomIn: function() {
410
- if (this.mapImp) {
411
- this.mapImp.zoomIn();
412
- }
413
- },
414
- /**
415
- * Function to zoom out.
416
- * Also called when the associated button is pressed.
417
- */
418
- zoomOut: function() {
419
- if (this.mapImp) {
420
- this.mapImp.zoomOut();
421
- }
422
- },
423
- centreLinesSelected: function(payload) {
424
- if (this.mapImp) {
425
- this.mapImp.enableCentrelines(payload.value);
426
- }
427
- },
428
- sckanSelected: function(payload) {
429
- if (this.mapImp) {
430
- this.mapImp.enableSckanPath(payload.key, payload.value);
431
- }
432
- },
433
- checkAllSCKAN: function(payload) {
434
- if (this.mapImp) {
435
- payload.keys.forEach(key => this.mapImp.enableSckanPath(key, payload.value));
436
- }
437
- },
438
- systemSelected: function(payload) {
439
- if (this.mapImp) {
440
- this.mapImp.enableSystem(payload.key, payload.value);
441
- }
442
- },
443
- checkAllSystems: function(payload) {
444
- if (this.mapImp) {
445
- payload.keys.forEach(key => this.mapImp.enableSystem(key, payload.value));
446
- }
447
- },
448
- layersSelected: function(payload) {
449
- if (this.mapImp) {
450
- this.mapImp.enableLayer(payload.key, payload.value);
451
- }
452
- },
453
- checkAllLayers: function(payload) {
454
- if (this.mapImp) {
455
- payload.keys.forEach(key => this.mapImp.enableLayer(key, payload.value));
456
- }
457
- },
458
- pathwaysSelected: function(payload) {
459
- if (this.mapImp) {
460
- this.mapImp.enablePath(payload.key, payload.value);
461
- }
462
- },
463
- checkAllPathways: function(payload) {
464
- if (this.mapImp) {
465
- payload.keys.forEach(key => this.mapImp.enablePath(key, payload.value));
466
- }
467
- },
468
- enablePanZoomEvents: function(flag) {
469
- this.mapImp.enablePanZoomEvents(flag);
470
- },
471
- eventCallback: function() {
472
- return (eventType, data, ...args) => {
473
- if (eventType !== "pan-zoom") {
474
- const label = data.label;
475
- const resource = [data.models];
476
- const taxonomy = this.entry;
477
- const biologicalSex = this.biologicalSex;
478
- const payload = {
479
- dataset: data.dataset,
480
- biologicalSex: biologicalSex,
481
- taxonomy: taxonomy,
482
- resource: resource,
483
- label: label,
484
- feature: data,
485
- userData: args,
486
- eventType: eventType
487
- };
488
- if (data && data.type !== "marker" && eventType === "click"){
489
- this.checkAndCreatePopups(payload);
490
- }
491
- this.$emit("resource-selected", payload);
492
- } else {
493
- this.$emit("pan-zoom-callback", data);
494
- }
495
- };
496
- },
497
- // checkNeuronClicked shows a neuron path pop up if a path was recently clicked
498
- checkAndCreatePopups: async function(data) {
499
- // Call flatmap database to get the connection data
500
- let results = await this.flatmapQueries.retrieveFlatmapKnowledgeForEvent(data)
501
- if(!results){
502
- if(data.feature.hyperlinks && data.feature.hyperlinks.length > 0){
503
- this.resourceForTooltip = data.resource[0];
504
- this.createTooltipFromNeuronCuration(data);
505
- }
506
- } else {
507
- this.resourceForTooltip = data.resource[0];
508
- this.createTooltipFromNeuronCuration(data);
509
- }
510
- },
511
- popUpCssHacks: function() {
512
- // Below is a hack to remove flatmap tooltips while popup is open
513
- let ftooltip = document.querySelector(".flatmap-tooltip-popup");
514
- if (ftooltip) ftooltip.style.display = "none";
515
- document.querySelector(".mapboxgl-popup-close-button").style.display =
516
- "block";
517
- this.$refs.tooltip.$el.style.display = "flex";
518
- document.querySelector(".mapboxgl-popup-close-button").onclick = () => {
519
- document.querySelector(".flatmap-tooltip-popup").style.display =
520
- "block";
521
- };
522
- },
523
- resourceSelected: function(action) {
524
- this.$emit("resource-selected", action);
525
- },
526
- createTooltipFromNeuronCuration: function(data) {
527
- this.tooltipEntry = this.flatmapQueries.createTooltipData(data);
528
- this.displayTooltip();
529
- },
530
- // Keeping this as an API
531
- showPopup: function(featureId, node, options) {
532
- let myOptions = options;
533
- if (this.mapImp) {
534
- if (myOptions) {
535
- if (!myOptions.className) myOptions.className = "custom-popup";
536
- } else {
537
- myOptions = { className: "custom-popup", positionAtLastClick: true };
538
- }
539
- this.mapImp.showPopup(featureId, node, myOptions);
540
- }
541
- },
542
- showMarkerPopup: function(featureId, node, options) {
543
- if (this.mapImp) {
544
- this.mapImp.showMarkerPopup(featureId, node, options);
545
- }
546
- },
547
- closeMinimap: function(){
548
- let minimapEl = this.$refs.flatmapContainer.querySelector('.maplibregl-ctrl-minimap'); // find minimap
549
- if (this.minimapSmall) { //switch the classes on the minimap
550
- minimapEl.classList.add('enlarge');
551
- minimapEl.classList.remove('shrink');
552
- } else {
553
- minimapEl.classList.add('shrink');
554
- minimapEl.classList.remove('enlarge');
555
- }
556
- this.minimapSmall = !this.minimapSmall;
557
- },
558
- addResizeButtonToMinimap: function(){
559
- let minimapEl = this.$refs.flatmapContainer.querySelector('.maplibregl-ctrl-minimap');
560
- if (minimapEl){
561
- this.$refs.minimapResize.parentNode.removeChild(this.$refs.minimapResize);
562
- minimapEl.appendChild(this.$refs.minimapResize);
563
- this.minimapResizeShow = true;
564
- }
565
- },
566
- setHelpMode: function(helpMode) {
567
- if (helpMode) {
568
- this.inHelp = true;
569
- this.hoverVisibilities.forEach(item => {
570
- item.value = true;
571
- });
572
- this.openFlatmapHelpPopup();
573
- } else {
574
- this.inHelp = false;
575
- this.hoverVisibilities.forEach(item => {
576
- item.value = false;
577
- });
578
- this.closeFlatmapHelpPopup();
579
- }
580
- },
581
- showToolitip: function(tooltipNumber) {
582
- if (!this.inHelp) {
583
- this.tooltipWait = setTimeout(() => {
584
- this.hoverVisibilities[tooltipNumber].value = true;
585
- }, 500);
586
- }
587
- },
588
- hideToolitip: function(tooltipNumber) {
589
- if (!this.inHelp) {
590
- this.hoverVisibilities[tooltipNumber].value = false;
591
- clearTimeout(this.tooltipWait);
592
- }
593
- },
594
- displayTooltip: function() {
595
- this.mapImp.showPopup(
596
- this.mapImp.modelFeatureIds(this.resourceForTooltip)[0],
597
- this.$refs.tooltip.$el,
598
- { className: "flatmapvuer-popover", positionAtLastClick: true }
599
- );
600
- this.popUpCssHacks();
601
- },
602
- openFlatmapHelpPopup: function() {
603
- if (this.mapImp) {
604
- let heartId = this.mapImp.featureIdsForModel("UBERON:0000948")[0];
605
- const elm = "Click for more information";
606
- this.mapImp.showPopup(heartId, elm, {
607
- anchor: "top",
608
- className: "flatmap-popup-popper"
609
- });
610
- }
611
- },
612
- closeFlatmapHelpPopup: function() {
613
- this.$el
614
- .querySelectorAll(".mapboxgl-popup-close-button")
615
- .forEach(item => {
616
- item.click();
617
- });
618
- },
619
- getLabels: function() {
620
- let labels = [];
621
- if (this.mapImp) {
622
- let annotations = this.mapImp.annotations;
623
- for (let value of annotations.values()) {
624
- if (value.label) labels.push(value.label);
625
- }
626
- return Array.from(new Set(labels));
627
- }
628
- },
629
- getState: function() {
630
- if (this.mapImp) {
631
- let state = {
632
- entry: this.entry,
633
- viewport: this.mapImp.getState()
634
- };
635
- const identifier = this.mapImp.getIdentifier();
636
- if (this.biologicalSex)
637
- state['biologicalSex'] = this.biologicalSex;
638
- else if (identifier && identifier.biologicalSex)
639
- state['biologicalSex'] = identifier.biologicalSex;
640
- if (identifier && identifier.uuid)
641
- state['uuid'] = identifier.uuid;
642
- return state;
643
- }
644
- return undefined;
645
- },
646
- setState: function(state) {
647
- if (state) {
648
- if (this.mapImp &&
649
- (state.entry && (this.entry == state.entry)) &&
650
- (!state.biologicalSex || (state.biologicalSex === this.biologicalSex)))
651
- {
652
- if (state.viewport) {
653
- this.mapImp.setState(state.viewport);
654
- }
655
- } else {
656
- this.createFlatmap(state);
657
- }
658
- this.setStateRequired = false;
659
- }
660
- },
661
- restoreMapState: function(state) {
662
- if (state) {
663
- if (state.viewport)
664
- this.mapImp.setState(state.viewport);
665
- if (state.searchTerm)
666
- this.searchAndShowResult(state.searchTerm, true);
667
- }
668
- },
669
- createFlatmap: function(state) {
670
- if (!this.mapImp && !this.loading) {
671
- this.loading = true;
672
- let minimap = false;
673
- if (this.displayMinimap) {
674
- minimap = { position: "top-right" };
675
- }
676
-
677
- //As for flatmap-viewer@2.2.7, see below for the documentation
678
- //for the identifier:
679
-
680
- //@arg identifier {string|Object}
681
- // A string or object identifying the map to load. If a string its
682
- // value can be either the map's ``uuid``, assigned at generation time,
683
- // or taxon and biological sex identifiers of the species that the map
684
- // represents. The latest version of a map is loaded unless it has been
685
- // identified using a ``uuid`` (see below).
686
- // @arg identifier.taxon {string} The taxon identifier of the species
687
- // represented by the map. This is specified as metadata in the map's source file.
688
- // @arg identifier.biologicalSex {string} The biological sex of the species
689
- // represented by the map. This is specified as metadatain the map's source file.
690
- // @arg identifier.uuid {string} The unique uuid the flatmap. If given then this exact map will
691
- // be loaded, overriding ``taxon`` and ``biologicalSex``.
692
-
693
- let identifier = { taxon: this.entry };
694
- //This now handle the uses of uuid when resuming states
695
- if (state) {
696
- if (state.uuid) {
697
- identifier = { uuid: state.uuid };
698
- } else if (state.entry) {
699
- identifier.taxon = state.entry;
700
- if (state.biologicalSex) {
701
- identifier["biologicalSex"] = state.biologicalSex;
702
- } else if (identifier.taxon === "NCBITaxon:9606") {
703
- //For backward compatibility
704
- identifier["biologicalSex"] ="PATO:0000384";
705
- }
706
- }
707
- } else {
708
- // Set the bioloicalSex now if map is not resumed from
709
- // a saved state
710
- if (this.biologicalSex) {
711
- identifier["biologicalSex"] = this.biologicalSex;
712
- }
713
- }
714
-
715
- let promise1 = this.mapManager.loadMap(
716
- identifier,
717
- this.$refs.display,
718
- this.eventCallback(),
719
- {
720
- //fullscreenControl: false,
721
- //annotatable: false,
722
- //debug: true,
723
- featureInfo: this.featureInfo,
724
- "min-zoom": this.minZoom,
725
- layerControl: true,
726
- pathControls: true,
727
- searchable: this.searchable,
728
- tooltips: this.tooltips,
729
- minimap: minimap
730
- }
731
- );
732
- promise1.then(returnedObject => {
733
- this.mapImp = returnedObject;
734
- this.onFlatmapReady();
735
- if (this._stateToBeSet)
736
- this.restoreMapState(this._stateToBeSet);
737
- else {
738
- this.restoreMapState(state);
739
- }
740
- });
741
- } else if (state) {
742
- this._stateToBeSet = { viewport: state.viewport, searchTerm: state.searchTerm };
743
- if (this.mapImp && !this.loading)
744
- this.restoreMapState(this._stateToBeSet);
745
- }
746
- },
747
- computePathControlsMaximumHeight() {
748
- const elem = this.$refs.display;
749
- if (elem) {
750
- const computed = getComputedStyle(elem);
751
- const padding = parseInt(computed.paddingTop) + parseInt(computed.paddingBottom);
752
- const height = elem.clientHeight - padding;
753
- this.pathwaysMaxHeight = height - 170;
754
- }
755
- },
756
- mapResize: function() {
757
- try {
758
- this.computePathControlsMaximumHeight();
759
- if (this.mapImp) {
760
- this.mapImp.resize();
761
- this.showMinimap(this.displayMinimap);
762
- if (this.mapImp._minimap) {
763
- this.mapImp._minimap.resize();
764
- }
765
- }
766
- } catch {
767
- console.error("Map resize error");
768
- }
769
- },
770
- onFlatmapReady: function(){
771
- // onFlatmapReady is used for functions that need to run immediately after the flatmap is loaded
772
- this.sensor = new ResizeSensor(
773
- this.$refs.display,
774
- this.mapResize
775
- );
776
- if (this.mapImp.options && this.mapImp.options.style === "functional") {
777
- this.isFC = true;
778
- }
779
- this.mapImp.setBackgroundOpacity(1);
780
- this.backgroundChangeCallback(this.currentBackground);
781
- this.pathways = this.mapImp.pathTypes();
782
- this.mapImp.enableCentrelines(false);
783
- //Disable layers for now
784
- //this.layers = this.mapImp.getLayers();
785
- this.systems = this.mapImp.getSystems();
786
- this.addResizeButtonToMinimap();
787
- this.loading = false;
788
- this.computePathControlsMaximumHeight();
789
- this.drawerOpen = true;
790
- this.mapResize();
791
- this.$emit("ready", this);
792
- },
793
- showMinimap: function(flag) {
794
- if (this.mapImp)
795
- this.mapImp.showMinimap(flag);
796
- },
797
- showPathwaysDrawer: function(flag) {
798
- this.drawerOpen = flag;
799
- },
800
- /**
801
- * Function to display features with annotation matching the provided term,
802
- * with the option to display the label using displayLabel flag.
803
- */
804
- searchAndShowResult: function(term, displayLabel) {
805
- if (this.mapImp) {
806
- if (term === undefined || term === "") {
807
- this.mapImp.clearSearchResults();
808
- return true;
809
- } else {
810
- const searchResults = this.mapImp.search(term);
811
- if (searchResults && searchResults.results &&
812
- searchResults.results.length > 0) {
813
- this.mapImp.showSearchResults(searchResults);
814
- if (displayLabel &&
815
- searchResults.results[0].featureId &&
816
- searchResults.results[0].text) {
817
- this.mapImp.showPopup(
818
- searchResults.results[0].featureId,
819
- searchResults.results[0].text,
820
- { className: "custom-popup", positionAtLastClick: false, preserveSelection: true }
821
- )
822
- }
823
- return true;
824
- }
825
- else
826
- this.mapImp.clearSearchResults();
827
- }
828
- }
829
- return false;
830
- },
831
- /**
832
- * Get the list of suggested terms
833
- */
834
- searchSuggestions: function(term) {
835
- if (this.mapImp)
836
- return this.mapImp.search(term);
837
- return [];
838
- },
839
- },
840
- props: {
841
- entry: String,
842
- biologicalSex: {
843
- type: String,
844
- default: ""
845
- },
846
- featureInfo: {
847
- type: Boolean,
848
- default: false
849
- },
850
- minZoom: {
851
- type: Number,
852
- default: 4
853
- },
854
- pathControls: {
855
- type: Boolean,
856
- default: false
857
- },
858
- searchable: {
859
- type: Boolean,
860
- default: false
861
- },
862
- layerControl: {
863
- type: Boolean,
864
- default: false
865
- },
866
- tooltips: {
867
- type: Boolean,
868
- default: true
869
- },
870
- helpMode: {
871
- type: Boolean,
872
- default: false
873
- },
874
- renderAtMounted: {
875
- type: Boolean,
876
- default: true
877
- },
878
- displayMinimap: {
879
- type: Boolean,
880
- default: false
881
- },
882
- displayWarning: {
883
- type: Boolean,
884
- default: false
885
- },
886
- isLegacy: {
887
- type: Boolean,
888
- default: false
889
- },
890
- displayLatestChanges: {
891
- type: Boolean,
892
- default: false,
893
- },
894
- latestChangesMessage: {
895
- type: String,
896
- default: "Search now provide suggested terms. Add new legends. New tilesets. New female map. Improve upstream downstream information.",
897
- },
898
- /**
899
- * State containing state of the flatmap.
900
- */
901
- state: {
902
- type: Object,
903
- default: undefined
904
- },
905
- /**
906
- * Specify the endpoint of the flatmap server.
907
- */
908
- flatmapAPI: {
909
- type: String,
910
- default: "https://mapcore-demo.org/current/flatmap/v3/"
911
- },
912
- sparcAPI: {
913
- type: String,
914
- default: "https://api.sparc.science/"
915
- },
916
- },
917
- provide() {
918
- return {
919
- sparcAPI: this.sparcAPI,
920
- flatmapAPI: this.flatmapAPI
921
- }
922
- },
923
- data: function() {
924
- return {
925
- layers: [],
926
- pathways: [],
927
- sckanDisplay: [
928
- {
929
- label: "Display Path with SCKAN",
930
- key: "VALID",
931
- },
932
- ],
933
- centreLines: [
934
- {
935
- label: "Display Nerves",
936
- key: "centrelines",
937
- enabled: false
938
- }
939
- ],
940
- systems: [],
941
- pathwaysMaxHeight: 1000,
942
- hoverVisibilities: [
943
- { value: false },
944
- { value: false },
945
- { value: false },
946
- { value: false },
947
- { value: false },
948
- { value: false },
949
- { value: false },
950
- { value: false }
951
- ],
952
- isFC: false,
953
- inHelp: false,
954
- currentBackground: "white",
955
- availableBackground: ["white", "lightskyblue", "black"],
956
- loading: false,
957
- flatmapMarker: flatmapMarker,
958
- tooltipEntry: createUnfilledTooltipData(),
959
- connectivityTooltipVisible: false,
960
- resourceForTooltip: undefined,
961
- drawerOpen: false,
962
- colourRadio: true,
963
- outlinesRadio: true,
964
- minimapResizeShow: false,
965
- minimapSmall: false,
966
- };
967
- },
968
- watch: {
969
- entry: function() {
970
- if (!this.state) this.createFlatmap();
971
- },
972
- helpMode: function(val) {
973
- this.setHelpMode(val);
974
- },
975
- state: {
976
- handler: function(state) {
977
- if (this.mapManager) {
978
- this.setState(state);
979
- } else {
980
- //this component has not been mounted yet
981
- this.setStateRequired = true;
982
- }
983
- },
984
- immediate: true,
985
- deep: true
986
- }
987
- },
988
- computed: {
989
- getWarningMessage: function() {
990
- if (this.isLegacy) {
991
- return "This is a legacy map, you may view the latest map instead.";
992
- } else if (this.isFC) {
993
- return "Beta feature - The connectivity shown here is the subset of neurons from the neuron populations in ApiNATOMY models which are at the same spatial scale and level of granularity.";
994
- }
995
- return "Beta feature - This map is based on the connectivity of a rat. New connectivity and species specificity will be added as the SPARC program progress.";
996
- },
997
- },
998
- mounted: function() {
999
- const flatmap = require("@abi-software/flatmap-viewer");
1000
- this.mapManager = new flatmap.MapManager(this.flatmapAPI);
1001
- this.flatmapQueries = new FlatmapQueries();
1002
- this.flatmapQueries.initialise(this.sparcAPI, this.flatmapAPI);
1003
- if (this.state) {
1004
- //State is set and require to set the state
1005
- if (this.setStateRequired) {
1006
- this.setState(this.state);
1007
- }
1008
- } else if(this.renderAtMounted) {
1009
- this.createFlatmap();
1010
- }
1011
- }
1012
- };
1013
- </script>
1014
-
1015
- <!-- Add "scoped" attribute to limit CSS to this component only -->
1016
- <style scoped lang="scss">
1017
- @import "~element-ui/packages/theme-chalk/src/button";
1018
- @import "~element-ui/packages/theme-chalk/src/loading";
1019
- @import "~element-ui/packages/theme-chalk/src/row";
1020
-
1021
- .beta-popovers {
1022
- position: absolute;
1023
- top: 90px;
1024
- left: 16px;
1025
- text-align: left;
1026
- font-size: 25px;
1027
- }
1028
-
1029
- .warning-icon {
1030
- color: $warning;
1031
-
1032
- &:hover {
1033
- cursor: pointer;
1034
- }
1035
- }
1036
-
1037
- .warning-text {
1038
- font-family: Asap, sans-serif;
1039
- font-size: 15px;
1040
- vertical-align: 5px;
1041
- }
1042
-
1043
- .latest-map-text {
1044
- color: $app-primary-color;;
1045
- font-family: Asap, sans-serif;
1046
- font-size: 12px;
1047
- margin-top: 5px;
1048
- vertical-align: 10px;
1049
- cursor: pointer;
1050
- }
1051
-
1052
- .latest-changesicon {
1053
- color: $success;
1054
-
1055
- &:hover {
1056
- cursor: pointer;
1057
- }
1058
- }
1059
-
1060
- .latest-changestext {
1061
- font-family: Asap, sans-serif;
1062
- font-size: 15px;
1063
- vertical-align: 5px;
1064
- }
1065
-
1066
- .flatmap-container {
1067
- height: 100%;
1068
- width: 100%;
1069
- }
1070
-
1071
- .pathway-location {
1072
- position: absolute;
1073
- bottom: 0px;
1074
- transition: all 1s ease;
1075
- &.open {
1076
- left: 0px;
1077
- }
1078
- &.close {
1079
- left: -298px;
1080
- }
1081
- }
1082
-
1083
- .svg-legends-container {
1084
- width:70%;
1085
- height:auto;
1086
- position:relative;
1087
- max-height:140px;
1088
- }
1089
-
1090
- .pathway-container {
1091
- float: left;
1092
- padding-left: 16px;
1093
- padding-right: 18px;
1094
- text-align: left;
1095
- overflow: auto;
1096
- border: 1px solid rgb(220, 223, 230);
1097
- padding-bottom: 16px;
1098
- background: #ffffff;
1099
- overflow-x: hidden;
1100
- scrollbar-width: thin;
1101
-
1102
- &::-webkit-scrollbar {
1103
- width: 4px;
1104
- }
1105
-
1106
- &::-webkit-scrollbar-thumb {
1107
- border-radius: 10px;
1108
- box-shadow: inset 0 0 6px #c0c4cc;
1109
- }
1110
- }
1111
-
1112
- .flatmap-marker-help {
1113
- display: inline-block;
1114
- }
1115
-
1116
- ::v-deep .popper-bump-right {
1117
- left: 30px;
1118
- }
1119
-
1120
- .el-dropdown-link {
1121
- cursor: pointer;
1122
- color: #409eff;
1123
- }
1124
- .el-icon-arrow-down {
1125
- font-size: 12px;
1126
- }
1127
- .demonstration {
1128
- display: block;
1129
- color: #8492a6;
1130
- font-size: 14px;
1131
- margin-bottom: 20px;
1132
- }
1133
-
1134
- .tooltip {
1135
- display: none;
1136
- }
1137
-
1138
- ::v-deep .mapboxgl-popup {
1139
- max-width: 300px !important;
1140
- }
1141
-
1142
- ::v-deep .flatmap-tooltip-popup {
1143
- &.mapboxgl-popup-anchor-bottom {
1144
- .mapboxgl-popup-content {
1145
- margin-bottom: 12px;
1146
- &::after,
1147
- &::before {
1148
- top: 100%;
1149
- border-width: 12px;
1150
- }
1151
- /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
1152
- &::after {
1153
- margin-top: -1px;
1154
- border-color: rgb(255, 255, 255) transparent transparent transparent;
1155
- }
1156
- /* this border color controlls the outside, thin border */
1157
- &::before {
1158
- margin: 0 auto;
1159
- border-color: $app-primary-color transparent transparent transparent;
1160
- }
1161
- }
1162
- }
1163
- &.mapboxgl-popup-anchor-top {
1164
- .mapboxgl-popup-content {
1165
- margin-top: 18px;
1166
- &::after,
1167
- &::before {
1168
- top: calc(-100% + 6px);
1169
- border-width: 12px;
1170
- }
1171
- /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
1172
- &::after {
1173
- margin-top: 1px;
1174
- border-color: transparent transparent rgb(255, 255, 255) transparent;
1175
- }
1176
- &::before {
1177
- margin: 0 auto;
1178
- border-color: transparent transparent $app-primary-color transparent;
1179
- }
1180
- }
1181
- }
1182
- .mapboxgl-popup-content {
1183
- border-radius: 4px;
1184
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
1185
- pointer-events: none;
1186
- display: none;
1187
- background: #fff;
1188
- border: 1px solid $app-primary-color;
1189
- padding-left: 6px;
1190
- padding-right: 6px;
1191
- display: flex;
1192
- justify-content: center;
1193
- align-items: center;
1194
- &::after,
1195
- &::before {
1196
- content: "";
1197
- display: block;
1198
- position: absolute;
1199
- width: 0;
1200
- height: 0;
1201
- border-style: solid;
1202
- flex-shrink: 0;
1203
- }
1204
- }
1205
- .mapboxgl-popup-tip {
1206
- display: none;
1207
- }
1208
- }
1209
-
1210
- ::v-deep .mapboxgl-popup {
1211
- &.flatmap-marker-popup {
1212
- box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
1213
- pointer-events: auto;
1214
- background: #fff;
1215
- }
1216
- }
1217
-
1218
- /* Fix for chrome bug where under triangle pops up above one on top of it */
1219
- .selector:not(*:root),
1220
- ::v-deep.flatmap-tooltip-popup {
1221
- .mapboxgl-popup-content::after {
1222
- top: 99.9%;
1223
- }
1224
- }
1225
-
1226
- ::v-deep .flatmap-tooltip-dialog {
1227
- .mapboxgl-popup-tip {
1228
- display: none;
1229
- }
1230
- }
1231
-
1232
- ::v-deep .flatmap-marker-popup {
1233
- .mapboxgl-popup-content {
1234
- padding: 0px;
1235
- }
1236
- }
1237
-
1238
- ::v-deep .flatmapvuer-popover {
1239
- .mapboxgl-popup-close-button {
1240
- position: absolute;
1241
- right: 0.5em;
1242
- top: 0;
1243
- border: 0;
1244
- border-radius: 0 3px 0 0;
1245
- cursor: pointer;
1246
- background-color: transparent;
1247
- font-size: 2.5em;
1248
- color: grey;
1249
- top: 0.95em;
1250
- }
1251
- }
1252
-
1253
- .zoomOut {
1254
- padding-left: 8px;
1255
- }
1256
-
1257
- .fitWindow {
1258
- padding-left: 8px;
1259
- }
1260
-
1261
- .background-colour {
1262
- bottom: 16px;
1263
- position: absolute;
1264
- transition: all 1s ease;
1265
- }
1266
- .background-colour.open {
1267
- left: 322px;
1268
- }
1269
- .background-colour.close {
1270
- left: 24px;
1271
- }
1272
-
1273
- ::v-deep .background-popper {
1274
- padding: 5px 12px;
1275
- background-color: #ffffff;
1276
- border: 1px solid $app-primary-color;
1277
- box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.06);
1278
- height: 200px;
1279
- width: 175px;
1280
- min-width: 175px;
1281
- &.el-popper[x-placement^="top"] {
1282
- .popper__arrow {
1283
- border-top-color: $app-primary-color !important;
1284
- &::after {
1285
- border-top-color: #fff !important;
1286
- }
1287
- }
1288
- }
1289
- }
1290
-
1291
- .backgroundText {
1292
- color: rgb(48, 49, 51);
1293
- font-size: 14px;
1294
- font-weight: normal;
1295
- line-height: 20px;
1296
- }
1297
-
1298
- .backgroundControl {
1299
- display: flex;
1300
- margin-top: 16px;
1301
- }
1302
-
1303
- .backgroundChoice {
1304
- width: 20px;
1305
- height: 20px;
1306
- border: 1px solid rgb(144, 147, 153);
1307
- margin-left: 20px;
1308
- &.active {
1309
- border: 2px solid $app-primary-color;
1310
- }
1311
- &:hover {
1312
- cursor: pointer;
1313
- }
1314
- &.white {
1315
- background-color: white;
1316
- margin-left: 10px;
1317
- }
1318
- &.black {
1319
- background-color: black;
1320
- }
1321
- &.lightskyblue {
1322
- background-color: lightskyblue;
1323
- }
1324
- }
1325
-
1326
- .icon-button {
1327
- height: 24px !important;
1328
- width: 24px !important;
1329
- color: $app-primary-color;
1330
- &:hover {
1331
- cursor: pointer;
1332
- }
1333
- }
1334
-
1335
- ::v-deep .maplibregl-ctrl-minimap {
1336
- transform-origin: top right;
1337
- @media (max-width: 1250px) {
1338
- height: 125px !important;// important is needed here as we are over-riding the style set by the flatmap
1339
- width: 180px !important;
1340
- >>> .maplibregl-canvas .mapboxgl-canvas {
1341
- height: 125px !important;
1342
- width: 180px !important;
1343
- }
1344
- }
1345
- @media (min-width: 1251px) {
1346
- height: 190px !important;
1347
- width: 300px !important;
1348
- >>> .maplibregl-canvas .mapboxgl-canvas {
1349
- height: 190px !important;
1350
- width: 300px !important;
1351
- }
1352
- }
1353
- transition: all 1s ease;
1354
- &.shrink {
1355
- transform: scale(0.5);
1356
- transform: scale(0.5);
1357
- }
1358
- }
1359
-
1360
- .minimap-resize {
1361
- position: absolute;
1362
- pointer-events: all;
1363
- cursor: pointer;
1364
- top: 0;
1365
- right: 0;
1366
- padding-top: 3px; // needed as icon is offset
1367
- width: 20px;
1368
- height: 14px;
1369
- z-index: 9;
1370
- transition: all 1s ease;
1371
- &.shrink {
1372
- transform: rotate(0deg);
1373
- }
1374
- &.enlarge {
1375
- transform: rotate(180deg) scale(2);
1376
- padding-bottom: 5px; // note padding is added to the opposite side since it is rotated
1377
- padding-left: 5px;
1378
- }
1379
- }
1380
-
1381
- ::v-deep .flatmap-popper {
1382
- padding: 6px 4px;
1383
- font-size: 12px;
1384
- color: rgb(48, 49, 51);
1385
- background-color: #f3ecf6;
1386
- border: 1px solid $app-primary-color;
1387
- white-space: nowrap;
1388
- min-width: unset;
1389
- &.warning-popper {
1390
- min-width: 150px;
1391
- max-width: 400px;
1392
- word-break: keep-all;
1393
- white-space: unset;
1394
- }
1395
- &.left-popper {
1396
- .popper__arrow {
1397
- border-left-color: $app-primary-color !important;
1398
- &::after {
1399
- border-left-color: #f3ecf6 !important;
1400
- }
1401
- }
1402
- }
1403
- &.right-popper {
1404
- .popper__arrow {
1405
- border-right-color: $app-primary-color !important;
1406
- &:after {
1407
- border-right-color: #f3ecf6 !important;
1408
- }
1409
- }
1410
- }
1411
- &.el-popper[x-placement^="top"] {
1412
- .popper__arrow {
1413
- border-top-color: $app-primary-color !important;
1414
- &:after {
1415
- border-top-color: #f3ecf6 !important;
1416
- }
1417
- }
1418
- }
1419
- }
1420
-
1421
- ::v-deep .el-loading-spinner {
1422
- i,
1423
- .el-loading-text {
1424
- color: $app-primary-color;
1425
- }
1426
- }
1427
-
1428
- ::v-deep .flatmap-popup-popper {
1429
- .mapboxgl-popup-tip {
1430
- border-bottom-color: $app-primary-color;
1431
- }
1432
- .mapboxgl-popup-content {
1433
- padding: 6px 4px;
1434
- font-size: 12px;
1435
- color: rgb(48, 49, 51);
1436
- background-color: #f3ecf6;
1437
- border: 1px solid $app-primary-color;
1438
- white-space: nowrap;
1439
- min-width: unset;
1440
- .mapboxgl-popup-close-button {
1441
- display: none;
1442
- }
1443
- }
1444
- }
1445
-
1446
- ::v-deep .popper-zoomout {
1447
- padding-right: 13px !important;
1448
- left: -21px !important;
1449
- }
1450
-
1451
- ::v-deep .popper-zoomout {
1452
- .popper__arrow {
1453
- left: 53px !important;
1454
- }
1455
- }
1456
-
1457
- ::v-deep .mapboxgl-popup-content {
1458
- padding: 0px;
1459
- }
1460
-
1461
- .bottom-right-control {
1462
- position: absolute;
1463
- right: 16px;
1464
- bottom: 16px;
1465
- }
1466
-
1467
- ::v-deep .my-drawer {
1468
- background: rgba(0, 0, 0, 0);
1469
- box-shadow: none;
1470
- }
1471
-
1472
- .drawer {
1473
- ::v-deep .el-drawer:focus {
1474
- outline: none;
1475
- }
1476
- }
1477
-
1478
- .open-drawer,
1479
- .drawer-button {
1480
- z-index: 8;
1481
- width: 20px;
1482
- height: 40px;
1483
- border: solid 1px $app-primary-color;
1484
- text-align: center;
1485
- vertical-align: middle;
1486
- cursor: pointer;
1487
- pointer-events: auto;
1488
- }
1489
-
1490
- .open-drawer {
1491
- position: absolute;
1492
- left: 0px;
1493
- background-color: #f7faff;
1494
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
1495
- }
1496
-
1497
- .drawer-button {
1498
- float: left;
1499
- margin-top: calc(50% - 36px);
1500
- background-color: #F9F2FC;
1501
-
1502
- i {
1503
- font-weight: 600;
1504
- margin-top: 12px;
1505
- color: $app-primary-color;
1506
- transition-delay: 0.9s;
1507
- }
1508
- &.open {
1509
- i {
1510
- transform: rotate(0deg) scaleY(2);
1511
- }
1512
- }
1513
- &.close {
1514
- i {
1515
- transform: rotate(180deg) scaleY(2);
1516
- }
1517
- }
1518
- }
1519
-
1520
- ::v-deep .mapboxgl-canvas-container {
1521
- canvas {
1522
- outline: none;
1523
- }
1524
- }
1525
-
1526
- .backgroundSpacer {
1527
- border-bottom: 1px solid #e4e7ed;
1528
- margin-bottom: 10px;
1529
- }
1530
-
1531
- .flatmap-radio {
1532
- ::v-deep label {
1533
- margin-right: 20px;
1534
- &:last-child {
1535
- margin-right: 0px;
1536
- }
1537
- }
1538
- .el-radio__input {
1539
- &.is-checked {
1540
- & + .el-radio__label {
1541
- color: $app-primary-color;
1542
- }
1543
- .el-radio__inner {
1544
- border-color: $app-primary-color;
1545
- background: $app-primary-color;
1546
- }
1547
- }
1548
- }
1549
- }
1550
-
1551
- ::v-deep .custom-popup {
1552
- .mapboxgl-popup-tip {
1553
- display: none;
1554
- }
1555
- .mapboxgl-popup-content {
1556
- border-radius: 4px;
1557
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
1558
- pointer-events: none;
1559
- display: none;
1560
- background: #fff;
1561
- font-family: "Asap",sans-serif;
1562
- font-size: 12pt;
1563
- color: $app-primary-color;
1564
- border: 1px solid $app-primary-color;
1565
- padding-left: 6px;
1566
- padding-right: 6px;
1567
- padding-top: 6px;
1568
- padding-bottom: 6px;
1569
- display: flex;
1570
- justify-content: center;
1571
- align-items: center;
1572
- &::after,
1573
- &::before {
1574
- content: "";
1575
- display: block;
1576
- position: absolute;
1577
- width: 0;
1578
- height: 0;
1579
- border-style: solid;
1580
- flex-shrink: 0;
1581
- }
1582
- .mapboxgl-popup-close-button {
1583
- display: none;
1584
- }
1585
- }
1586
- &.mapboxgl-popup-anchor-bottom {
1587
- .mapboxgl-popup-content {
1588
- margin-bottom: 12px;
1589
- &::after,
1590
- &::before {
1591
- top: 100%;
1592
- border-width: 12px;
1593
- }
1594
- /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
1595
- &::after {
1596
- margin-top: -1px;
1597
- border-color: rgb(255, 255, 255) transparent transparent transparent;
1598
- }
1599
- /* this border color controlls the outside, thin border */
1600
- &::before {
1601
- margin: 0 auto;
1602
- border-color: $app-primary-color transparent transparent transparent;
1603
- }
1604
- }
1605
- }
1606
- &.mapboxgl-popup-anchor-top {
1607
- .mapboxgl-popup-content {
1608
- margin-top: 18px;
1609
- &::after,
1610
- &::before {
1611
- top: calc(-100% + 6px);
1612
- border-width: 12px;
1613
- }
1614
- /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
1615
- &::after {
1616
- margin-top: 1px;
1617
- border-color: transparent transparent rgb(255, 255, 255) transparent;
1618
- }
1619
- &::before {
1620
- margin: 0 auto;
1621
- border-color: transparent transparent $app-primary-color transparent;
1622
- }
1623
- }
1624
- }
1625
- }
1626
- </style>
1627
-
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 style="height:100%;width:100%;position:relative;overflow-y:none">
12
+ <div style="height:100%;width:100%;" ref="display"></div>
13
+ <div class="beta-popovers">
14
+ <div>
15
+ <el-popover
16
+ :content="getWarningMessage"
17
+ placement="right"
18
+ :appendToBody="false"
19
+ trigger="manual"
20
+ popper-class="warning-popper flatmap-popper right-popper"
21
+ v-model="hoverVisibilities[6].value"
22
+ ref="warningPopover"
23
+ ></el-popover>
24
+ <i
25
+ class="el-icon-warning warning-icon"
26
+ v-if="displayWarning"
27
+ @mouseover="showToolitip(6)"
28
+ @mouseout="hideToolitip(6)"
29
+ v-popover:warningPopover
30
+ >
31
+ <template v-if="isLegacy">
32
+ <span class="warning-text">Legacy Map</span>
33
+ <div class="latest-map-text" @click="viewLatestMap">Click here for the latest map</div>
34
+ </template>
35
+ <template v-else>
36
+ <span class="warning-text">Beta</span>
37
+ </template>
38
+ </i>
39
+ </div>
40
+ <el-popover
41
+ :content="latestChangesMessage"
42
+ placement="right"
43
+ v-if="displayLatestChanges"
44
+ :appendToBody="false"
45
+ trigger="manual"
46
+ popper-class="warning-popper flatmap-popper right-popper"
47
+ v-model="hoverVisibilities[7].value"
48
+ ref="latestChangesPopover"
49
+ ></el-popover>
50
+ <i
51
+ class="el-icon-warning latest-changesicon"
52
+ v-if="displayLatestChanges && latestChangesMessage"
53
+ @mouseover="showToolitip(7)"
54
+ @mouseout="hideToolitip(7)"
55
+ v-popover:latestChangesPopover
56
+ >
57
+ <span class="warning-text">What's new?</span>
58
+ </i>
59
+ </div>
60
+
61
+ <!-- The element below is placed onto the flatmap when it is ready -->
62
+ <i class="el-icon-arrow-down minimap-resize" :class="{ enlarge: minimapSmall, shrink: !minimapSmall}" ref="minimapResize" v-show="minimapResizeShow" @click="closeMinimap"></i>
63
+
64
+ <div class="bottom-right-control">
65
+ <el-popover
66
+ content="Zoom in"
67
+ placement="left"
68
+ :appendToBody="false"
69
+ trigger="manual"
70
+ popper-class="flatmap-popper left-popper"
71
+ v-model="hoverVisibilities[0].value"
72
+ >
73
+ <map-svg-icon
74
+ icon="zoomIn"
75
+ class="icon-button zoomIn"
76
+ slot="reference"
77
+ @click.native="zoomIn()"
78
+ @mouseover.native="showToolitip(0)"
79
+ @mouseout.native="hideToolitip(0)"
80
+ />
81
+ </el-popover>
82
+ <el-popover
83
+ content="Zoom out"
84
+ placement="top-end"
85
+ :appendToBody="false"
86
+ trigger="manual"
87
+ popper-class="flatmap-popper popper-zoomout"
88
+ v-model="hoverVisibilities[1].value"
89
+ >
90
+ <map-svg-icon
91
+ icon="zoomOut"
92
+ class="icon-button zoomOut"
93
+ slot="reference"
94
+ @click.native="zoomOut()"
95
+ @mouseover.native="showToolitip(1)"
96
+ @mouseout.native="hideToolitip(1)"
97
+ />
98
+ </el-popover>
99
+ <el-popover
100
+ content="Reset"
101
+ placement="top"
102
+ :appendToBody="false"
103
+ trigger="manual"
104
+ popper-class="flatmap-popper"
105
+ v-model="hoverVisibilities[2].value"
106
+ >
107
+ <div>
108
+ Fit to
109
+ <br>
110
+ window
111
+ </div>
112
+ <map-svg-icon
113
+ slot="reference"
114
+ icon="fitWindow"
115
+ class="icon-button fitWindow"
116
+ @click.native="resetView()"
117
+ @mouseover.native="showToolitip(2)"
118
+ @mouseout.native="hideToolitip(2)"
119
+ />
120
+ </el-popover>
121
+ </div>
122
+ <el-popover
123
+ content="Change pathway visibility"
124
+ placement="right"
125
+ :appendToBody="false"
126
+ trigger="manual"
127
+ popper-class="flatmap-popper right-popper"
128
+ v-model="hoverVisibilities[4].value"
129
+ ref="checkBoxPopover"
130
+ />
131
+ <div class="pathway-location" :class="{ open: drawerOpen, close: !drawerOpen }">
132
+ <div
133
+ class="pathway-container"
134
+ :style="{'max-height': pathwaysMaxHeight + 'px'}"
135
+ v-if="pathControls"
136
+ v-popover:checkBoxPopover
137
+ >
138
+ <svg-legends v-if="!isFC" class="svg-legends-container"/>
139
+ <el-popover
140
+ content="Find these markers for data"
141
+ placement="right"
142
+ :appendToBody="false"
143
+ trigger="manual"
144
+ popper-class="flatmap-popper popper-bump-right right-popper"
145
+ v-model="hoverVisibilities[5].value"
146
+ ref="markerPopover"
147
+ ></el-popover>
148
+ <div
149
+ v-show="hoverVisibilities[5].value"
150
+ class="flatmap-marker-help"
151
+ v-html="flatmapMarker"
152
+ v-popover:markerPopover
153
+ ></div>
154
+ <selections-group
155
+ v-if="isFC && systems && systems.length > 0"
156
+ title="Systems"
157
+ labelKey="name"
158
+ identifierKey="id"
159
+ :selections="systems"
160
+ colourStyle="background"
161
+ @changed="systemSelected"
162
+ @checkAll="checkAllSystems"
163
+ ref="systemsSelection"
164
+ key="systemsSelection"
165
+ />
166
+ <!--
167
+ <selections-group
168
+ v-if="!isFC && centreLines && centreLines.length > 0"
169
+ title="Nerves"
170
+ labelKey="label"
171
+ identifierKey="key"
172
+ :selections="centreLines"
173
+ @changed="centreLinesSelected"
174
+ ref="centrelinesSelection"
175
+ key="centrelinesSelection"
176
+ />
177
+ <selections-group
178
+ v-if="isFC && sckanDisplay && sckanDisplay.length > 0"
179
+ title="SCKAN"
180
+ labelKey="label"
181
+ identifierKey="key"
182
+ :selections="sckanDisplay"
183
+ @changed="sckanSelected"
184
+ @checkAll="checkAllSCKAN"
185
+ ref="skcanSelection"
186
+ key="skcanSelection"
187
+ />
188
+ <selections-group
189
+ v-if="layers && layers.length > 0"
190
+ title="Layers"
191
+ labelKey="description"
192
+ identifierKey="id"
193
+ :selections="layers"
194
+ @changed="layersSelected"
195
+ @checkAll="checkAllLayers"
196
+ ref="layersSelection"
197
+ key="layersSelection"
198
+ />
199
+ -->
200
+ <selections-group
201
+ v-if="pathways && pathways.length > 0"
202
+ title="Pathways"
203
+ labelKey="label"
204
+ identifierKey="type"
205
+ colourStyle="line"
206
+ :selections="pathways"
207
+ @changed="pathwaysSelected"
208
+ @checkAll="checkAllPathways"
209
+ ref="pathwaysSelection"
210
+ key="pathwaysSelection"
211
+ />
212
+ </div>
213
+ <div
214
+ @click="toggleDrawer"
215
+ class="drawer-button"
216
+ :class="{ open: drawerOpen, close: !drawerOpen }"
217
+ >
218
+ <i class="el-icon-arrow-left"></i>
219
+ </div>
220
+ </div>
221
+ <el-popover
222
+ ref="backgroundPopover"
223
+ placement="top-start"
224
+ width="175"
225
+ :appendToBody="false"
226
+ trigger="click"
227
+
228
+ popper-class="background-popper"
229
+ >
230
+ <el-row class="backgroundText">Organs display</el-row>
231
+ <el-row class="backgroundControl">
232
+ <el-radio-group v-model="colourRadio" class="flatmap-radio" @change="setColour">
233
+ <el-radio :label="true">Colour</el-radio>
234
+ <el-radio :label="false">Greyscale</el-radio>
235
+ </el-radio-group>
236
+ </el-row>
237
+ <el-row class="backgroundSpacer"></el-row>
238
+ <el-row class="backgroundText">Outlines display</el-row>
239
+ <el-row class="backgroundControl">
240
+ <el-radio-group v-model="outlinesRadio" class="flatmap-radio" @change="setOutlines">
241
+ <el-radio :label="true">Show</el-radio>
242
+ <el-radio :label="false">Hide</el-radio>
243
+ </el-radio-group>
244
+ </el-row>
245
+ <el-row class="backgroundSpacer"></el-row>
246
+ <el-row class="backgroundText">Change background</el-row>
247
+ <el-row class="backgroundControl">
248
+ <div
249
+ v-for="item in availableBackground"
250
+ :key="item"
251
+ :class="['backgroundChoice', item, item == currentBackground ? 'active' :'']"
252
+ @click="backgroundChangeCallback(item)"
253
+ />
254
+ </el-row>
255
+ </el-popover>
256
+ <el-popover
257
+ content="Change settings"
258
+ placement="right"
259
+ v-model="hoverVisibilities[3].value"
260
+ :appendToBody="false"
261
+ trigger="manual"
262
+ popper-class="flatmap-popper right-popper"
263
+ >
264
+ <map-svg-icon
265
+ v-popover:backgroundPopover
266
+ icon="changeBckgd"
267
+ class="icon-button background-colour"
268
+ :class="{ open: drawerOpen, close: !drawerOpen }"
269
+ slot="reference"
270
+ @mouseover.native="showToolitip(3)"
271
+ @mouseout.native="hideToolitip(3)"
272
+ />
273
+ </el-popover>
274
+ <Tooltip
275
+ ref="tooltip"
276
+ class="tooltip"
277
+ :entry="tooltipEntry"
278
+ @resource-selected="resourceSelected"
279
+ />
280
+ </div>
281
+ </div>
282
+ </template>
283
+
284
+ <script>
285
+ /* eslint-disable no-alert, no-console */
286
+ import Vue from "vue";
287
+ import Tooltip from "./Tooltip";
288
+ import SelectionsGroup from "./SelectionsGroup.vue";
289
+ import { MapSvgIcon, MapSvgSpriteColor } from "@abi-software/svg-sprite";
290
+ import SvgLegends from "./legends/SvgLegends";
291
+ import {
292
+ Col,
293
+ Loading,
294
+ Radio,
295
+ RadioGroup,
296
+ Row
297
+ } from "element-ui";
298
+ import lang from "element-ui/lib/locale/lang/en";
299
+ import locale from "element-ui/lib/locale";
300
+ import flatmapMarker from "../icons/flatmap-marker";
301
+ import {FlatmapQueries} from "../services/flatmapQueries.js";
302
+
303
+ locale.use(lang);
304
+ Vue.use(Col);
305
+ Vue.use(Loading.directive);
306
+ Vue.use(Radio);
307
+ Vue.use(RadioGroup);
308
+ Vue.use(Row);
309
+ const ResizeSensor = require("css-element-queries/src/ResizeSensor");
310
+
311
+ const createUnfilledTooltipData = function (){
312
+ return {
313
+ destinations: [],
314
+ origins: [],
315
+ components: [],
316
+ destinationsWithDatasets: [],
317
+ originsWithDatasets: [],
318
+ componentsWithDatasets: [],
319
+ resource: undefined
320
+ }
321
+ }
322
+
323
+ export default {
324
+ name: "FlatmapVuer",
325
+ components: {
326
+ MapSvgIcon,
327
+ MapSvgSpriteColor,
328
+ Tooltip,
329
+ SelectionsGroup,
330
+ SvgLegends
331
+ },
332
+ beforeCreate: function() {
333
+ this.mapManager = undefined;
334
+ this.mapImp = undefined;
335
+ //The state watcher may triggered before
336
+ //created causing issue, This flag will
337
+ //resolve this issue.
338
+ this.setStateRequired = false;
339
+ },
340
+ methods: {
341
+ viewLatestMap: function() {
342
+ let biologicalSex = this.biologicalSex ? this.biologicalSex : undefined;
343
+ //Human requires special handling
344
+ if (this.entry === "NCBITaxon:9606") {
345
+ biologicalSex = "PATO:0000384";
346
+ }
347
+ const state = {
348
+ entry: this.entry,
349
+ biologicalSex,
350
+ viewport: this.mapImp.getState()
351
+ };
352
+ this.$emit("view-latest-map", state);
353
+ },
354
+ backgroundChangeCallback: function(colour) {
355
+ this.currentBackground = colour;
356
+ if (this.mapImp) {
357
+ this.mapImp.setBackgroundColour(this.currentBackground, 1);
358
+ }
359
+ },
360
+ toggleDrawer: function() {
361
+ this.drawerOpen = !this.drawerOpen;
362
+ },
363
+ /**
364
+ * Function to toggle colour/greyscale of organs.
365
+ */
366
+ setColour: function(flag) {
367
+ this.colourRadio = flag;
368
+ if (this.mapImp) {
369
+ this.mapImp.setColour({ colour: flag, outline: this.outlinesRadio });
370
+ }
371
+ },
372
+ /**
373
+ * Function to toggle outlines f organs.
374
+ */
375
+ setOutlines: function(flag) {
376
+ this.outlineRadio = flag;
377
+ if (this.mapImp) {
378
+ this.mapImp.setColour({ colour: this.colourRadio, outline: flag });
379
+ }
380
+ },
381
+ /**
382
+ * Function to toggle paths to default.
383
+ * Also called when the associated button is pressed.
384
+ */
385
+ resetView: function() {
386
+ if (this.mapImp) {
387
+ this.mapImp.resetMap();
388
+ if (this.$refs.centrelinesSelection) {
389
+ this.$refs.centrelinesSelection.reset();
390
+ }
391
+ if (this.$refs.skcanSelection) {
392
+ this.$refs.skcanSelection.reset();
393
+ }
394
+ if (this.$refs.layersSelection) {
395
+ this.$refs.layersSelection.reset();
396
+ }
397
+ if (this.$refs.systemsSelection) {
398
+ this.$refs.pathwaysSelection.reset();
399
+ }
400
+ if (this.$refs.pathwaysSelection) {
401
+ this.$refs.pathwaysSelection.reset();
402
+ }
403
+ }
404
+ },
405
+ /**
406
+ * Function to zoom in.
407
+ * Also called when the associated button is pressed.
408
+ */
409
+ zoomIn: function() {
410
+ if (this.mapImp) {
411
+ this.mapImp.zoomIn();
412
+ }
413
+ },
414
+ /**
415
+ * Function to zoom out.
416
+ * Also called when the associated button is pressed.
417
+ */
418
+ zoomOut: function() {
419
+ if (this.mapImp) {
420
+ this.mapImp.zoomOut();
421
+ }
422
+ },
423
+ centreLinesSelected: function(payload) {
424
+ if (this.mapImp) {
425
+ this.mapImp.enableCentrelines(payload.value);
426
+ }
427
+ },
428
+ sckanSelected: function(payload) {
429
+ if (this.mapImp) {
430
+ this.mapImp.enableSckanPath(payload.key, payload.value);
431
+ }
432
+ },
433
+ checkAllSCKAN: function(payload) {
434
+ if (this.mapImp) {
435
+ payload.keys.forEach(key => this.mapImp.enableSckanPath(key, payload.value));
436
+ }
437
+ },
438
+ systemSelected: function(payload) {
439
+ if (this.mapImp) {
440
+ this.mapImp.enableSystem(payload.key, payload.value);
441
+ }
442
+ },
443
+ checkAllSystems: function(payload) {
444
+ if (this.mapImp) {
445
+ payload.keys.forEach(key => this.mapImp.enableSystem(key, payload.value));
446
+ }
447
+ },
448
+ layersSelected: function(payload) {
449
+ if (this.mapImp) {
450
+ this.mapImp.enableLayer(payload.key, payload.value);
451
+ }
452
+ },
453
+ checkAllLayers: function(payload) {
454
+ if (this.mapImp) {
455
+ payload.keys.forEach(key => this.mapImp.enableLayer(key, payload.value));
456
+ }
457
+ },
458
+ pathwaysSelected: function(payload) {
459
+ if (this.mapImp) {
460
+ this.mapImp.enablePath(payload.key, payload.value);
461
+ }
462
+ },
463
+ checkAllPathways: function(payload) {
464
+ if (this.mapImp) {
465
+ payload.keys.forEach(key => this.mapImp.enablePath(key, payload.value));
466
+ }
467
+ },
468
+ enablePanZoomEvents: function(flag) {
469
+ this.mapImp.enablePanZoomEvents(flag);
470
+ },
471
+ eventCallback: function() {
472
+ return (eventType, data, ...args) => {
473
+ if (eventType !== "pan-zoom") {
474
+ const label = data.label;
475
+ const resource = [data.models];
476
+ const taxonomy = this.entry;
477
+ const biologicalSex = this.biologicalSex;
478
+ const payload = {
479
+ dataset: data.dataset,
480
+ biologicalSex: biologicalSex,
481
+ taxonomy: taxonomy,
482
+ resource: resource,
483
+ label: label,
484
+ feature: data,
485
+ userData: args,
486
+ eventType: eventType
487
+ };
488
+ if (data && data.type !== "marker" && eventType === "click"){
489
+ this.checkAndCreatePopups(payload);
490
+ }
491
+ this.$emit("resource-selected", payload);
492
+ } else {
493
+ this.$emit("pan-zoom-callback", data);
494
+ }
495
+ };
496
+ },
497
+ // checkNeuronClicked shows a neuron path pop up if a path was recently clicked
498
+ checkAndCreatePopups: async function(data) {
499
+ // Call flatmap database to get the connection data
500
+ let results = await this.flatmapQueries.retrieveFlatmapKnowledgeForEvent(data)
501
+ if(!results){
502
+ if(data.feature.hyperlinks && data.feature.hyperlinks.length > 0){
503
+ this.resourceForTooltip = data.resource[0];
504
+ this.createTooltipFromNeuronCuration(data);
505
+ }
506
+ } else {
507
+ this.resourceForTooltip = data.resource[0];
508
+ this.createTooltipFromNeuronCuration(data);
509
+ }
510
+ },
511
+ popUpCssHacks: function() {
512
+ // Below is a hack to remove flatmap tooltips while popup is open
513
+ let ftooltip = document.querySelector(".flatmap-tooltip-popup");
514
+ if (ftooltip) ftooltip.style.display = "none";
515
+ document.querySelector(".mapboxgl-popup-close-button").style.display =
516
+ "block";
517
+ this.$refs.tooltip.$el.style.display = "flex";
518
+ document.querySelector(".mapboxgl-popup-close-button").onclick = () => {
519
+ document.querySelector(".flatmap-tooltip-popup").style.display =
520
+ "block";
521
+ };
522
+ },
523
+ resourceSelected: function(action) {
524
+ this.$emit("resource-selected", action);
525
+ },
526
+ createTooltipFromNeuronCuration: function(data) {
527
+ this.tooltipEntry = this.flatmapQueries.createTooltipData(data);
528
+ this.displayTooltip();
529
+ },
530
+ // Keeping this as an API
531
+ showPopup: function(featureId, node, options) {
532
+ let myOptions = options;
533
+ if (this.mapImp) {
534
+ if (myOptions) {
535
+ if (!myOptions.className) myOptions.className = "custom-popup";
536
+ } else {
537
+ myOptions = { className: "custom-popup", positionAtLastClick: true };
538
+ }
539
+ this.mapImp.showPopup(featureId, node, myOptions);
540
+ }
541
+ },
542
+ showMarkerPopup: function(featureId, node, options) {
543
+ if (this.mapImp) {
544
+ this.mapImp.showMarkerPopup(featureId, node, options);
545
+ }
546
+ },
547
+ closeMinimap: function(){
548
+ let minimapEl = this.$refs.flatmapContainer.querySelector('.maplibregl-ctrl-minimap'); // find minimap
549
+ if (this.minimapSmall) { //switch the classes on the minimap
550
+ minimapEl.classList.add('enlarge');
551
+ minimapEl.classList.remove('shrink');
552
+ } else {
553
+ minimapEl.classList.add('shrink');
554
+ minimapEl.classList.remove('enlarge');
555
+ }
556
+ this.minimapSmall = !this.minimapSmall;
557
+ },
558
+ addResizeButtonToMinimap: function(){
559
+ let minimapEl = this.$refs.flatmapContainer.querySelector('.maplibregl-ctrl-minimap');
560
+ if (minimapEl){
561
+ this.$refs.minimapResize.parentNode.removeChild(this.$refs.minimapResize);
562
+ minimapEl.appendChild(this.$refs.minimapResize);
563
+ this.minimapResizeShow = true;
564
+ }
565
+ },
566
+ setHelpMode: function(helpMode) {
567
+ if (helpMode) {
568
+ this.inHelp = true;
569
+ this.hoverVisibilities.forEach(item => {
570
+ item.value = true;
571
+ });
572
+ this.openFlatmapHelpPopup();
573
+ } else {
574
+ this.inHelp = false;
575
+ this.hoverVisibilities.forEach(item => {
576
+ item.value = false;
577
+ });
578
+ this.closeFlatmapHelpPopup();
579
+ }
580
+ },
581
+ showToolitip: function(tooltipNumber) {
582
+ if (!this.inHelp) {
583
+ this.tooltipWait = setTimeout(() => {
584
+ this.hoverVisibilities[tooltipNumber].value = true;
585
+ }, 500);
586
+ }
587
+ },
588
+ hideToolitip: function(tooltipNumber) {
589
+ if (!this.inHelp) {
590
+ this.hoverVisibilities[tooltipNumber].value = false;
591
+ clearTimeout(this.tooltipWait);
592
+ }
593
+ },
594
+ displayTooltip: function() {
595
+ this.mapImp.showPopup(
596
+ this.mapImp.modelFeatureIds(this.resourceForTooltip)[0],
597
+ this.$refs.tooltip.$el,
598
+ { className: "flatmapvuer-popover", positionAtLastClick: true }
599
+ );
600
+ this.popUpCssHacks();
601
+ },
602
+ openFlatmapHelpPopup: function() {
603
+ if (this.mapImp) {
604
+ let heartId = this.mapImp.featureIdsForModel("UBERON:0000948")[0];
605
+ const elm = "Click for more information";
606
+ this.mapImp.showPopup(heartId, elm, {
607
+ anchor: "top",
608
+ className: "flatmap-popup-popper"
609
+ });
610
+ }
611
+ },
612
+ closeFlatmapHelpPopup: function() {
613
+ this.$el
614
+ .querySelectorAll(".mapboxgl-popup-close-button")
615
+ .forEach(item => {
616
+ item.click();
617
+ });
618
+ },
619
+ getLabels: function() {
620
+ let labels = [];
621
+ if (this.mapImp) {
622
+ let annotations = this.mapImp.annotations;
623
+ for (let value of annotations.values()) {
624
+ if (value.label) labels.push(value.label);
625
+ }
626
+ return Array.from(new Set(labels));
627
+ }
628
+ },
629
+ getState: function() {
630
+ if (this.mapImp) {
631
+ let state = {
632
+ entry: this.entry,
633
+ viewport: this.mapImp.getState()
634
+ };
635
+ const identifier = this.mapImp.getIdentifier();
636
+ if (this.biologicalSex)
637
+ state['biologicalSex'] = this.biologicalSex;
638
+ else if (identifier && identifier.biologicalSex)
639
+ state['biologicalSex'] = identifier.biologicalSex;
640
+ if (identifier && identifier.uuid)
641
+ state['uuid'] = identifier.uuid;
642
+ return state;
643
+ }
644
+ return undefined;
645
+ },
646
+ setState: function(state) {
647
+ if (state) {
648
+ if (this.mapImp &&
649
+ (state.entry && (this.entry == state.entry)) &&
650
+ (!state.biologicalSex || (state.biologicalSex === this.biologicalSex)))
651
+ {
652
+ if (state.viewport) {
653
+ this.mapImp.setState(state.viewport);
654
+ }
655
+ } else {
656
+ this.createFlatmap(state);
657
+ }
658
+ this.setStateRequired = false;
659
+ }
660
+ },
661
+ restoreMapState: function(state) {
662
+ if (state) {
663
+ if (state.viewport)
664
+ this.mapImp.setState(state.viewport);
665
+ if (state.searchTerm)
666
+ this.searchAndShowResult(state.searchTerm, true);
667
+ }
668
+ },
669
+ createFlatmap: function(state) {
670
+ if (!this.mapImp && !this.loading) {
671
+ this.loading = true;
672
+ let minimap = false;
673
+ if (this.displayMinimap) {
674
+ minimap = { position: "top-right" };
675
+ }
676
+
677
+ //As for flatmap-viewer@2.2.7, see below for the documentation
678
+ //for the identifier:
679
+
680
+ //@arg identifier {string|Object}
681
+ // A string or object identifying the map to load. If a string its
682
+ // value can be either the map's ``uuid``, assigned at generation time,
683
+ // or taxon and biological sex identifiers of the species that the map
684
+ // represents. The latest version of a map is loaded unless it has been
685
+ // identified using a ``uuid`` (see below).
686
+ // @arg identifier.taxon {string} The taxon identifier of the species
687
+ // represented by the map. This is specified as metadata in the map's source file.
688
+ // @arg identifier.biologicalSex {string} The biological sex of the species
689
+ // represented by the map. This is specified as metadatain the map's source file.
690
+ // @arg identifier.uuid {string} The unique uuid the flatmap. If given then this exact map will
691
+ // be loaded, overriding ``taxon`` and ``biologicalSex``.
692
+
693
+ let identifier = { taxon: this.entry };
694
+ //This now handle the uses of uuid when resuming states
695
+ if (state) {
696
+ if (state.uuid) {
697
+ identifier = { uuid: state.uuid };
698
+ } else if (state.entry) {
699
+ identifier.taxon = state.entry;
700
+ if (state.biologicalSex) {
701
+ identifier["biologicalSex"] = state.biologicalSex;
702
+ } else if (identifier.taxon === "NCBITaxon:9606") {
703
+ //For backward compatibility
704
+ identifier["biologicalSex"] ="PATO:0000384";
705
+ }
706
+ }
707
+ } else {
708
+ // Set the bioloicalSex now if map is not resumed from
709
+ // a saved state
710
+ if (this.biologicalSex) {
711
+ identifier["biologicalSex"] = this.biologicalSex;
712
+ }
713
+ }
714
+
715
+ let promise1 = this.mapManager.loadMap(
716
+ identifier,
717
+ this.$refs.display,
718
+ this.eventCallback(),
719
+ {
720
+ //fullscreenControl: false,
721
+ //annotatable: false,
722
+ //debug: true,
723
+ featureInfo: this.featureInfo,
724
+ "min-zoom": this.minZoom,
725
+ layerControl: true,
726
+ pathControls: true,
727
+ searchable: this.searchable,
728
+ tooltips: this.tooltips,
729
+ minimap: minimap
730
+ }
731
+ );
732
+ promise1.then(returnedObject => {
733
+ this.mapImp = returnedObject;
734
+ this.onFlatmapReady();
735
+ if (this._stateToBeSet)
736
+ this.restoreMapState(this._stateToBeSet);
737
+ else {
738
+ this.restoreMapState(state);
739
+ }
740
+ });
741
+ } else if (state) {
742
+ this._stateToBeSet = { viewport: state.viewport, searchTerm: state.searchTerm };
743
+ if (this.mapImp && !this.loading)
744
+ this.restoreMapState(this._stateToBeSet);
745
+ }
746
+ },
747
+ computePathControlsMaximumHeight() {
748
+ const elem = this.$refs.display;
749
+ if (elem) {
750
+ const computed = getComputedStyle(elem);
751
+ const padding = parseInt(computed.paddingTop) + parseInt(computed.paddingBottom);
752
+ const height = elem.clientHeight - padding;
753
+ this.pathwaysMaxHeight = height - 170;
754
+ }
755
+ },
756
+ mapResize: function() {
757
+ try {
758
+ this.computePathControlsMaximumHeight();
759
+ if (this.mapImp) {
760
+ this.mapImp.resize();
761
+ this.showMinimap(this.displayMinimap);
762
+ if (this.mapImp._minimap) {
763
+ this.mapImp._minimap.resize();
764
+ }
765
+ }
766
+ } catch {
767
+ console.error("Map resize error");
768
+ }
769
+ },
770
+ onFlatmapReady: function(){
771
+ // onFlatmapReady is used for functions that need to run immediately after the flatmap is loaded
772
+ this.sensor = new ResizeSensor(
773
+ this.$refs.display,
774
+ this.mapResize
775
+ );
776
+ if (this.mapImp.options && this.mapImp.options.style === "functional") {
777
+ this.isFC = true;
778
+ }
779
+ this.mapImp.setBackgroundOpacity(1);
780
+ this.backgroundChangeCallback(this.currentBackground);
781
+ this.pathways = this.mapImp.pathTypes();
782
+ this.mapImp.enableCentrelines(false);
783
+ //Disable layers for now
784
+ //this.layers = this.mapImp.getLayers();
785
+ this.systems = this.mapImp.getSystems();
786
+ this.addResizeButtonToMinimap();
787
+ this.loading = false;
788
+ this.computePathControlsMaximumHeight();
789
+ this.drawerOpen = true;
790
+ this.mapResize();
791
+ this.$emit("ready", this);
792
+ },
793
+ showMinimap: function(flag) {
794
+ if (this.mapImp)
795
+ this.mapImp.showMinimap(flag);
796
+ },
797
+ showPathwaysDrawer: function(flag) {
798
+ this.drawerOpen = flag;
799
+ },
800
+ /**
801
+ * Function to display features with annotation matching the provided term,
802
+ * with the option to display the label using displayLabel flag.
803
+ */
804
+ searchAndShowResult: function(term, displayLabel) {
805
+ if (this.mapImp) {
806
+ if (term === undefined || term === "") {
807
+ this.mapImp.clearSearchResults();
808
+ return true;
809
+ } else {
810
+ const searchResults = this.mapImp.search(term);
811
+ if (searchResults && searchResults.results &&
812
+ searchResults.results.length > 0) {
813
+ this.mapImp.showSearchResults(searchResults);
814
+ if (displayLabel &&
815
+ searchResults.results[0].featureId &&
816
+ searchResults.results[0].text) {
817
+ this.mapImp.showPopup(
818
+ searchResults.results[0].featureId,
819
+ searchResults.results[0].text,
820
+ { className: "custom-popup", positionAtLastClick: false, preserveSelection: true }
821
+ )
822
+ }
823
+ return true;
824
+ }
825
+ else
826
+ this.mapImp.clearSearchResults();
827
+ }
828
+ }
829
+ return false;
830
+ },
831
+ /**
832
+ * Get the list of suggested terms
833
+ */
834
+ searchSuggestions: function(term) {
835
+ if (this.mapImp)
836
+ return this.mapImp.search(term);
837
+ return [];
838
+ },
839
+ },
840
+ props: {
841
+ entry: String,
842
+ biologicalSex: {
843
+ type: String,
844
+ default: ""
845
+ },
846
+ featureInfo: {
847
+ type: Boolean,
848
+ default: false
849
+ },
850
+ minZoom: {
851
+ type: Number,
852
+ default: 4
853
+ },
854
+ pathControls: {
855
+ type: Boolean,
856
+ default: false
857
+ },
858
+ searchable: {
859
+ type: Boolean,
860
+ default: false
861
+ },
862
+ layerControl: {
863
+ type: Boolean,
864
+ default: false
865
+ },
866
+ tooltips: {
867
+ type: Boolean,
868
+ default: true
869
+ },
870
+ helpMode: {
871
+ type: Boolean,
872
+ default: false
873
+ },
874
+ renderAtMounted: {
875
+ type: Boolean,
876
+ default: true
877
+ },
878
+ displayMinimap: {
879
+ type: Boolean,
880
+ default: false
881
+ },
882
+ displayWarning: {
883
+ type: Boolean,
884
+ default: false
885
+ },
886
+ isLegacy: {
887
+ type: Boolean,
888
+ default: false
889
+ },
890
+ displayLatestChanges: {
891
+ type: Boolean,
892
+ default: false,
893
+ },
894
+ latestChangesMessage: {
895
+ type: String,
896
+ default: "Search now provide suggested terms. Add new legends. New tilesets. New female map. Improve upstream downstream information.",
897
+ },
898
+ /**
899
+ * State containing state of the flatmap.
900
+ */
901
+ state: {
902
+ type: Object,
903
+ default: undefined
904
+ },
905
+ /**
906
+ * Specify the endpoint of the flatmap server.
907
+ */
908
+ flatmapAPI: {
909
+ type: String,
910
+ default: "https://mapcore-demo.org/current/flatmap/v3/"
911
+ },
912
+ sparcAPI: {
913
+ type: String,
914
+ default: "https://api.sparc.science/"
915
+ },
916
+ },
917
+ provide() {
918
+ return {
919
+ sparcAPI: this.sparcAPI,
920
+ flatmapAPI: this.flatmapAPI
921
+ }
922
+ },
923
+ data: function() {
924
+ return {
925
+ layers: [],
926
+ pathways: [],
927
+ sckanDisplay: [
928
+ {
929
+ label: "Display Path with SCKAN",
930
+ key: "VALID",
931
+ },
932
+ ],
933
+ centreLines: [
934
+ {
935
+ label: "Display Nerves",
936
+ key: "centrelines",
937
+ enabled: false
938
+ }
939
+ ],
940
+ systems: [],
941
+ pathwaysMaxHeight: 1000,
942
+ hoverVisibilities: [
943
+ { value: false },
944
+ { value: false },
945
+ { value: false },
946
+ { value: false },
947
+ { value: false },
948
+ { value: false },
949
+ { value: false },
950
+ { value: false }
951
+ ],
952
+ isFC: false,
953
+ inHelp: false,
954
+ currentBackground: "white",
955
+ availableBackground: ["white", "lightskyblue", "black"],
956
+ loading: false,
957
+ flatmapMarker: flatmapMarker,
958
+ tooltipEntry: createUnfilledTooltipData(),
959
+ connectivityTooltipVisible: false,
960
+ resourceForTooltip: undefined,
961
+ drawerOpen: false,
962
+ colourRadio: true,
963
+ outlinesRadio: true,
964
+ minimapResizeShow: false,
965
+ minimapSmall: false,
966
+ };
967
+ },
968
+ watch: {
969
+ entry: function() {
970
+ if (!this.state) this.createFlatmap();
971
+ },
972
+ helpMode: function(val) {
973
+ this.setHelpMode(val);
974
+ },
975
+ state: {
976
+ handler: function(state) {
977
+ if (this.mapManager) {
978
+ this.setState(state);
979
+ } else {
980
+ //this component has not been mounted yet
981
+ this.setStateRequired = true;
982
+ }
983
+ },
984
+ immediate: true,
985
+ deep: true
986
+ }
987
+ },
988
+ computed: {
989
+ getWarningMessage: function() {
990
+ if (this.isLegacy) {
991
+ return "This is a legacy map, you may view the latest map instead.";
992
+ } else if (this.isFC) {
993
+ return "Beta feature - The connectivity shown here is the subset of neurons from the neuron populations in ApiNATOMY models which are at the same spatial scale and level of granularity.";
994
+ }
995
+ return "Beta feature - This map is based on the connectivity of a rat. New connectivity and species specificity will be added as the SPARC program progress.";
996
+ },
997
+ },
998
+ mounted: function() {
999
+ const flatmap = require("@abi-software/flatmap-viewer");
1000
+ this.mapManager = new flatmap.MapManager(this.flatmapAPI);
1001
+ this.flatmapQueries = new FlatmapQueries();
1002
+ this.flatmapQueries.initialise(this.sparcAPI, this.flatmapAPI);
1003
+ if (this.state) {
1004
+ //State is set and require to set the state
1005
+ if (this.setStateRequired) {
1006
+ this.setState(this.state);
1007
+ }
1008
+ } else if(this.renderAtMounted) {
1009
+ this.createFlatmap();
1010
+ }
1011
+ }
1012
+ };
1013
+ </script>
1014
+
1015
+ <!-- Add "scoped" attribute to limit CSS to this component only -->
1016
+ <style scoped lang="scss">
1017
+ @import "~element-ui/packages/theme-chalk/src/button";
1018
+ @import "~element-ui/packages/theme-chalk/src/loading";
1019
+ @import "~element-ui/packages/theme-chalk/src/row";
1020
+
1021
+ .beta-popovers {
1022
+ position: absolute;
1023
+ top: 90px;
1024
+ left: 16px;
1025
+ text-align: left;
1026
+ font-size: 25px;
1027
+ }
1028
+
1029
+ .warning-icon {
1030
+ color: $warning;
1031
+
1032
+ &:hover {
1033
+ cursor: pointer;
1034
+ }
1035
+ }
1036
+
1037
+ .warning-text {
1038
+ font-family: Asap, sans-serif;
1039
+ font-size: 15px;
1040
+ vertical-align: 5px;
1041
+ }
1042
+
1043
+ .latest-map-text {
1044
+ color: $app-primary-color;;
1045
+ font-family: Asap, sans-serif;
1046
+ font-size: 12px;
1047
+ margin-top: 5px;
1048
+ vertical-align: 10px;
1049
+ cursor: pointer;
1050
+ }
1051
+
1052
+ .latest-changesicon {
1053
+ color: $success;
1054
+
1055
+ &:hover {
1056
+ cursor: pointer;
1057
+ }
1058
+ }
1059
+
1060
+ .latest-changestext {
1061
+ font-family: Asap, sans-serif;
1062
+ font-size: 15px;
1063
+ vertical-align: 5px;
1064
+ }
1065
+
1066
+ .flatmap-container {
1067
+ height: 100%;
1068
+ width: 100%;
1069
+ }
1070
+
1071
+ .pathway-location {
1072
+ position: absolute;
1073
+ bottom: 0px;
1074
+ transition: all 1s ease;
1075
+ &.open {
1076
+ left: 0px;
1077
+ }
1078
+ &.close {
1079
+ left: -298px;
1080
+ }
1081
+ }
1082
+
1083
+ .svg-legends-container {
1084
+ width:70%;
1085
+ height:auto;
1086
+ position:relative;
1087
+ max-height:140px;
1088
+ }
1089
+
1090
+ .pathway-container {
1091
+ float: left;
1092
+ padding-left: 16px;
1093
+ padding-right: 18px;
1094
+ text-align: left;
1095
+ overflow: auto;
1096
+ border: 1px solid rgb(220, 223, 230);
1097
+ padding-bottom: 16px;
1098
+ background: #ffffff;
1099
+ overflow-x: hidden;
1100
+ scrollbar-width: thin;
1101
+
1102
+ &::-webkit-scrollbar {
1103
+ width: 4px;
1104
+ }
1105
+
1106
+ &::-webkit-scrollbar-thumb {
1107
+ border-radius: 10px;
1108
+ box-shadow: inset 0 0 6px #c0c4cc;
1109
+ }
1110
+ }
1111
+
1112
+ .flatmap-marker-help {
1113
+ display: inline-block;
1114
+ }
1115
+
1116
+ ::v-deep .popper-bump-right {
1117
+ left: 30px;
1118
+ }
1119
+
1120
+ .el-dropdown-link {
1121
+ cursor: pointer;
1122
+ color: #409eff;
1123
+ }
1124
+ .el-icon-arrow-down {
1125
+ font-size: 12px;
1126
+ }
1127
+ .demonstration {
1128
+ display: block;
1129
+ color: #8492a6;
1130
+ font-size: 14px;
1131
+ margin-bottom: 20px;
1132
+ }
1133
+
1134
+ .tooltip {
1135
+ display: none;
1136
+ }
1137
+
1138
+ ::v-deep .mapboxgl-popup {
1139
+ max-width: 300px !important;
1140
+ }
1141
+
1142
+ ::v-deep .flatmap-tooltip-popup {
1143
+ &.mapboxgl-popup-anchor-bottom {
1144
+ .mapboxgl-popup-content {
1145
+ margin-bottom: 12px;
1146
+ &::after,
1147
+ &::before {
1148
+ top: 100%;
1149
+ border-width: 12px;
1150
+ }
1151
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
1152
+ &::after {
1153
+ margin-top: -1px;
1154
+ border-color: rgb(255, 255, 255) transparent transparent transparent;
1155
+ }
1156
+ /* this border color controlls the outside, thin border */
1157
+ &::before {
1158
+ margin: 0 auto;
1159
+ border-color: $app-primary-color transparent transparent transparent;
1160
+ }
1161
+ }
1162
+ }
1163
+ &.mapboxgl-popup-anchor-top {
1164
+ .mapboxgl-popup-content {
1165
+ margin-top: 18px;
1166
+ &::after,
1167
+ &::before {
1168
+ top: calc(-100% + 6px);
1169
+ border-width: 12px;
1170
+ }
1171
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
1172
+ &::after {
1173
+ margin-top: 1px;
1174
+ border-color: transparent transparent rgb(255, 255, 255) transparent;
1175
+ }
1176
+ &::before {
1177
+ margin: 0 auto;
1178
+ border-color: transparent transparent $app-primary-color transparent;
1179
+ }
1180
+ }
1181
+ }
1182
+ .mapboxgl-popup-content {
1183
+ border-radius: 4px;
1184
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
1185
+ pointer-events: none;
1186
+ display: none;
1187
+ background: #fff;
1188
+ border: 1px solid $app-primary-color;
1189
+ padding-left: 6px;
1190
+ padding-right: 6px;
1191
+ display: flex;
1192
+ justify-content: center;
1193
+ align-items: center;
1194
+ &::after,
1195
+ &::before {
1196
+ content: "";
1197
+ display: block;
1198
+ position: absolute;
1199
+ width: 0;
1200
+ height: 0;
1201
+ border-style: solid;
1202
+ flex-shrink: 0;
1203
+ }
1204
+ }
1205
+ .mapboxgl-popup-tip {
1206
+ display: none;
1207
+ }
1208
+ }
1209
+
1210
+ ::v-deep .mapboxgl-popup {
1211
+ &.flatmap-marker-popup {
1212
+ box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
1213
+ pointer-events: auto;
1214
+ background: #fff;
1215
+ }
1216
+ }
1217
+
1218
+ /* Fix for chrome bug where under triangle pops up above one on top of it */
1219
+ .selector:not(*:root),
1220
+ ::v-deep.flatmap-tooltip-popup {
1221
+ .mapboxgl-popup-content::after {
1222
+ top: 99.9%;
1223
+ }
1224
+ }
1225
+
1226
+ ::v-deep .flatmap-tooltip-dialog {
1227
+ .mapboxgl-popup-tip {
1228
+ display: none;
1229
+ }
1230
+ }
1231
+
1232
+ ::v-deep .flatmap-marker-popup {
1233
+ .mapboxgl-popup-content {
1234
+ padding: 0px;
1235
+ }
1236
+ }
1237
+
1238
+ ::v-deep .flatmapvuer-popover {
1239
+ .mapboxgl-popup-close-button {
1240
+ position: absolute;
1241
+ right: 0.5em;
1242
+ top: 0;
1243
+ border: 0;
1244
+ border-radius: 0 3px 0 0;
1245
+ cursor: pointer;
1246
+ background-color: transparent;
1247
+ font-size: 2.5em;
1248
+ color: grey;
1249
+ top: 0.95em;
1250
+ }
1251
+ }
1252
+
1253
+ .zoomOut {
1254
+ padding-left: 8px;
1255
+ }
1256
+
1257
+ .fitWindow {
1258
+ padding-left: 8px;
1259
+ }
1260
+
1261
+ .background-colour {
1262
+ bottom: 16px;
1263
+ position: absolute;
1264
+ transition: all 1s ease;
1265
+ }
1266
+ .background-colour.open {
1267
+ left: 322px;
1268
+ }
1269
+ .background-colour.close {
1270
+ left: 24px;
1271
+ }
1272
+
1273
+ ::v-deep .background-popper {
1274
+ padding: 5px 12px;
1275
+ background-color: #ffffff;
1276
+ border: 1px solid $app-primary-color;
1277
+ box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.06);
1278
+ height: 200px;
1279
+ width: 175px;
1280
+ min-width: 175px;
1281
+ &.el-popper[x-placement^="top"] {
1282
+ .popper__arrow {
1283
+ border-top-color: $app-primary-color !important;
1284
+ &::after {
1285
+ border-top-color: #fff !important;
1286
+ }
1287
+ }
1288
+ }
1289
+ }
1290
+
1291
+ .backgroundText {
1292
+ color: rgb(48, 49, 51);
1293
+ font-size: 14px;
1294
+ font-weight: normal;
1295
+ line-height: 20px;
1296
+ }
1297
+
1298
+ .backgroundControl {
1299
+ display: flex;
1300
+ margin-top: 16px;
1301
+ }
1302
+
1303
+ .backgroundChoice {
1304
+ width: 20px;
1305
+ height: 20px;
1306
+ border: 1px solid rgb(144, 147, 153);
1307
+ margin-left: 20px;
1308
+ &.active {
1309
+ border: 2px solid $app-primary-color;
1310
+ }
1311
+ &:hover {
1312
+ cursor: pointer;
1313
+ }
1314
+ &.white {
1315
+ background-color: white;
1316
+ margin-left: 10px;
1317
+ }
1318
+ &.black {
1319
+ background-color: black;
1320
+ }
1321
+ &.lightskyblue {
1322
+ background-color: lightskyblue;
1323
+ }
1324
+ }
1325
+
1326
+ .icon-button {
1327
+ height: 24px !important;
1328
+ width: 24px !important;
1329
+ color: $app-primary-color;
1330
+ &:hover {
1331
+ cursor: pointer;
1332
+ }
1333
+ }
1334
+
1335
+ ::v-deep .maplibregl-ctrl-minimap {
1336
+ transform-origin: top right;
1337
+ @media (max-width: 1250px) {
1338
+ height: 125px !important;// important is needed here as we are over-riding the style set by the flatmap
1339
+ width: 180px !important;
1340
+ >>> .maplibregl-canvas .mapboxgl-canvas {
1341
+ height: 125px !important;
1342
+ width: 180px !important;
1343
+ }
1344
+ }
1345
+ @media (min-width: 1251px) {
1346
+ height: 190px !important;
1347
+ width: 300px !important;
1348
+ >>> .maplibregl-canvas .mapboxgl-canvas {
1349
+ height: 190px !important;
1350
+ width: 300px !important;
1351
+ }
1352
+ }
1353
+ transition: all 1s ease;
1354
+ &.shrink {
1355
+ transform: scale(0.5);
1356
+ transform: scale(0.5);
1357
+ }
1358
+ }
1359
+
1360
+ .minimap-resize {
1361
+ position: absolute;
1362
+ pointer-events: all;
1363
+ cursor: pointer;
1364
+ top: 0;
1365
+ right: 0;
1366
+ padding-top: 3px; // needed as icon is offset
1367
+ width: 20px;
1368
+ height: 14px;
1369
+ z-index: 9;
1370
+ transition: all 1s ease;
1371
+ &.shrink {
1372
+ transform: rotate(0deg);
1373
+ }
1374
+ &.enlarge {
1375
+ transform: rotate(180deg) scale(2);
1376
+ padding-bottom: 5px; // note padding is added to the opposite side since it is rotated
1377
+ padding-left: 5px;
1378
+ }
1379
+ }
1380
+
1381
+ ::v-deep .flatmap-popper {
1382
+ padding: 6px 4px;
1383
+ font-size: 12px;
1384
+ color: rgb(48, 49, 51);
1385
+ background-color: #f3ecf6;
1386
+ border: 1px solid $app-primary-color;
1387
+ white-space: nowrap;
1388
+ min-width: unset;
1389
+ &.warning-popper {
1390
+ min-width: 150px;
1391
+ max-width: 400px;
1392
+ word-break: keep-all;
1393
+ white-space: unset;
1394
+ }
1395
+ &.left-popper {
1396
+ .popper__arrow {
1397
+ border-left-color: $app-primary-color !important;
1398
+ &::after {
1399
+ border-left-color: #f3ecf6 !important;
1400
+ }
1401
+ }
1402
+ }
1403
+ &.right-popper {
1404
+ .popper__arrow {
1405
+ border-right-color: $app-primary-color !important;
1406
+ &:after {
1407
+ border-right-color: #f3ecf6 !important;
1408
+ }
1409
+ }
1410
+ }
1411
+ &.el-popper[x-placement^="top"] {
1412
+ .popper__arrow {
1413
+ border-top-color: $app-primary-color !important;
1414
+ &:after {
1415
+ border-top-color: #f3ecf6 !important;
1416
+ }
1417
+ }
1418
+ }
1419
+ }
1420
+
1421
+ ::v-deep .el-loading-spinner {
1422
+ i,
1423
+ .el-loading-text {
1424
+ color: $app-primary-color;
1425
+ }
1426
+ }
1427
+
1428
+ ::v-deep .flatmap-popup-popper {
1429
+ .mapboxgl-popup-tip {
1430
+ border-bottom-color: $app-primary-color;
1431
+ }
1432
+ .mapboxgl-popup-content {
1433
+ padding: 6px 4px;
1434
+ font-size: 12px;
1435
+ color: rgb(48, 49, 51);
1436
+ background-color: #f3ecf6;
1437
+ border: 1px solid $app-primary-color;
1438
+ white-space: nowrap;
1439
+ min-width: unset;
1440
+ .mapboxgl-popup-close-button {
1441
+ display: none;
1442
+ }
1443
+ }
1444
+ }
1445
+
1446
+ ::v-deep .popper-zoomout {
1447
+ padding-right: 13px !important;
1448
+ left: -21px !important;
1449
+ }
1450
+
1451
+ ::v-deep .popper-zoomout {
1452
+ .popper__arrow {
1453
+ left: 53px !important;
1454
+ }
1455
+ }
1456
+
1457
+ ::v-deep .mapboxgl-popup-content {
1458
+ padding: 0px;
1459
+ }
1460
+
1461
+ .bottom-right-control {
1462
+ position: absolute;
1463
+ right: 16px;
1464
+ bottom: 16px;
1465
+ }
1466
+
1467
+ ::v-deep .my-drawer {
1468
+ background: rgba(0, 0, 0, 0);
1469
+ box-shadow: none;
1470
+ }
1471
+
1472
+ .drawer {
1473
+ ::v-deep .el-drawer:focus {
1474
+ outline: none;
1475
+ }
1476
+ }
1477
+
1478
+ .open-drawer,
1479
+ .drawer-button {
1480
+ z-index: 8;
1481
+ width: 20px;
1482
+ height: 40px;
1483
+ border: solid 1px $app-primary-color;
1484
+ text-align: center;
1485
+ vertical-align: middle;
1486
+ cursor: pointer;
1487
+ pointer-events: auto;
1488
+ }
1489
+
1490
+ .open-drawer {
1491
+ position: absolute;
1492
+ left: 0px;
1493
+ background-color: #f7faff;
1494
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
1495
+ }
1496
+
1497
+ .drawer-button {
1498
+ float: left;
1499
+ margin-top: calc(50% - 36px);
1500
+ background-color: #F9F2FC;
1501
+
1502
+ i {
1503
+ font-weight: 600;
1504
+ margin-top: 12px;
1505
+ color: $app-primary-color;
1506
+ transition-delay: 0.9s;
1507
+ }
1508
+ &.open {
1509
+ i {
1510
+ transform: rotate(0deg) scaleY(2);
1511
+ }
1512
+ }
1513
+ &.close {
1514
+ i {
1515
+ transform: rotate(180deg) scaleY(2);
1516
+ }
1517
+ }
1518
+ }
1519
+
1520
+ ::v-deep .mapboxgl-canvas-container {
1521
+ canvas {
1522
+ outline: none;
1523
+ }
1524
+ }
1525
+
1526
+ .backgroundSpacer {
1527
+ border-bottom: 1px solid #e4e7ed;
1528
+ margin-bottom: 10px;
1529
+ }
1530
+
1531
+ .flatmap-radio {
1532
+ ::v-deep label {
1533
+ margin-right: 20px;
1534
+ &:last-child {
1535
+ margin-right: 0px;
1536
+ }
1537
+ }
1538
+ .el-radio__input {
1539
+ &.is-checked {
1540
+ & + .el-radio__label {
1541
+ color: $app-primary-color;
1542
+ }
1543
+ .el-radio__inner {
1544
+ border-color: $app-primary-color;
1545
+ background: $app-primary-color;
1546
+ }
1547
+ }
1548
+ }
1549
+ }
1550
+
1551
+ ::v-deep .custom-popup {
1552
+ .mapboxgl-popup-tip {
1553
+ display: none;
1554
+ }
1555
+ .mapboxgl-popup-content {
1556
+ border-radius: 4px;
1557
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
1558
+ pointer-events: none;
1559
+ display: none;
1560
+ background: #fff;
1561
+ font-family: "Asap",sans-serif;
1562
+ font-size: 12pt;
1563
+ color: $app-primary-color;
1564
+ border: 1px solid $app-primary-color;
1565
+ padding-left: 6px;
1566
+ padding-right: 6px;
1567
+ padding-top: 6px;
1568
+ padding-bottom: 6px;
1569
+ display: flex;
1570
+ justify-content: center;
1571
+ align-items: center;
1572
+ &::after,
1573
+ &::before {
1574
+ content: "";
1575
+ display: block;
1576
+ position: absolute;
1577
+ width: 0;
1578
+ height: 0;
1579
+ border-style: solid;
1580
+ flex-shrink: 0;
1581
+ }
1582
+ .mapboxgl-popup-close-button {
1583
+ display: none;
1584
+ }
1585
+ }
1586
+ &.mapboxgl-popup-anchor-bottom {
1587
+ .mapboxgl-popup-content {
1588
+ margin-bottom: 12px;
1589
+ &::after,
1590
+ &::before {
1591
+ top: 100%;
1592
+ border-width: 12px;
1593
+ }
1594
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
1595
+ &::after {
1596
+ margin-top: -1px;
1597
+ border-color: rgb(255, 255, 255) transparent transparent transparent;
1598
+ }
1599
+ /* this border color controlls the outside, thin border */
1600
+ &::before {
1601
+ margin: 0 auto;
1602
+ border-color: $app-primary-color transparent transparent transparent;
1603
+ }
1604
+ }
1605
+ }
1606
+ &.mapboxgl-popup-anchor-top {
1607
+ .mapboxgl-popup-content {
1608
+ margin-top: 18px;
1609
+ &::after,
1610
+ &::before {
1611
+ top: calc(-100% + 6px);
1612
+ border-width: 12px;
1613
+ }
1614
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
1615
+ &::after {
1616
+ margin-top: 1px;
1617
+ border-color: transparent transparent rgb(255, 255, 255) transparent;
1618
+ }
1619
+ &::before {
1620
+ margin: 0 auto;
1621
+ border-color: transparent transparent $app-primary-color transparent;
1622
+ }
1623
+ }
1624
+ }
1625
+ }
1626
+ </style>
1627
+