@abi-software/flatmapvuer 0.3.14 → 0.3.15

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