@abi-software/flatmapvuer 0.3.6 → 0.3.8

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,1358 +1,1388 @@
1
- <template>
2
- <div
3
- class="flatmap-container"
4
- v-loading="loading"
5
- element-loading-text="Loading..."
6
- element-loading-spinner="el-icon-loading"
7
- element-loading-background="rgba(0, 0, 0, 0.3)"
8
- >
9
- <map-svg-sprite-color />
10
- <div style="height:100%;width:100%;position:relative;overflow-y:none">
11
- <div style="height:100%;width:100%;" ref="display"></div>
12
- <div class="beta-popovers">
13
- <div>
14
- <el-popover
15
- :content="warningMessage"
16
- placement="right"
17
- :appendToBody="false"
18
- trigger="manual"
19
- popper-class="warning-popper flatmap-popper right-popper"
20
- v-model="hoverVisibilities[6].value"
21
- ref="warningPopover"
22
- ></el-popover>
23
- <i
24
- class="el-icon-warning warning-icon"
25
- v-if="displayWarning && warningMessage"
26
- @mouseover="showToolitip(6)"
27
- @mouseout="hideToolitip(6)"
28
- v-popover:warningPopover
29
- >
30
- <span class="warning-text">Beta</span>
31
- </i>
32
- </div>
33
- <el-popover
34
- :content="latestChangesMessage"
35
- placement="right"
36
- v-if="displayLatestChanges"
37
- :appendToBody="false"
38
- trigger="manual"
39
- popper-class="warning-popper flatmap-popper right-popper"
40
- v-model="hoverVisibilities[7].value"
41
- ref="latestChangesPopover"
42
- ></el-popover>
43
- <i
44
- class="el-icon-warning latest-changesicon"
45
- v-if="displayLatestChanges && latestChangesMessage"
46
- @mouseover="showToolitip(7)"
47
- @mouseout="hideToolitip(7)"
48
- v-popover:latestChangesPopover
49
- >
50
- <span class="warning-text">What's new?</span>
51
- </i>
52
- </div>
53
-
54
- <div class="bottom-right-control">
55
- <el-popover
56
- content="Zoom in"
57
- placement="left"
58
- :appendToBody="false"
59
- trigger="manual"
60
- popper-class="flatmap-popper left-popper"
61
- v-model="hoverVisibilities[0].value"
62
- >
63
- <map-svg-icon
64
- icon="zoomIn"
65
- class="icon-button zoomIn"
66
- slot="reference"
67
- @click.native="zoomIn()"
68
- @mouseover.native="showToolitip(0)"
69
- @mouseout.native="hideToolitip(0)"
70
- />
71
- </el-popover>
72
- <el-popover
73
- content="Zoom out"
74
- placement="top-end"
75
- :appendToBody="false"
76
- trigger="manual"
77
- popper-class="flatmap-popper popper-zoomout"
78
- v-model="hoverVisibilities[1].value"
79
- >
80
- <map-svg-icon
81
- icon="zoomOut"
82
- class="icon-button zoomOut"
83
- slot="reference"
84
- @click.native="zoomOut()"
85
- @mouseover.native="showToolitip(1)"
86
- @mouseout.native="hideToolitip(1)"
87
- />
88
- </el-popover>
89
- <el-popover
90
- content="Reset"
91
- placement="top"
92
- :appendToBody="false"
93
- trigger="manual"
94
- popper-class="flatmap-popper"
95
- v-model="hoverVisibilities[2].value"
96
- >
97
- <div>
98
- Fit to
99
- <br>
100
- window
101
- </div>
102
- <map-svg-icon
103
- slot="reference"
104
- icon="fitWindow"
105
- class="icon-button fitWindow"
106
- @click.native="resetView()"
107
- @mouseover.native="showToolitip(2)"
108
- @mouseout.native="hideToolitip(2)"
109
- />
110
- </el-popover>
111
- </div>
112
- <el-popover
113
- content="Change pathway visibility"
114
- placement="right"
115
- :appendToBody="false"
116
- trigger="manual"
117
- popper-class="flatmap-popper right-popper"
118
- v-model="hoverVisibilities[4].value"
119
- ref="checkBoxPopover"
120
- />
121
- <div class="pathway-location" :class="{ open: drawerOpen, close: !drawerOpen }">
122
- <div
123
- class="pathway-container"
124
- v-if="pathways.length > 0 && pathControls"
125
- v-popover:checkBoxPopover
126
- >
127
- <el-popover
128
- content="Find these markers for data"
129
- placement="right"
130
- :appendToBody="false"
131
- trigger="manual"
132
- popper-class="flatmap-popper popper-bump-right right-popper"
133
- v-model="hoverVisibilities[5].value"
134
- ref="markerPopover"
135
- ></el-popover>
136
- <div
137
- v-show="hoverVisibilities[5].value"
138
- class="flatmap-marker-help"
139
- v-html="flatmapMarker"
140
- v-popover:markerPopover
141
- ></div>
142
- <el-row>
143
- <el-col :span="12">
144
- <div class="pathways-display-text">Pathways</div>
145
- </el-col>
146
- <el-col :span="12">
147
- <el-checkbox
148
- class="all-checkbox"
149
- :indeterminate="isIndeterminate"
150
- v-model="checkAll"
151
- @change="handleCheckAllChange"
152
- >Display all</el-checkbox>
153
- </el-col>
154
- </el-row>
155
- <el-checkbox-group
156
- v-model="checkedItems"
157
- size="small"
158
- class="checkbox-group"
159
- @change="handleCheckedItemsChange"
160
- >
161
- <div class="checkbox-group-inner">
162
- <el-row v-for="item in pathways" :key="item.type" :label="item.type">
163
- <div class="checkbox-container">
164
- <el-checkbox
165
- class="my-checkbox"
166
- :label="item.type"
167
- @change="visibilityToggle()"
168
- :checked="true"
169
- >
170
- <div class="path-visual" :class="item.type"></div>
171
- {{item.label}}
172
- </el-checkbox>
173
- </div>
174
- </el-row>
175
- </div>
176
- </el-checkbox-group>
177
- </div>
178
- <div
179
- @click="toggleDrawer"
180
- class="drawer-button"
181
- :class="{ open: drawerOpen, close: !drawerOpen }"
182
- >
183
- <i class="el-icon-arrow-left"></i>
184
- </div>
185
- </div>
186
- <el-popover
187
- ref="backgroundPopover"
188
- placement="top-start"
189
- width="175"
190
- :appendToBody="false"
191
- trigger="click"
192
- popper-class="background-popper"
193
- >
194
- <el-row class="backgroundText">Organs display</el-row>
195
- <el-row class="backgroundControl">
196
- <el-radio-group v-model="colourRadio" class="flatmap-radio" @change="setColour">
197
- <el-radio :label="true">Colour</el-radio>
198
- <el-radio :label="false">Greyscale</el-radio>
199
- </el-radio-group>
200
- </el-row>
201
- <el-row class="backgroundSpacer"></el-row>
202
- <el-row class="backgroundText">Outlines display</el-row>
203
- <el-row class="backgroundControl">
204
- <el-radio-group v-model="outlinesRadio" class="flatmap-radio" @change="setOutlines">
205
- <el-radio :label="true">Show</el-radio>
206
- <el-radio :label="false">Hide</el-radio>
207
- </el-radio-group>
208
- </el-row>
209
- <el-row class="backgroundSpacer"></el-row>
210
- <el-row class="backgroundText">Change background</el-row>
211
- <el-row class="backgroundControl">
212
- <div
213
- v-for="item in availableBackground"
214
- :key="item"
215
- :class="['backgroundChoice', item, item == currentBackground ? 'active' :'']"
216
- @click="backgroundChangeCallback(item)"
217
- />
218
- </el-row>
219
- </el-popover>
220
- <el-popover
221
- content="Change background color"
222
- placement="right"
223
- v-model="hoverVisibilities[3].value"
224
- :appendToBody="false"
225
- trigger="manual"
226
- popper-class="flatmap-popper right-popper"
227
- >
228
- <map-svg-icon
229
- v-popover:backgroundPopover
230
- icon="changeBckgd"
231
- class="icon-button background-colour"
232
- :class="{ open: drawerOpen, close: !drawerOpen }"
233
- slot="reference"
234
- @mouseover.native="showToolitip(3)"
235
- @mouseout.native="hideToolitip(3)"
236
- />
237
- </el-popover>
238
- <Tooltip
239
- ref="tooltip"
240
- class="tooltip"
241
- :content="tooltipContent"
242
- @resource-selected="resourceSelected"
243
- />
244
- </div>
245
- </div>
246
- </template>
247
-
248
- <script>
249
- /* eslint-disable no-alert, no-console */
250
- import Vue from "vue";
251
- import Tooltip from "./Tooltip";
252
- import { MapSvgIcon, MapSvgSpriteColor } from "@abi-software/svg-sprite";
253
- import {
254
- Checkbox,
255
- CheckboxGroup,
256
- Col,
257
- Loading,
258
- Radio,
259
- RadioGroup,
260
- Row
261
- } from "element-ui";
262
- import lang from "element-ui/lib/locale/lang/en";
263
- import locale from "element-ui/lib/locale";
264
- import flatmapMarker from "../icons/flatmap-marker";
265
-
266
- locale.use(lang);
267
- Vue.use(Checkbox);
268
- Vue.use(CheckboxGroup);
269
- Vue.use(Col);
270
- Vue.use(Loading.directive);
271
- Vue.use(Radio);
272
- Vue.use(RadioGroup);
273
- Vue.use(Row);
274
- const ResizeSensor = require("css-element-queries/src/ResizeSensor");
275
-
276
- const mapResize = map => {
277
- return () => {
278
- if (map) map.resize();
279
- };
280
- };
281
-
282
- export default {
283
- name: "FlatmapVuer",
284
- components: {
285
- MapSvgIcon,
286
- MapSvgSpriteColor,
287
- Tooltip
288
- },
289
- beforeCreate: function() {
290
- this.mapManager = undefined;
291
- this.mapImp = undefined;
292
- },
293
- methods: {
294
- backgroundChangeCallback: function(colour) {
295
- this.currentBackground = colour;
296
- if (this.mapImp) {
297
- this.mapImp.setBackgroundColour(this.currentBackground, 1);
298
- }
299
- },
300
- toggleDrawer: function() {
301
- this.drawerOpen = !this.drawerOpen;
302
- },
303
- /**
304
- * Function to toggle colour/greyscale of organs.
305
- */
306
- setColour: function(flag) {
307
- this.colourRadio = flag;
308
- if (this.mapImp) {
309
- this.mapImp.setColour({ colour: flag, outline: this.outlinesRadio });
310
- }
311
- },
312
- /**
313
- * Function to toggle outlines f organs.
314
- */
315
- setOutlines: function(flag) {
316
- this.outlineRadio = flag;
317
- if (this.mapImp) {
318
- this.mapImp.setColour({ colour: this.colourRadio, outline: flag });
319
- }
320
- },
321
- /**
322
- * Function to toggle paths to default.
323
- * Also called when the associated button is pressed.
324
- */
325
- resetView: function() {
326
- if (this.mapImp) {
327
- this.mapImp.resetMap();
328
- this.checkedItems = this.mapImp.pathTypes().map(item => item.type);
329
- this.isIndeterminate = false;
330
- this.checkAll = true;
331
- }
332
- },
333
- /**
334
- * Function to zoom in.
335
- * Also called when the associated button is pressed.
336
- */
337
- zoomIn: function() {
338
- if (this.mapImp) {
339
- this.mapImp.zoomIn();
340
- }
341
- },
342
- /**
343
- * Function to zoom out.
344
- * Also called when the associated button is pressed.
345
- */
346
- zoomOut: function() {
347
- if (this.mapImp) {
348
- this.mapImp.zoomOut();
349
- }
350
- },
351
- visibilityToggle: function() {
352
- if (this.mapImp) {
353
- this.mapImp.showPaths(this.checkedItems);
354
- }
355
- },
356
- handleCheckedItemsChange: function(value) {
357
- let checkedCount = value.length;
358
- this.checkAll = checkedCount === this.pathways.length;
359
- this.isIndeterminate =
360
- checkedCount > 0 && checkedCount < this.pathways.length;
361
- },
362
- handleCheckAllChange(val) {
363
- this.checkedItems = val ? this.pathways.map(a => a.type) : [];
364
- this.isIndeterminate = false;
365
- if (this.mapImp) {
366
- this.mapImp.showPaths(this.checkedItems);
367
- }
368
- },
369
- enablePanZoomEvents: function(flag) {
370
- this.mapImp.enablePanZoomEvents(flag);
371
- },
372
- eventCallback: function() {
373
- return (eventType, data, ...args) => {
374
- if (eventType !== "pan-zoom") {
375
- const label = data.label;
376
- const resource = [data.models];
377
- const taxonomy = this.entry;
378
- const payload = {
379
- dataset: data.dataset,
380
- taxonomy: taxonomy,
381
- resource: resource,
382
- label: label,
383
- feature: data,
384
- userData: args,
385
- eventType: eventType
386
- };
387
- // Disable the nueron pop up for now.
388
- if (data && data.type !== "marker")
389
- this.checkAndCreatePopups(payload);
390
- this.$emit("resource-selected", payload);
391
- } else {
392
- this.$emit("pan-zoom-callback", data);
393
- }
394
- };
395
- },
396
- // checkNeuronClicked shows a neuron path pop up if a path was recently clicked
397
- checkAndCreatePopups: function(data) {
398
- if (
399
- data.eventType == "click" &&
400
- this.hasNeuronTooltip(data)
401
- ) {
402
- this.createTooltipFromNeuronCuration(data);
403
- this.mapImp.showPopup(
404
- this.mapImp.modelFeatureIds(data.resource[0])[0],
405
- this.$refs.tooltip.$el,
406
- { className: "flatmapvuer-popover", positionAtLastClick: true }
407
- );
408
- this.popUpCssHacks();
409
- }
410
- },
411
- popUpCssHacks: function() {
412
- // Below is a hack to remove flatmap tooltips while popup is open
413
- let ftooltip = document.querySelector(".flatmap-tooltip-popup");
414
- if (ftooltip) ftooltip.style.display = "none";
415
- document.querySelector(".mapboxgl-popup-close-button").style.display =
416
- "block";
417
- this.$refs.tooltip.$el.style.display = "flex";
418
- document.querySelector(".mapboxgl-popup-close-button").onclick = () => {
419
- document.querySelector(".flatmap-tooltip-popup").style.display =
420
- "block";
421
- };
422
- },
423
- resourceSelected: function(action) {
424
- this.$emit("resource-selected", action);
425
- },
426
- hasNeuronTooltip: function(data) {
427
-
428
- // neural data check
429
- if (data.resource[0]){
430
- if (data.resource[0].includes('ilxtr:neuron')){
431
- return true
432
- }
433
- }
434
- // annotated with datset check
435
- if (data.dataset) {
436
- return true
437
- }
438
-
439
- // if there is no cuff, neural data, or dataset we do not display neuron tooltip
440
- return false
441
-
442
- },
443
- createTooltipFromNeuronCuration: function(data) {
444
- const feature = data.resource[0];
445
- let content = {
446
- title: undefined,
447
- components: undefined,
448
- start: undefined,
449
- distribution: undefined,
450
- actions: []
451
- };
452
-
453
- this.tooltipVisible = false;
454
-
455
- // neural data check
456
- if (feature){
457
- if (feature.includes('ilxtr:neuron')){
458
- this.tooltipVisible = true;
459
- this.tooltipContent = content;
460
- this.tooltipContent.uberon = feature;
461
- this.tooltipContent.title = data.label;
462
- this.tooltipContent.featureIds = [feature];
463
- this.tooltipContent.actions.push({
464
- title: "Search for datasets",
465
- label: "Neuron Datasets",
466
- resource: feature.split(":")[1],
467
- type: "Neuron Search",
468
- feature: feature,
469
- nervePath: true
470
- });
471
- }
472
- }
473
- // annotated with datset check
474
- if (data.dataset) {
475
- this.tooltipVisible = true;
476
- this.tooltipContent = content;
477
- this.tooltipContent.uberon = feature;
478
- this.tooltipContent.title = data.label;
479
- this.tooltipContent.actions.push({
480
- title: "View dataset",
481
- resource: data.dataset,
482
- type: "URL",
483
- feature: feature,
484
- nervePath: false
485
- });
486
- }
487
- },
488
- // Keeping this as an API
489
- showPopup: function(featureId, node, options) {
490
- let myOptions = options;
491
- if (this.mapImp) {
492
- if (myOptions) {
493
- if (!myOptions.className) myOptions.className = "flatmapvuer-popover";
494
- } else {
495
- myOptions = { className: "flatmapvuer-popover", positionAtLastClick: true };
496
- }
497
- this.mapImp.showPopup(featureId, node, myOptions);
498
- }
499
- },
500
- showMarkerPopup: function(featureId, node, options) {
501
- if (this.mapImp) {
502
- this.mapImp.showMarkerPopup(featureId, node, options);
503
- }
504
- },
505
- setHelpMode: function(helpMode) {
506
- if (helpMode) {
507
- this.inHelp = true;
508
- this.hoverVisibilities.forEach(item => {
509
- item.value = true;
510
- });
511
- this.openFlatmapHelpPopup();
512
- } else {
513
- this.inHelp = false;
514
- this.hoverVisibilities.forEach(item => {
515
- item.value = false;
516
- });
517
- this.closeFlatmapHelpPopup();
518
- }
519
- },
520
- showToolitip: function(tooltipNumber) {
521
- if (!this.inHelp) {
522
- this.tooltipWait = setTimeout(() => {
523
- this.hoverVisibilities[tooltipNumber].value = true;
524
- }, 500);
525
- }
526
- },
527
- hideToolitip: function(tooltipNumber) {
528
- if (!this.inHelp) {
529
- this.hoverVisibilities[tooltipNumber].value = false;
530
- clearTimeout(this.tooltipWait);
531
- }
532
- },
533
- openFlatmapHelpPopup: function() {
534
- if (this.mapImp) {
535
- let heartId = this.mapImp.featureIdsForModel("UBERON:0000948")[0];
536
- const elm = "Click for more information";
537
- this.mapImp.showPopup(heartId, elm, {
538
- anchor: "top",
539
- className: "flatmap-popup-popper"
540
- });
541
- }
542
- },
543
- closeFlatmapHelpPopup: function() {
544
- this.$el
545
- .querySelectorAll(".mapboxgl-popup-close-button")
546
- .forEach(item => {
547
- item.click();
548
- });
549
- },
550
- getLabels: function() {
551
- let labels = [];
552
- if (this.mapImp) {
553
- let annotations = this.mapImp.annotations;
554
- for (let value of annotations.values()) {
555
- if (value.label) labels.push(value.label);
556
- }
557
- return Array.from(new Set(labels));
558
- }
559
- },
560
- getState: function() {
561
- if (this.mapImp) {
562
- let state = {
563
- entry: this.entry,
564
- viewport: this.mapImp.getState()
565
- };
566
- return state;
567
- }
568
- return undefined;
569
- },
570
- setState: function(state) {
571
- if (state) {
572
- if (this.mapImp && state.entry) {
573
- if (this.entry == state.entry)
574
- if (state.viewport) {
575
- this.mapImp.setState(state.viewport);
576
- }
577
- } else {
578
- this.createFlatmap(state);
579
- }
580
- }
581
- },
582
- createFlatmap: function(state) {
583
- if (!this.mapImp && !this.loading) {
584
- this.loading = true;
585
- let minimap = false;
586
- if (this.displayMinimap) {
587
- minimap = { position: "top-right" };
588
- }
589
- let entry = this.entry;
590
- if (state && state.entry) entry = state.entry;
591
- let promise1 = this.mapManager.loadMap(
592
- entry,
593
- this.$refs.display,
594
- this.eventCallback(),
595
- {
596
- //fullscreenControl: false,
597
- //annotatable: false,
598
- //debug: true,
599
- featureInfo: this.featureInfo,
600
- "min-zoom": this.minZoom,
601
- pathControls: false,
602
- searchable: this.searchable,
603
- tooltips: this.tooltips,
604
- minimap: minimap
605
- }
606
- );
607
- promise1.then(returnedObject => {
608
- this.mapImp = returnedObject;
609
- this.sensor = new ResizeSensor(
610
- this.$refs.display,
611
- mapResize(this.mapImp)
612
- );
613
- this.mapImp.setBackgroundOpacity(1);
614
- this.backgroundChangeCallback(this.currentBackground);
615
- this.pathways = this.mapImp.pathTypes();
616
- this.$emit("ready", this);
617
- this.loading = false;
618
- if (this._viewportToBeSet)
619
- this.mapImp.setState(this._viewportToBeSet);
620
- else if (state && state.viewport)
621
- this.mapImp.setState(state.viewport);
622
- });
623
- } else if (state) {
624
- if (this.entry == state.entry) this._viewportToBeSet = state.viewport;
625
- }
626
- },
627
- showMinimap: function(flag) {
628
- if (this.mapImp)
629
- this.mapImp.showMinimap(flag);
630
- },
631
- showPathwaysDrawer: function(flag) {
632
- this.drawerOpen = flag;
633
- },
634
- /**
635
- * Function to display features with annotation matching the provided term.
636
- */
637
- searchAndShowResult: function(term) {
638
- if (this.mapImp) {
639
- if (term === undefined || term === "") {
640
- this.mapImp.clearSearchResults();
641
- return true;
642
- } else {
643
- let searchResults = this.mapImp.search(term);
644
- if (searchResults && searchResults.__featureIds.length > 0) {
645
- this.mapImp.showSearchResults(searchResults);
646
- return true;
647
- }
648
- else
649
- this.mapImp.clearSearchResults();
650
- }
651
- }
652
- return false;
653
- }
654
- },
655
- props: {
656
- entry: String,
657
- featureInfo: {
658
- type: Boolean,
659
- default: false
660
- },
661
- minZoom: {
662
- type: Number,
663
- default: 4
664
- },
665
- pathControls: {
666
- type: Boolean,
667
- default: true
668
- },
669
- searchable: {
670
- type: Boolean,
671
- default: false
672
- },
673
- tooltips: {
674
- type: Boolean,
675
- default: true
676
- },
677
- helpMode: {
678
- type: Boolean,
679
- default: false
680
- },
681
- renderAtMounted: {
682
- type: Boolean,
683
- default: true
684
- },
685
- displayMinimap: {
686
- type: Boolean,
687
- default: false
688
- },
689
- displayWarning: {
690
- type: Boolean,
691
- default: false
692
- },
693
- warningMessage: {
694
- type: String,
695
- 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."
696
- },
697
- displayLatestChanges: {
698
- type: Boolean,
699
- default: false,
700
- },
701
- latestChangesMessage: {
702
- type: String,
703
- default: "Bladder connectivity can now be explored and searched on when selected! To see it, click on any of the paths coming from the bladder. Other pathways will be searchable soon.",
704
- },
705
- /**
706
- * State containing state of the flatmap.
707
- */
708
- state: {
709
- type: Object,
710
- default: undefined
711
- },
712
- /**
713
- * Specify the endpoint of the flatmap server.
714
- */
715
- flatmapAPI: {
716
- type: String,
717
- default: "https://mapcore-demo.org/flatmaps/"
718
- },
719
- sparcAPI: {
720
- type: String,
721
- default: "https://api.sparc.science/"
722
- },
723
- },
724
- provide() {
725
- return {
726
- sparcAPI: this.sparcAPI,
727
- flatmapAPI: this.flatmapAPI
728
- }
729
- },
730
- data: function() {
731
- return {
732
- checkedItems: [],
733
- pathways: [],
734
- isIndeterminate: false,
735
- checkAll: true,
736
- hoverVisibilities: [
737
- { value: false },
738
- { value: false },
739
- { value: false },
740
- { value: false },
741
- { value: false },
742
- { value: false },
743
- { value: false },
744
- { value: false }
745
- ],
746
- inHelp: false,
747
- currentBackground: "white",
748
- availableBackground: ["white", "lightskyblue", "black"],
749
- loading: false,
750
- flatmapMarker: flatmapMarker,
751
- drawerOpen: true,
752
- tooltipContent: { featureIds: []},
753
- colourRadio: true,
754
- outlinesRadio: true
755
- };
756
- },
757
- watch: {
758
- entry: function() {
759
- if (!this.state) this.createFlatmap();
760
- },
761
- helpMode: function(val) {
762
- this.setHelpMode(val);
763
- },
764
- state: {
765
- handler: function(state) {
766
- this.setState(state);
767
- },
768
- immediate: true,
769
- deep: true
770
- }
771
- },
772
- mounted: function() {
773
- const flatmap = require("@abi-software/flatmap-viewer");
774
- this.mapManager = new flatmap.MapManager(this.flatmapAPI);
775
- if (this.renderAtMounted) this.createFlatmap();
776
- }
777
- };
778
- </script>
779
-
780
- <!-- Add "scoped" attribute to limit CSS to this component only -->
781
- <style scoped lang="scss">
782
- @import "~element-ui/packages/theme-chalk/src/button";
783
- @import "~element-ui/packages/theme-chalk/src/checkbox";
784
- @import "~element-ui/packages/theme-chalk/src/checkbox-group";
785
- @import "~element-ui/packages/theme-chalk/src/loading";
786
- @import "~element-ui/packages/theme-chalk/src/row";
787
-
788
- .beta-popovers{
789
- position: absolute;
790
- top: 90px;
791
- left: 16px;
792
- text-align: left;
793
- font-size: 25px;
794
- }
795
-
796
- .warning-icon {
797
- color: $warning;
798
-
799
- &:hover {
800
- cursor: pointer;
801
- }
802
- }
803
-
804
- .warning-text {
805
- font-family: Asap, sans-serif;
806
- font-size: 15px;
807
- vertical-align: 5px;
808
- }
809
-
810
- .latest-changesicon {
811
- color: $success;
812
-
813
- &:hover {
814
- cursor: pointer;
815
- }
816
- }
817
-
818
- .latest-changestext {
819
- font-family: Asap, sans-serif;
820
- font-size: 15px;
821
- vertical-align: 5px;
822
- }
823
-
824
- .path-visual {
825
- margin: 3px 0;
826
- height: 3px;
827
- width: 25px;
828
- margin-right: 5px;
829
- display: inline-block;
830
- &.cns {
831
- background: #9b1fc1;
832
- }
833
- &.lcn {
834
- background: #f19e38;
835
- }
836
- &.para-pre {
837
- background: #3f8f4a;
838
- }
839
- &.para-post {
840
- background: repeating-linear-gradient(
841
- 90deg,
842
- #3f8f4a,
843
- #3f8f4a 6px,
844
- transparent 0,
845
- transparent 9px
846
- );
847
- }
848
- &.sensory {
849
- background: #2a62f6;
850
- }
851
- &.somatic {
852
- background: #98561d;
853
- }
854
- &.symp-pre {
855
- background: #ea3423;
856
- }
857
- &.symp-post {
858
- background: repeating-linear-gradient(
859
- 90deg,
860
- #ea3423,
861
- #ea3423 6px,
862
- transparent 0,
863
- transparent 9px
864
- );
865
- }
866
- }
867
-
868
- .flatmap-container {
869
- height: 100%;
870
- width: 100%;
871
- }
872
-
873
- .pathway-location {
874
- position: absolute;
875
- bottom: 0px;
876
- transition: all 1s ease;
877
- &.open {
878
- left: 0px;
879
- }
880
- &.close {
881
- left: -298px;
882
- }
883
- }
884
-
885
- .pathway-container {
886
- float: left;
887
- padding-left: 16px;
888
- padding-right: 18px;
889
- max-height: calc(100% - 184px);
890
- text-align: left;
891
- overflow: auto;
892
- border: 1px solid rgb(220, 223, 230);
893
- padding-top: 7px;
894
- padding-bottom: 16px;
895
- background: #ffffff;
896
- }
897
-
898
- .pathways-display-text {
899
- width: 59px;
900
- height: 20px;
901
- color: rgb(48, 49, 51);
902
- font-size: 14px;
903
- font-weight: normal;
904
- line-height: 20px;
905
- margin-left: 8px;
906
- }
907
-
908
- .all-checkbox {
909
- float: right;
910
- }
911
-
912
- .checkbox-container {
913
- display: flex;
914
- cursor: pointer;
915
- }
916
-
917
- .checkbox-group {
918
- width: 260px;
919
- border: 1px solid rgb(144, 147, 153);
920
- border-radius: 4px;
921
- background: #ffffff;
922
- }
923
-
924
- .my-checkbox {
925
- background-color: #fff;
926
- width: 100%;
927
- }
928
-
929
- .checkbox-group-inner {
930
- padding: 18px;
931
- }
932
-
933
- .flatmap-marker-help {
934
- display: inline-block;
935
- }
936
-
937
- ::v-deep .popper-bump-right {
938
- left: 30px;
939
- }
940
-
941
- ::v-deep .el-checkbox__label {
942
- padding-left: 5px;
943
- color: $app-primary-color;
944
- font-size: 12px;
945
- font-weight: 500;
946
- letter-spacing: 0px;
947
- line-height: 14px;
948
- }
949
-
950
- ::v-deep .el-checkbox__input {
951
- &.is-indeterminate,
952
- &.is-checked {
953
- .el-checkbox__inner {
954
- background-color: $app-primary-color;
955
- border-color: $app-primary-color;
956
- }
957
- }
958
- }
959
-
960
- ::v-deep .el-checkbox__label {
961
- color: $app-primary-color !important;
962
- }
963
-
964
- .el-dropdown-link {
965
- cursor: pointer;
966
- color: #409eff;
967
- }
968
- .el-icon-arrow-down {
969
- font-size: 12px;
970
- }
971
- .demonstration {
972
- display: block;
973
- color: #8492a6;
974
- font-size: 14px;
975
- margin-bottom: 20px;
976
- }
977
-
978
- .tooltip {
979
- display: none;
980
- }
981
-
982
- ::v-deep .mapboxgl-popup {
983
- max-width: 300px !important;
984
- }
985
-
986
- ::v-deep .flatmap-tooltip-popup {
987
- &.mapboxgl-popup-anchor-bottom {
988
- .mapboxgl-popup-content {
989
- margin-bottom: 12px;
990
- &::after,
991
- &::before {
992
- top: 100%;
993
- border-width: 12px;
994
- }
995
- /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
996
- &::after {
997
- margin-top: -1px;
998
- border-color: rgb(255, 255, 255) transparent transparent transparent;
999
- }
1000
- /* this border color controlls the outside, thin border */
1001
- &::before {
1002
- margin: 0 auto;
1003
- border-color: $app-primary-color transparent transparent transparent;
1004
- }
1005
- }
1006
- }
1007
- &.mapboxgl-popup-anchor-top {
1008
- .mapboxgl-popup-content {
1009
- margin-top: 18px;
1010
- &::after,
1011
- &::before {
1012
- top: calc(-100% + 6px);
1013
- border-width: 12px;
1014
- }
1015
- /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
1016
- &::after {
1017
- margin-top: 1px;
1018
- border-color: transparent transparent rgb(255, 255, 255) transparent;
1019
- }
1020
- &::before {
1021
- margin: 0 auto;
1022
- border-color: transparent transparent $app-primary-color transparent;
1023
- }
1024
- }
1025
- }
1026
- .mapboxgl-popup-content {
1027
- border-radius: 4px;
1028
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
1029
- pointer-events: none;
1030
- display: none;
1031
- background: #fff;
1032
- border: 1px solid $app-primary-color;
1033
- padding-left: 6px;
1034
- padding-right: 6px;
1035
- display: flex;
1036
- justify-content: center;
1037
- align-items: center;
1038
- &::after,
1039
- &::before {
1040
- content: "";
1041
- display: block;
1042
- position: absolute;
1043
- width: 0;
1044
- height: 0;
1045
- border-style: solid;
1046
- flex-shrink: 0;
1047
- }
1048
- }
1049
- .mapboxgl-popup-tip {
1050
- display: none;
1051
- }
1052
- }
1053
-
1054
- ::v-deep .mapboxgl-popup {
1055
- &.flatmap-marker-popup {
1056
- box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
1057
- pointer-events: auto;
1058
- background: #fff;
1059
- }
1060
- }
1061
-
1062
- /* Fix for chrome bug where under triangle pops up above one on top of it */
1063
- .selector:not(*:root),
1064
- ::v-deep.flatmap-tooltip-popup {
1065
- .mapboxgl-popup-content::after {
1066
- top: 99.9%;
1067
- }
1068
- }
1069
-
1070
- ::v-deep .flatmap-tooltip-dialog {
1071
- .mapboxgl-popup-tip {
1072
- display: none;
1073
- }
1074
- }
1075
-
1076
- ::v-deep .flatmap-marker-popup {
1077
- .mapboxgl-popup-content {
1078
- padding: 0px;
1079
- }
1080
- }
1081
-
1082
- ::v-deep .flatmapvuer-popover {
1083
- .mapboxgl-popup-close-button {
1084
- position: absolute;
1085
- right: 0.5em;
1086
- top: 0;
1087
- border: 0;
1088
- border-radius: 0 3px 0 0;
1089
- cursor: pointer;
1090
- background-color: transparent;
1091
- font-size: 2.5em;
1092
- color: grey;
1093
- top: 0.95em;
1094
- }
1095
- }
1096
-
1097
- .zoomOut {
1098
- padding-left: 8px;
1099
- }
1100
-
1101
- .fitWindow {
1102
- padding-left: 8px;
1103
- }
1104
-
1105
- .background-colour {
1106
- bottom: 16px;
1107
- position: absolute;
1108
- transition: all 1s ease;
1109
- }
1110
- .background-colour.open {
1111
- left: 322px;
1112
- }
1113
- .background-colour.close {
1114
- left: 24px;
1115
- }
1116
-
1117
- ::v-deep .background-popper {
1118
- padding: 5px 12px;
1119
- background-color: #ffffff;
1120
- border: 1px solid $app-primary-color;
1121
- box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.06);
1122
- height: 200px;
1123
- width: 175px;
1124
- min-width: 175px;
1125
- &.el-popper[x-placement^="top"] {
1126
- .popper__arrow {
1127
- border-top-color: $app-primary-color !important;
1128
- &::after {
1129
- border-top-color: #fff !important;
1130
- }
1131
- }
1132
- }
1133
- }
1134
-
1135
- .backgroundText {
1136
- color: rgb(48, 49, 51);
1137
- font-size: 14px;
1138
- font-weight: normal;
1139
- line-height: 20px;
1140
- }
1141
-
1142
- .backgroundControl {
1143
- display: flex;
1144
- margin-top: 16px;
1145
- }
1146
-
1147
- .backgroundChoice {
1148
- width: 20px;
1149
- height: 20px;
1150
- border: 1px solid rgb(144, 147, 153);
1151
- margin-left: 20px;
1152
- &.active {
1153
- border: 2px solid $app-primary-color;
1154
- }
1155
- &:hover {
1156
- cursor: pointer;
1157
- }
1158
- &.white {
1159
- background-color: white;
1160
- margin-left: 10px;
1161
- }
1162
- &.black {
1163
- background-color: black;
1164
- }
1165
- &.lightskyblue {
1166
- background-color: white;
1167
- }
1168
- }
1169
-
1170
- .togglePaths {
1171
- top: 201px;
1172
- right: 20px;
1173
- position: absolute;
1174
- }
1175
-
1176
- .icon-button {
1177
- height: 24px !important;
1178
- width: 24px !important;
1179
- color: $app-primary-color;
1180
- &:hover {
1181
- cursor: pointer;
1182
- }
1183
- }
1184
-
1185
- ::v-deep .flatmap-popper {
1186
- padding: 6px 4px;
1187
- font-size: 12px;
1188
- color: rgb(48, 49, 51);
1189
- background-color: #f3ecf6;
1190
- border: 1px solid $app-primary-color;
1191
- white-space: nowrap;
1192
- min-width: unset;
1193
- &.warning-popper {
1194
- min-width: 150px;
1195
- max-width: 400px;
1196
- word-break: keep-all;
1197
- white-space: unset;
1198
- }
1199
- &.left-popper {
1200
- .popper__arrow {
1201
- border-left-color: $app-primary-color !important;
1202
- &::after {
1203
- border-left-color: #f3ecf6 !important;
1204
- }
1205
- }
1206
- }
1207
- &.right-popper {
1208
- .popper__arrow {
1209
- border-right-color: $app-primary-color !important;
1210
- &:after {
1211
- border-right-color: #f3ecf6 !important;
1212
- }
1213
- }
1214
- }
1215
- &.el-popper[x-placement^="top"] {
1216
- .popper__arrow {
1217
- border-top-color: $app-primary-color !important;
1218
- &:after {
1219
- border-top-color: #f3ecf6 !important;
1220
- }
1221
- }
1222
- }
1223
- }
1224
-
1225
- ::v-deep .el-loading-spinner {
1226
- i,
1227
- .el-loading-text {
1228
- color: $app-primary-color;
1229
- }
1230
- }
1231
-
1232
- ::v-deep .flatmap-popup-popper {
1233
- .mapboxgl-popup-tip {
1234
- border-bottom-color: $app-primary-color;
1235
- }
1236
- .mapboxgl-popup-content {
1237
- padding: 6px 4px;
1238
- font-size: 12px;
1239
- color: rgb(48, 49, 51);
1240
- background-color: #f3ecf6;
1241
- border: 1px solid $app-primary-color;
1242
- white-space: nowrap;
1243
- min-width: unset;
1244
- .mapboxgl-popup-close-button {
1245
- display: none;
1246
- }
1247
- }
1248
- }
1249
-
1250
- ::v-deep .flatmap-popper {
1251
-
1252
- }
1253
-
1254
- ::v-deep .popper-zoomout {
1255
- padding-right: 13px !important;
1256
- left: -21px !important;
1257
- }
1258
-
1259
- ::v-deep .popper-zoomout {
1260
- .popper__arrow {
1261
- left: 53px !important;
1262
- }
1263
- }
1264
-
1265
- ::v-deep .mapboxgl-popup-content {
1266
- padding: 0px;
1267
- }
1268
-
1269
- .bottom-right-control {
1270
- position: absolute;
1271
- right: 16px;
1272
- bottom: 16px;
1273
- }
1274
-
1275
- ::v-deep .my-drawer {
1276
- background: rgba(0, 0, 0, 0);
1277
- box-shadow: none;
1278
- }
1279
-
1280
- .drawer {
1281
- ::v-deep .el-drawer:focus {
1282
- outline: none;
1283
- }
1284
- }
1285
-
1286
- .open-drawer,
1287
- .drawer-button {
1288
- z-index: 8;
1289
- width: 20px;
1290
- height: 40px;
1291
- border: solid 1px #e4e7ed;
1292
- text-align: center;
1293
- vertical-align: middle;
1294
- cursor: pointer;
1295
- pointer-events: auto;
1296
- }
1297
-
1298
- .open-drawer {
1299
- position: absolute;
1300
- left: 0px;
1301
- background-color: #f7faff;
1302
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
1303
- }
1304
-
1305
- .drawer-button {
1306
- float: left;
1307
- margin-top: calc(50% - 36px);
1308
- border-left: 0;
1309
- background-color: #ffffff;
1310
- i {
1311
- margin-top: 12px;
1312
- color: $app-primary-color;
1313
- transition-delay: 0.9s;
1314
- }
1315
- &.open {
1316
- i {
1317
- transform: rotate(0deg) scaleY(2.5);
1318
- }
1319
- }
1320
- &.close {
1321
- i {
1322
- transform: rotate(180deg) scaleY(2.5);
1323
- }
1324
- }
1325
- }
1326
-
1327
- ::v-deep .mapboxgl-canvas-container {
1328
- canvas {
1329
- outline: none;
1330
- }
1331
- }
1332
-
1333
- .backgroundSpacer {
1334
- border-bottom: 1px solid #e4e7ed;
1335
- margin-bottom: 10px;
1336
- }
1337
-
1338
- .flatmap-radio {
1339
- ::v-deep label {
1340
- margin-right: 20px;
1341
- &:last-child {
1342
- margin-right: 0px;
1343
- }
1344
- }
1345
- .el-radio__input {
1346
- &.is-checked {
1347
- & + .el-radio__label {
1348
- color: $app-primary-color;
1349
- }
1350
- .el-radio__inner {
1351
- border-color: $app-primary-color;
1352
- background: $app-primary-color;
1353
- }
1354
- }
1355
- }
1356
- }
1357
- </style>
1358
-
1
+ <template>
2
+ <div
3
+ class="flatmap-container"
4
+ v-loading="loading"
5
+ element-loading-text="Loading..."
6
+ element-loading-spinner="el-icon-loading"
7
+ element-loading-background="rgba(0, 0, 0, 0.3)"
8
+ >
9
+ <map-svg-sprite-color />
10
+ <div style="height:100%;width:100%;position:relative;overflow-y:none">
11
+ <div style="height:100%;width:100%;" ref="display"></div>
12
+ <div class="beta-popovers">
13
+ <div>
14
+ <el-popover
15
+ :content="warningMessage"
16
+ placement="right"
17
+ :appendToBody="false"
18
+ trigger="manual"
19
+ popper-class="warning-popper flatmap-popper right-popper"
20
+ v-model="hoverVisibilities[6].value"
21
+ ref="warningPopover"
22
+ ></el-popover>
23
+ <i
24
+ class="el-icon-warning warning-icon"
25
+ v-if="displayWarning && warningMessage"
26
+ @mouseover="showToolitip(6)"
27
+ @mouseout="hideToolitip(6)"
28
+ v-popover:warningPopover
29
+ >
30
+ <span class="warning-text">Beta</span>
31
+ </i>
32
+ </div>
33
+ <el-popover
34
+ :content="latestChangesMessage"
35
+ placement="right"
36
+ v-if="displayLatestChanges"
37
+ :appendToBody="false"
38
+ trigger="manual"
39
+ popper-class="warning-popper flatmap-popper right-popper"
40
+ v-model="hoverVisibilities[7].value"
41
+ ref="latestChangesPopover"
42
+ ></el-popover>
43
+ <i
44
+ class="el-icon-warning latest-changesicon"
45
+ v-if="displayLatestChanges && latestChangesMessage"
46
+ @mouseover="showToolitip(7)"
47
+ @mouseout="hideToolitip(7)"
48
+ v-popover:latestChangesPopover
49
+ >
50
+ <span class="warning-text">What's new?</span>
51
+ </i>
52
+ </div>
53
+
54
+ <div class="bottom-right-control">
55
+ <el-popover
56
+ content="Zoom in"
57
+ placement="left"
58
+ :appendToBody="false"
59
+ trigger="manual"
60
+ popper-class="flatmap-popper left-popper"
61
+ v-model="hoverVisibilities[0].value"
62
+ >
63
+ <map-svg-icon
64
+ icon="zoomIn"
65
+ class="icon-button zoomIn"
66
+ slot="reference"
67
+ @click.native="zoomIn()"
68
+ @mouseover.native="showToolitip(0)"
69
+ @mouseout.native="hideToolitip(0)"
70
+ />
71
+ </el-popover>
72
+ <el-popover
73
+ content="Zoom out"
74
+ placement="top-end"
75
+ :appendToBody="false"
76
+ trigger="manual"
77
+ popper-class="flatmap-popper popper-zoomout"
78
+ v-model="hoverVisibilities[1].value"
79
+ >
80
+ <map-svg-icon
81
+ icon="zoomOut"
82
+ class="icon-button zoomOut"
83
+ slot="reference"
84
+ @click.native="zoomOut()"
85
+ @mouseover.native="showToolitip(1)"
86
+ @mouseout.native="hideToolitip(1)"
87
+ />
88
+ </el-popover>
89
+ <el-popover
90
+ content="Reset"
91
+ placement="top"
92
+ :appendToBody="false"
93
+ trigger="manual"
94
+ popper-class="flatmap-popper"
95
+ v-model="hoverVisibilities[2].value"
96
+ >
97
+ <div>
98
+ Fit to
99
+ <br>
100
+ window
101
+ </div>
102
+ <map-svg-icon
103
+ slot="reference"
104
+ icon="fitWindow"
105
+ class="icon-button fitWindow"
106
+ @click.native="resetView()"
107
+ @mouseover.native="showToolitip(2)"
108
+ @mouseout.native="hideToolitip(2)"
109
+ />
110
+ </el-popover>
111
+ </div>
112
+ <el-popover
113
+ content="Change pathway visibility"
114
+ placement="right"
115
+ :appendToBody="false"
116
+ trigger="manual"
117
+ popper-class="flatmap-popper right-popper"
118
+ v-model="hoverVisibilities[4].value"
119
+ ref="checkBoxPopover"
120
+ />
121
+ <div class="pathway-location" :class="{ open: drawerOpen, close: !drawerOpen }">
122
+ <div
123
+ class="pathway-container"
124
+ v-if="pathways.length > 0 && pathControls"
125
+ v-popover:checkBoxPopover
126
+ >
127
+ <svg-legends class= "svg-legends-container"/>
128
+ <el-popover
129
+ content="Find these markers for data"
130
+ placement="right"
131
+ :appendToBody="false"
132
+ trigger="manual"
133
+ popper-class="flatmap-popper popper-bump-right right-popper"
134
+ v-model="hoverVisibilities[5].value"
135
+ ref="markerPopover"
136
+ ></el-popover>
137
+ <div
138
+ v-show="hoverVisibilities[5].value"
139
+ class="flatmap-marker-help"
140
+ v-html="flatmapMarker"
141
+ v-popover:markerPopover
142
+ ></div>
143
+ <el-row>
144
+ <el-col :span="12">
145
+ <div class="pathways-display-text">Pathways</div>
146
+ </el-col>
147
+ <el-col :span="12">
148
+ <el-checkbox
149
+ class="all-checkbox"
150
+ :indeterminate="isIndeterminate"
151
+ v-model="checkAll"
152
+ @change="handleCheckAllChange"
153
+ >Display all</el-checkbox>
154
+ </el-col>
155
+ </el-row>
156
+ <el-checkbox-group
157
+ v-model="checkedItems"
158
+ size="small"
159
+ class="checkbox-group"
160
+ @change="handleCheckedItemsChange"
161
+ >
162
+ <div class="checkbox-group-inner">
163
+ <el-row v-for="item in pathways" :key="item.type" :label="item.type">
164
+ <div class="checkbox-container">
165
+ <el-checkbox
166
+ class="my-checkbox"
167
+ :label="item.type"
168
+ @change="visibilityToggle()"
169
+ :checked="true"
170
+ >
171
+ <div class="path-visual" :class="item.type"></div>
172
+ {{item.label}}
173
+ </el-checkbox>
174
+ </div>
175
+ </el-row>
176
+ </div>
177
+ </el-checkbox-group>
178
+ </div>
179
+ <div
180
+ @click="toggleDrawer"
181
+ class="drawer-button"
182
+ :class="{ open: drawerOpen, close: !drawerOpen }"
183
+ >
184
+ <i class="el-icon-arrow-left"></i>
185
+ </div>
186
+ </div>
187
+ <el-popover
188
+ ref="backgroundPopover"
189
+ placement="top-start"
190
+ width="175"
191
+ :appendToBody="false"
192
+ trigger="click"
193
+ popper-class="background-popper"
194
+ >
195
+ <el-row class="backgroundText">Organs display</el-row>
196
+ <el-row class="backgroundControl">
197
+ <el-radio-group v-model="colourRadio" class="flatmap-radio" @change="setColour">
198
+ <el-radio :label="true">Colour</el-radio>
199
+ <el-radio :label="false">Greyscale</el-radio>
200
+ </el-radio-group>
201
+ </el-row>
202
+ <el-row class="backgroundSpacer"></el-row>
203
+ <el-row class="backgroundText">Outlines display</el-row>
204
+ <el-row class="backgroundControl">
205
+ <el-radio-group v-model="outlinesRadio" class="flatmap-radio" @change="setOutlines">
206
+ <el-radio :label="true">Show</el-radio>
207
+ <el-radio :label="false">Hide</el-radio>
208
+ </el-radio-group>
209
+ </el-row>
210
+ <el-row class="backgroundSpacer"></el-row>
211
+ <el-row class="backgroundText">Change background</el-row>
212
+ <el-row class="backgroundControl">
213
+ <div
214
+ v-for="item in availableBackground"
215
+ :key="item"
216
+ :class="['backgroundChoice', item, item == currentBackground ? 'active' :'']"
217
+ @click="backgroundChangeCallback(item)"
218
+ />
219
+ </el-row>
220
+ </el-popover>
221
+ <el-popover
222
+ content="Change background color"
223
+ placement="right"
224
+ v-model="hoverVisibilities[3].value"
225
+ :appendToBody="false"
226
+ trigger="manual"
227
+ popper-class="flatmap-popper right-popper"
228
+ >
229
+ <map-svg-icon
230
+ v-popover:backgroundPopover
231
+ icon="changeBckgd"
232
+ class="icon-button background-colour"
233
+ :class="{ open: drawerOpen, close: !drawerOpen }"
234
+ slot="reference"
235
+ @mouseover.native="showToolitip(3)"
236
+ @mouseout.native="hideToolitip(3)"
237
+ />
238
+ </el-popover>
239
+ <Tooltip
240
+ ref="tooltip"
241
+ class="tooltip"
242
+ :content="tooltipContent"
243
+ @resource-selected="resourceSelected"
244
+ />
245
+ </div>
246
+ </div>
247
+ </template>
248
+
249
+ <script>
250
+ /* eslint-disable no-alert, no-console */
251
+ import Vue from "vue";
252
+ import Tooltip from "./Tooltip";
253
+ import { MapSvgIcon, MapSvgSpriteColor } from "@abi-software/svg-sprite";
254
+ import SvgLegends from "./legends/Legends";
255
+ import {
256
+ Checkbox,
257
+ CheckboxGroup,
258
+ Col,
259
+ Loading,
260
+ Radio,
261
+ RadioGroup,
262
+ Row
263
+ } from "element-ui";
264
+ import lang from "element-ui/lib/locale/lang/en";
265
+ import locale from "element-ui/lib/locale";
266
+ import flatmapMarker from "../icons/flatmap-marker";
267
+
268
+ locale.use(lang);
269
+ Vue.use(Checkbox);
270
+ Vue.use(CheckboxGroup);
271
+ Vue.use(Col);
272
+ Vue.use(Loading.directive);
273
+ Vue.use(Radio);
274
+ Vue.use(RadioGroup);
275
+ Vue.use(Row);
276
+ const ResizeSensor = require("css-element-queries/src/ResizeSensor");
277
+
278
+ const mapResize = map => {
279
+ return () => {
280
+ if (map) map.resize();
281
+ };
282
+ };
283
+
284
+ export default {
285
+ name: "FlatmapVuer",
286
+ components: {
287
+ MapSvgIcon,
288
+ MapSvgSpriteColor,
289
+ Tooltip,
290
+ SvgLegends
291
+ },
292
+ beforeCreate: function() {
293
+ this.mapManager = undefined;
294
+ this.mapImp = undefined;
295
+ },
296
+ methods: {
297
+ backgroundChangeCallback: function(colour) {
298
+ this.currentBackground = colour;
299
+ if (this.mapImp) {
300
+ this.mapImp.setBackgroundColour(this.currentBackground, 1);
301
+ }
302
+ },
303
+ toggleDrawer: function() {
304
+ this.drawerOpen = !this.drawerOpen;
305
+ },
306
+ /**
307
+ * Function to toggle colour/greyscale of organs.
308
+ */
309
+ setColour: function(flag) {
310
+ this.colourRadio = flag;
311
+ if (this.mapImp) {
312
+ this.mapImp.setColour({ colour: flag, outline: this.outlinesRadio });
313
+ }
314
+ },
315
+ /**
316
+ * Function to toggle outlines f organs.
317
+ */
318
+ setOutlines: function(flag) {
319
+ this.outlineRadio = flag;
320
+ if (this.mapImp) {
321
+ this.mapImp.setColour({ colour: this.colourRadio, outline: flag });
322
+ }
323
+ },
324
+ /**
325
+ * Function to toggle paths to default.
326
+ * Also called when the associated button is pressed.
327
+ */
328
+ resetView: function() {
329
+ if (this.mapImp) {
330
+ this.mapImp.resetMap();
331
+ this.checkedItems = this.mapImp.pathTypes().map(item => item.type);
332
+ this.isIndeterminate = false;
333
+ this.checkAll = true;
334
+ }
335
+ },
336
+ /**
337
+ * Function to zoom in.
338
+ * Also called when the associated button is pressed.
339
+ */
340
+ zoomIn: function() {
341
+ if (this.mapImp) {
342
+ this.mapImp.zoomIn();
343
+ }
344
+ },
345
+ /**
346
+ * Function to zoom out.
347
+ * Also called when the associated button is pressed.
348
+ */
349
+ zoomOut: function() {
350
+ if (this.mapImp) {
351
+ this.mapImp.zoomOut();
352
+ }
353
+ },
354
+ visibilityToggle: function() {
355
+ if (this.mapImp) {
356
+ this.mapImp.showPaths(this.checkedItems);
357
+ }
358
+ },
359
+ handleCheckedItemsChange: function(value) {
360
+ let checkedCount = value.length;
361
+ this.checkAll = checkedCount === this.pathways.length;
362
+ this.isIndeterminate =
363
+ checkedCount > 0 && checkedCount < this.pathways.length;
364
+ },
365
+ handleCheckAllChange(val) {
366
+ this.checkedItems = val ? this.pathways.map(a => a.type) : [];
367
+ this.isIndeterminate = false;
368
+ if (this.mapImp) {
369
+ this.mapImp.showPaths(this.checkedItems);
370
+ }
371
+ },
372
+ enablePanZoomEvents: function(flag) {
373
+ this.mapImp.enablePanZoomEvents(flag);
374
+ },
375
+ eventCallback: function() {
376
+ return (eventType, data, ...args) => {
377
+ if (eventType !== "pan-zoom") {
378
+ const label = data.label;
379
+ const resource = [data.models];
380
+ const taxonomy = this.entry;
381
+ const flatmapId = this.flatmapId;
382
+ const payload = {
383
+ dataset: data.dataset,
384
+ flatmapId: flatmapId,
385
+ taxonomy: taxonomy,
386
+ resource: resource,
387
+ label: label,
388
+ feature: data,
389
+ userData: args,
390
+ eventType: eventType
391
+ };
392
+ // Disable the nueron pop up for now.
393
+ if (data && data.type !== "marker")
394
+ this.checkAndCreatePopups(payload);
395
+ this.$emit("resource-selected", payload);
396
+ } else {
397
+ this.$emit("pan-zoom-callback", data);
398
+ }
399
+ };
400
+ },
401
+ // checkNeuronClicked shows a neuron path pop up if a path was recently clicked
402
+ checkAndCreatePopups: function(data) {
403
+ if (
404
+ data.eventType == "click" &&
405
+ this.hasNeuronTooltip(data)
406
+ ) {
407
+ this.createTooltipFromNeuronCuration(data);
408
+ this.mapImp.showPopup(
409
+ this.mapImp.modelFeatureIds(data.resource[0])[0],
410
+ this.$refs.tooltip.$el,
411
+ { className: "flatmapvuer-popover", positionAtLastClick: true }
412
+ );
413
+ this.popUpCssHacks();
414
+ }
415
+ },
416
+ popUpCssHacks: function() {
417
+ // Below is a hack to remove flatmap tooltips while popup is open
418
+ let ftooltip = document.querySelector(".flatmap-tooltip-popup");
419
+ if (ftooltip) ftooltip.style.display = "none";
420
+ document.querySelector(".mapboxgl-popup-close-button").style.display =
421
+ "block";
422
+ this.$refs.tooltip.$el.style.display = "flex";
423
+ document.querySelector(".mapboxgl-popup-close-button").onclick = () => {
424
+ document.querySelector(".flatmap-tooltip-popup").style.display =
425
+ "block";
426
+ };
427
+ },
428
+ resourceSelected: function(action) {
429
+ this.$emit("resource-selected", action);
430
+ },
431
+ hasNeuronTooltip: function(data) {
432
+
433
+ // neural data check
434
+ if (data.resource[0]){
435
+ if (data.resource[0].includes('ilxtr:neuron')){
436
+ return true
437
+ }
438
+ }
439
+ // annotated with datset check
440
+ if (data.dataset) {
441
+ return true
442
+ }
443
+
444
+ // if there is no cuff, neural data, or dataset we do not display neuron tooltip
445
+ return false
446
+
447
+ },
448
+ createTooltipFromNeuronCuration: function(data) {
449
+ const feature = data.resource[0];
450
+ let content = {
451
+ title: undefined,
452
+ components: undefined,
453
+ start: undefined,
454
+ distribution: undefined,
455
+ actions: []
456
+ };
457
+
458
+ this.tooltipVisible = false;
459
+
460
+ // neural data check
461
+ if (feature){
462
+ if (feature.includes('ilxtr:neuron')){
463
+ this.tooltipVisible = true;
464
+ this.tooltipContent = content;
465
+ this.tooltipContent.uberon = feature;
466
+ this.tooltipContent.title = data.label;
467
+ this.tooltipContent.featureIds = [feature];
468
+ this.tooltipContent.actions.push({
469
+ title: "Search for datasets",
470
+ label: "Neuron Datasets",
471
+ resource: feature.split(":")[1],
472
+ type: "Neuron Search",
473
+ feature: feature,
474
+ nervePath: true
475
+ });
476
+ }
477
+ }
478
+ // annotated with datset check
479
+ if (data.dataset) {
480
+ this.tooltipVisible = true;
481
+ this.tooltipContent = content;
482
+ this.tooltipContent.uberon = feature;
483
+ this.tooltipContent.title = data.label;
484
+ this.tooltipContent.actions.push({
485
+ title: "View dataset",
486
+ resource: data.dataset,
487
+ type: "URL",
488
+ feature: feature,
489
+ nervePath: false
490
+ });
491
+ }
492
+ },
493
+ // Keeping this as an API
494
+ showPopup: function(featureId, node, options) {
495
+ let myOptions = options;
496
+ if (this.mapImp) {
497
+ if (myOptions) {
498
+ if (!myOptions.className) myOptions.className = "flatmapvuer-popover";
499
+ } else {
500
+ myOptions = { className: "flatmapvuer-popover", positionAtLastClick: true };
501
+ }
502
+ this.mapImp.showPopup(featureId, node, myOptions);
503
+ }
504
+ },
505
+ showMarkerPopup: function(featureId, node, options) {
506
+ if (this.mapImp) {
507
+ this.mapImp.showMarkerPopup(featureId, node, options);
508
+ }
509
+ },
510
+ setHelpMode: function(helpMode) {
511
+ if (helpMode) {
512
+ this.inHelp = true;
513
+ this.hoverVisibilities.forEach(item => {
514
+ item.value = true;
515
+ });
516
+ this.openFlatmapHelpPopup();
517
+ } else {
518
+ this.inHelp = false;
519
+ this.hoverVisibilities.forEach(item => {
520
+ item.value = false;
521
+ });
522
+ this.closeFlatmapHelpPopup();
523
+ }
524
+ },
525
+ showToolitip: function(tooltipNumber) {
526
+ if (!this.inHelp) {
527
+ this.tooltipWait = setTimeout(() => {
528
+ this.hoverVisibilities[tooltipNumber].value = true;
529
+ }, 500);
530
+ }
531
+ },
532
+ hideToolitip: function(tooltipNumber) {
533
+ if (!this.inHelp) {
534
+ this.hoverVisibilities[tooltipNumber].value = false;
535
+ clearTimeout(this.tooltipWait);
536
+ }
537
+ },
538
+ openFlatmapHelpPopup: function() {
539
+ if (this.mapImp) {
540
+ let heartId = this.mapImp.featureIdsForModel("UBERON:0000948")[0];
541
+ const elm = "Click for more information";
542
+ this.mapImp.showPopup(heartId, elm, {
543
+ anchor: "top",
544
+ className: "flatmap-popup-popper"
545
+ });
546
+ }
547
+ },
548
+ closeFlatmapHelpPopup: function() {
549
+ this.$el
550
+ .querySelectorAll(".mapboxgl-popup-close-button")
551
+ .forEach(item => {
552
+ item.click();
553
+ });
554
+ },
555
+ getLabels: function() {
556
+ let labels = [];
557
+ if (this.mapImp) {
558
+ let annotations = this.mapImp.annotations;
559
+ for (let value of annotations.values()) {
560
+ if (value.label) labels.push(value.label);
561
+ }
562
+ return Array.from(new Set(labels));
563
+ }
564
+ },
565
+ getState: function() {
566
+ if (this.mapImp) {
567
+ let state = {
568
+ entry: this.entry,
569
+ flatmapId: this.flatmapId,
570
+ viewport: this.mapImp.getState()
571
+ };
572
+ return state;
573
+ }
574
+ return undefined;
575
+ },
576
+ setState: function(state) {
577
+ if (state) {
578
+ if (this.mapImp && (state.entry || state.flatmapId)) {
579
+ if ((this.flatmapId && (this.flatmapId == state.flatmapId)) || (this.entry == state.entry))
580
+ if (state.viewport) {
581
+ this.mapImp.setState(state.viewport);
582
+ }
583
+ } else {
584
+ this.createFlatmap(state);
585
+ }
586
+ }
587
+ },
588
+ createFlatmap: function(state) {
589
+ if (!this.mapImp && !this.loading) {
590
+ this.loading = true;
591
+ let minimap = false;
592
+ if (this.displayMinimap) {
593
+ minimap = { position: "top-right" };
594
+ }
595
+
596
+ let entry = this.flatmapId;
597
+ if (state && state.flatmapId) entry = state.flatmapId;
598
+ if (!entry) {
599
+ entry = this.entry;
600
+ if (state && state.entry) entry = state.entry;
601
+ }
602
+
603
+ let promise1 = this.mapManager.loadMap(
604
+ entry,
605
+ this.$refs.display,
606
+ this.eventCallback(),
607
+ {
608
+ //fullscreenControl: false,
609
+ //annotatable: false,
610
+ //debug: true,
611
+ featureInfo: this.featureInfo,
612
+ "min-zoom": this.minZoom,
613
+ pathControls: false,
614
+ searchable: this.searchable,
615
+ tooltips: this.tooltips,
616
+ minimap: minimap
617
+ }
618
+ );
619
+ promise1.then(returnedObject => {
620
+ this.mapImp = returnedObject;
621
+ this.sensor = new ResizeSensor(
622
+ this.$refs.display,
623
+ mapResize(this.mapImp)
624
+ );
625
+ this.mapImp.setBackgroundOpacity(1);
626
+ this.backgroundChangeCallback(this.currentBackground);
627
+ this.pathways = this.mapImp.pathTypes();
628
+ this.$emit("ready", this);
629
+ this.loading = false;
630
+ if (this._viewportToBeSet)
631
+ this.mapImp.setState(this._viewportToBeSet);
632
+ else if (state && state.viewport)
633
+ this.mapImp.setState(state.viewport);
634
+ });
635
+ } else if (state) {
636
+ if ((this.flatmapId == state.flatmapId) || this.entry == state.entry)
637
+ this._viewportToBeSet = state.viewport;
638
+ }
639
+ },
640
+ showMinimap: function(flag) {
641
+ if (this.mapImp)
642
+ this.mapImp.showMinimap(flag);
643
+ },
644
+ showPathwaysDrawer: function(flag) {
645
+ this.drawerOpen = flag;
646
+ },
647
+ /**
648
+ * Function to display features with annotation matching the provided term.
649
+ */
650
+ searchAndShowResult: function(term) {
651
+ if (this.mapImp) {
652
+ if (term === undefined || term === "") {
653
+ this.mapImp.clearSearchResults();
654
+ return true;
655
+ } else {
656
+ let searchResults = this.mapImp.search(term);
657
+ if (searchResults && searchResults.__featureIds.length > 0) {
658
+ this.mapImp.showSearchResults(searchResults);
659
+ return true;
660
+ }
661
+ else
662
+ this.mapImp.clearSearchResults();
663
+ }
664
+ }
665
+ return false;
666
+ },
667
+ /**
668
+ * Get the list of suggested terms
669
+ */
670
+ searchSuggestions: function(term) {
671
+ if (this.mapImp)
672
+ return this.mapImp.search(term);
673
+ return [];
674
+ },
675
+ },
676
+ props: {
677
+ entry: String,
678
+ flatmapId: String,
679
+ featureInfo: {
680
+ type: Boolean,
681
+ default: false
682
+ },
683
+ minZoom: {
684
+ type: Number,
685
+ default: 4
686
+ },
687
+ pathControls: {
688
+ type: Boolean,
689
+ default: true
690
+ },
691
+ searchable: {
692
+ type: Boolean,
693
+ default: false
694
+ },
695
+ tooltips: {
696
+ type: Boolean,
697
+ default: true
698
+ },
699
+ helpMode: {
700
+ type: Boolean,
701
+ default: false
702
+ },
703
+ renderAtMounted: {
704
+ type: Boolean,
705
+ default: true
706
+ },
707
+ displayMinimap: {
708
+ type: Boolean,
709
+ default: false
710
+ },
711
+ displayWarning: {
712
+ type: Boolean,
713
+ default: false
714
+ },
715
+ warningMessage: {
716
+ type: String,
717
+ 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."
718
+ },
719
+ displayLatestChanges: {
720
+ type: Boolean,
721
+ default: false,
722
+ },
723
+ latestChangesMessage: {
724
+ type: String,
725
+ default: "Search now provide suggested terms. Add new legends. New tilesets. New female map. Improve upstream downstream information",
726
+ },
727
+ /**
728
+ * State containing state of the flatmap.
729
+ */
730
+ state: {
731
+ type: Object,
732
+ default: undefined
733
+ },
734
+ /**
735
+ * Specify the endpoint of the flatmap server.
736
+ */
737
+ flatmapAPI: {
738
+ type: String,
739
+ default: "https://mapcore-demo.org/current/flatmap/v3/"
740
+ },
741
+ sparcAPI: {
742
+ type: String,
743
+ default: "https://api.sparc.science/"
744
+ },
745
+ },
746
+ provide() {
747
+ return {
748
+ sparcAPI: this.sparcAPI,
749
+ flatmapAPI: this.flatmapAPI
750
+ }
751
+ },
752
+ data: function() {
753
+ return {
754
+ checkedItems: [],
755
+ pathways: [],
756
+ isIndeterminate: false,
757
+ checkAll: true,
758
+ hoverVisibilities: [
759
+ { value: false },
760
+ { value: false },
761
+ { value: false },
762
+ { value: false },
763
+ { value: false },
764
+ { value: false },
765
+ { value: false },
766
+ { value: false }
767
+ ],
768
+ inHelp: false,
769
+ currentBackground: "white",
770
+ availableBackground: ["white", "lightskyblue", "black"],
771
+ loading: false,
772
+ flatmapMarker: flatmapMarker,
773
+ drawerOpen: true,
774
+ tooltipContent: { featureIds: []},
775
+ colourRadio: true,
776
+ outlinesRadio: true
777
+ };
778
+ },
779
+ watch: {
780
+ entry: function() {
781
+ if (!this.state) this.createFlatmap();
782
+ },
783
+ flatmapId: function() {
784
+ if (!this.state) this.createFlatmap();
785
+ },
786
+ helpMode: function(val) {
787
+ this.setHelpMode(val);
788
+ },
789
+ state: {
790
+ handler: function(state) {
791
+ this.setState(state);
792
+ },
793
+ immediate: true,
794
+ deep: true
795
+ }
796
+ },
797
+ mounted: function() {
798
+ const flatmap = require("@abi-software/flatmap-viewer");
799
+ this.mapManager = new flatmap.MapManager(this.flatmapAPI);
800
+ if (this.renderAtMounted) this.createFlatmap();
801
+ }
802
+ };
803
+ </script>
804
+
805
+ <!-- Add "scoped" attribute to limit CSS to this component only -->
806
+ <style scoped lang="scss">
807
+ @import "~element-ui/packages/theme-chalk/src/button";
808
+ @import "~element-ui/packages/theme-chalk/src/checkbox";
809
+ @import "~element-ui/packages/theme-chalk/src/checkbox-group";
810
+ @import "~element-ui/packages/theme-chalk/src/loading";
811
+ @import "~element-ui/packages/theme-chalk/src/row";
812
+
813
+ .beta-popovers {
814
+ position: absolute;
815
+ top: 90px;
816
+ left: 16px;
817
+ text-align: left;
818
+ font-size: 25px;
819
+ }
820
+
821
+ .warning-icon {
822
+ color: $warning;
823
+
824
+ &:hover {
825
+ cursor: pointer;
826
+ }
827
+ }
828
+
829
+ .warning-text {
830
+ font-family: Asap, sans-serif;
831
+ font-size: 15px;
832
+ vertical-align: 5px;
833
+ }
834
+
835
+ .latest-changesicon {
836
+ color: $success;
837
+
838
+ &:hover {
839
+ cursor: pointer;
840
+ }
841
+ }
842
+
843
+ .latest-changestext {
844
+ font-family: Asap, sans-serif;
845
+ font-size: 15px;
846
+ vertical-align: 5px;
847
+ }
848
+
849
+ .path-visual {
850
+ margin: 3px 0;
851
+ height: 3px;
852
+ width: 25px;
853
+ margin-right: 5px;
854
+ display: inline-block;
855
+ &.cns {
856
+ background: #9b1fc1;
857
+ }
858
+ &.lcn {
859
+ background: #f19e38;
860
+ }
861
+ &.para-pre {
862
+ background: #3f8f4a;
863
+ }
864
+ &.para-post {
865
+ background: repeating-linear-gradient(
866
+ 90deg,
867
+ #3f8f4a,
868
+ #3f8f4a 6px,
869
+ transparent 0,
870
+ transparent 9px
871
+ );
872
+ }
873
+ &.sensory {
874
+ background: #2a62f6;
875
+ }
876
+ &.somatic {
877
+ background: #98561d;
878
+ }
879
+ &.symp-pre {
880
+ background: #ea3423;
881
+ }
882
+ &.symp-post {
883
+ background: repeating-linear-gradient(
884
+ 90deg,
885
+ #ea3423,
886
+ #ea3423 6px,
887
+ transparent 0,
888
+ transparent 9px
889
+ );
890
+ }
891
+ }
892
+
893
+ .flatmap-container {
894
+ height: 100%;
895
+ width: 100%;
896
+ }
897
+
898
+ .pathway-location {
899
+ position: absolute;
900
+ bottom: 0px;
901
+ transition: all 1s ease;
902
+ &.open {
903
+ left: 0px;
904
+ }
905
+ &.close {
906
+ left: -298px;
907
+ }
908
+ }
909
+
910
+ .svg-legends-container {
911
+ width:70%;
912
+ height:auto;
913
+ }
914
+
915
+ .pathway-container {
916
+ float: left;
917
+ padding-left: 16px;
918
+ padding-right: 18px;
919
+ max-height: calc(100% - 184px);
920
+ text-align: left;
921
+ overflow: auto;
922
+ border: 1px solid rgb(220, 223, 230);
923
+ padding-bottom: 16px;
924
+ background: #ffffff;
925
+ }
926
+
927
+ .pathways-display-text {
928
+ width: 59px;
929
+ height: 20px;
930
+ color: rgb(48, 49, 51);
931
+ font-size: 14px;
932
+ font-weight: normal;
933
+ line-height: 20px;
934
+ margin-left: 8px;
935
+ }
936
+
937
+ .all-checkbox {
938
+ float: right;
939
+ }
940
+
941
+ .checkbox-container {
942
+ display: flex;
943
+ cursor: pointer;
944
+ }
945
+
946
+ .checkbox-group {
947
+ width: 260px;
948
+ border: 1px solid rgb(144, 147, 153);
949
+ border-radius: 4px;
950
+ background: #ffffff;
951
+ }
952
+
953
+ .my-checkbox {
954
+ background-color: #fff;
955
+ width: 100%;
956
+ }
957
+
958
+ .checkbox-group-inner {
959
+ padding: 18px;
960
+ }
961
+
962
+ .flatmap-marker-help {
963
+ display: inline-block;
964
+ }
965
+
966
+ ::v-deep .popper-bump-right {
967
+ left: 30px;
968
+ }
969
+
970
+ ::v-deep .el-checkbox__label {
971
+ padding-left: 5px;
972
+ color: $app-primary-color;
973
+ font-size: 12px;
974
+ font-weight: 500;
975
+ letter-spacing: 0px;
976
+ line-height: 14px;
977
+ }
978
+
979
+ ::v-deep .el-checkbox__input {
980
+ &.is-indeterminate,
981
+ &.is-checked {
982
+ .el-checkbox__inner {
983
+ background-color: $app-primary-color;
984
+ border-color: $app-primary-color;
985
+ }
986
+ }
987
+ }
988
+
989
+ ::v-deep .el-checkbox__label {
990
+ color: $app-primary-color !important;
991
+ }
992
+
993
+ .el-dropdown-link {
994
+ cursor: pointer;
995
+ color: #409eff;
996
+ }
997
+ .el-icon-arrow-down {
998
+ font-size: 12px;
999
+ }
1000
+ .demonstration {
1001
+ display: block;
1002
+ color: #8492a6;
1003
+ font-size: 14px;
1004
+ margin-bottom: 20px;
1005
+ }
1006
+
1007
+ .tooltip {
1008
+ display: none;
1009
+ }
1010
+
1011
+ ::v-deep .mapboxgl-popup {
1012
+ max-width: 300px !important;
1013
+ }
1014
+
1015
+ ::v-deep .flatmap-tooltip-popup {
1016
+ &.mapboxgl-popup-anchor-bottom {
1017
+ .mapboxgl-popup-content {
1018
+ margin-bottom: 12px;
1019
+ &::after,
1020
+ &::before {
1021
+ top: 100%;
1022
+ border-width: 12px;
1023
+ }
1024
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
1025
+ &::after {
1026
+ margin-top: -1px;
1027
+ border-color: rgb(255, 255, 255) transparent transparent transparent;
1028
+ }
1029
+ /* this border color controlls the outside, thin border */
1030
+ &::before {
1031
+ margin: 0 auto;
1032
+ border-color: $app-primary-color transparent transparent transparent;
1033
+ }
1034
+ }
1035
+ }
1036
+ &.mapboxgl-popup-anchor-top {
1037
+ .mapboxgl-popup-content {
1038
+ margin-top: 18px;
1039
+ &::after,
1040
+ &::before {
1041
+ top: calc(-100% + 6px);
1042
+ border-width: 12px;
1043
+ }
1044
+ /* this border color controlls the color of the triangle (what looks like the fill of the triangle) */
1045
+ &::after {
1046
+ margin-top: 1px;
1047
+ border-color: transparent transparent rgb(255, 255, 255) transparent;
1048
+ }
1049
+ &::before {
1050
+ margin: 0 auto;
1051
+ border-color: transparent transparent $app-primary-color transparent;
1052
+ }
1053
+ }
1054
+ }
1055
+ .mapboxgl-popup-content {
1056
+ border-radius: 4px;
1057
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
1058
+ pointer-events: none;
1059
+ display: none;
1060
+ background: #fff;
1061
+ border: 1px solid $app-primary-color;
1062
+ padding-left: 6px;
1063
+ padding-right: 6px;
1064
+ display: flex;
1065
+ justify-content: center;
1066
+ align-items: center;
1067
+ &::after,
1068
+ &::before {
1069
+ content: "";
1070
+ display: block;
1071
+ position: absolute;
1072
+ width: 0;
1073
+ height: 0;
1074
+ border-style: solid;
1075
+ flex-shrink: 0;
1076
+ }
1077
+ }
1078
+ .mapboxgl-popup-tip {
1079
+ display: none;
1080
+ }
1081
+ }
1082
+
1083
+ ::v-deep .mapboxgl-popup {
1084
+ &.flatmap-marker-popup {
1085
+ box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
1086
+ pointer-events: auto;
1087
+ background: #fff;
1088
+ }
1089
+ }
1090
+
1091
+ /* Fix for chrome bug where under triangle pops up above one on top of it */
1092
+ .selector:not(*:root),
1093
+ ::v-deep.flatmap-tooltip-popup {
1094
+ .mapboxgl-popup-content::after {
1095
+ top: 99.9%;
1096
+ }
1097
+ }
1098
+
1099
+ ::v-deep .flatmap-tooltip-dialog {
1100
+ .mapboxgl-popup-tip {
1101
+ display: none;
1102
+ }
1103
+ }
1104
+
1105
+ ::v-deep .flatmap-marker-popup {
1106
+ .mapboxgl-popup-content {
1107
+ padding: 0px;
1108
+ }
1109
+ }
1110
+
1111
+ ::v-deep .flatmapvuer-popover {
1112
+ .mapboxgl-popup-close-button {
1113
+ position: absolute;
1114
+ right: 0.5em;
1115
+ top: 0;
1116
+ border: 0;
1117
+ border-radius: 0 3px 0 0;
1118
+ cursor: pointer;
1119
+ background-color: transparent;
1120
+ font-size: 2.5em;
1121
+ color: grey;
1122
+ top: 0.95em;
1123
+ }
1124
+ }
1125
+
1126
+ .zoomOut {
1127
+ padding-left: 8px;
1128
+ }
1129
+
1130
+ .fitWindow {
1131
+ padding-left: 8px;
1132
+ }
1133
+
1134
+ .background-colour {
1135
+ bottom: 16px;
1136
+ position: absolute;
1137
+ transition: all 1s ease;
1138
+ }
1139
+ .background-colour.open {
1140
+ left: 322px;
1141
+ }
1142
+ .background-colour.close {
1143
+ left: 24px;
1144
+ }
1145
+
1146
+ ::v-deep .background-popper {
1147
+ padding: 5px 12px;
1148
+ background-color: #ffffff;
1149
+ border: 1px solid $app-primary-color;
1150
+ box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.06);
1151
+ height: 200px;
1152
+ width: 175px;
1153
+ min-width: 175px;
1154
+ &.el-popper[x-placement^="top"] {
1155
+ .popper__arrow {
1156
+ border-top-color: $app-primary-color !important;
1157
+ &::after {
1158
+ border-top-color: #fff !important;
1159
+ }
1160
+ }
1161
+ }
1162
+ }
1163
+
1164
+ .backgroundText {
1165
+ color: rgb(48, 49, 51);
1166
+ font-size: 14px;
1167
+ font-weight: normal;
1168
+ line-height: 20px;
1169
+ }
1170
+
1171
+ .backgroundControl {
1172
+ display: flex;
1173
+ margin-top: 16px;
1174
+ }
1175
+
1176
+ .backgroundChoice {
1177
+ width: 20px;
1178
+ height: 20px;
1179
+ border: 1px solid rgb(144, 147, 153);
1180
+ margin-left: 20px;
1181
+ &.active {
1182
+ border: 2px solid $app-primary-color;
1183
+ }
1184
+ &:hover {
1185
+ cursor: pointer;
1186
+ }
1187
+ &.white {
1188
+ background-color: white;
1189
+ margin-left: 10px;
1190
+ }
1191
+ &.black {
1192
+ background-color: black;
1193
+ }
1194
+ &.lightskyblue {
1195
+ background-color: lightskyblue;
1196
+ }
1197
+ }
1198
+
1199
+ .togglePaths {
1200
+ top: 201px;
1201
+ right: 20px;
1202
+ position: absolute;
1203
+ }
1204
+
1205
+ .icon-button {
1206
+ height: 24px !important;
1207
+ width: 24px !important;
1208
+ color: $app-primary-color;
1209
+ &:hover {
1210
+ cursor: pointer;
1211
+ }
1212
+ }
1213
+
1214
+ ::v-deep .flatmap-popper {
1215
+ padding: 6px 4px;
1216
+ font-size: 12px;
1217
+ color: rgb(48, 49, 51);
1218
+ background-color: #f3ecf6;
1219
+ border: 1px solid $app-primary-color;
1220
+ white-space: nowrap;
1221
+ min-width: unset;
1222
+ &.warning-popper {
1223
+ min-width: 150px;
1224
+ max-width: 400px;
1225
+ word-break: keep-all;
1226
+ white-space: unset;
1227
+ }
1228
+ &.left-popper {
1229
+ .popper__arrow {
1230
+ border-left-color: $app-primary-color !important;
1231
+ &::after {
1232
+ border-left-color: #f3ecf6 !important;
1233
+ }
1234
+ }
1235
+ }
1236
+ &.right-popper {
1237
+ .popper__arrow {
1238
+ border-right-color: $app-primary-color !important;
1239
+ &:after {
1240
+ border-right-color: #f3ecf6 !important;
1241
+ }
1242
+ }
1243
+ }
1244
+ &.el-popper[x-placement^="top"] {
1245
+ .popper__arrow {
1246
+ border-top-color: $app-primary-color !important;
1247
+ &:after {
1248
+ border-top-color: #f3ecf6 !important;
1249
+ }
1250
+ }
1251
+ }
1252
+ }
1253
+
1254
+ ::v-deep .el-loading-spinner {
1255
+ i,
1256
+ .el-loading-text {
1257
+ color: $app-primary-color;
1258
+ }
1259
+ }
1260
+
1261
+ ::v-deep .flatmap-popup-popper {
1262
+ .mapboxgl-popup-tip {
1263
+ border-bottom-color: $app-primary-color;
1264
+ }
1265
+ .mapboxgl-popup-content {
1266
+ padding: 6px 4px;
1267
+ font-size: 12px;
1268
+ color: rgb(48, 49, 51);
1269
+ background-color: #f3ecf6;
1270
+ border: 1px solid $app-primary-color;
1271
+ white-space: nowrap;
1272
+ min-width: unset;
1273
+ .mapboxgl-popup-close-button {
1274
+ display: none;
1275
+ }
1276
+ }
1277
+ }
1278
+
1279
+ ::v-deep .flatmap-popper {
1280
+
1281
+ }
1282
+
1283
+ ::v-deep .popper-zoomout {
1284
+ padding-right: 13px !important;
1285
+ left: -21px !important;
1286
+ }
1287
+
1288
+ ::v-deep .popper-zoomout {
1289
+ .popper__arrow {
1290
+ left: 53px !important;
1291
+ }
1292
+ }
1293
+
1294
+ ::v-deep .mapboxgl-popup-content {
1295
+ padding: 0px;
1296
+ }
1297
+
1298
+ .bottom-right-control {
1299
+ position: absolute;
1300
+ right: 16px;
1301
+ bottom: 16px;
1302
+ }
1303
+
1304
+ ::v-deep .my-drawer {
1305
+ background: rgba(0, 0, 0, 0);
1306
+ box-shadow: none;
1307
+ }
1308
+
1309
+ .drawer {
1310
+ ::v-deep .el-drawer:focus {
1311
+ outline: none;
1312
+ }
1313
+ }
1314
+
1315
+ .open-drawer,
1316
+ .drawer-button {
1317
+ z-index: 8;
1318
+ width: 20px;
1319
+ height: 40px;
1320
+ border: solid 1px $app-primary-color;
1321
+ text-align: center;
1322
+ vertical-align: middle;
1323
+ cursor: pointer;
1324
+ pointer-events: auto;
1325
+ }
1326
+
1327
+ .open-drawer {
1328
+ position: absolute;
1329
+ left: 0px;
1330
+ background-color: #f7faff;
1331
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
1332
+ }
1333
+
1334
+ .drawer-button {
1335
+ float: left;
1336
+ margin-top: calc(50% - 36px);
1337
+ background-color: #F9F2FC;
1338
+
1339
+ i {
1340
+ font-weight: 600;
1341
+ margin-top: 12px;
1342
+ color: $app-primary-color;
1343
+ transition-delay: 0.9s;
1344
+ }
1345
+ &.open {
1346
+ i {
1347
+ transform: rotate(0deg) scaleY(2);
1348
+ }
1349
+ }
1350
+ &.close {
1351
+ i {
1352
+ transform: rotate(180deg) scaleY(2);
1353
+ }
1354
+ }
1355
+ }
1356
+
1357
+ ::v-deep .mapboxgl-canvas-container {
1358
+ canvas {
1359
+ outline: none;
1360
+ }
1361
+ }
1362
+
1363
+ .backgroundSpacer {
1364
+ border-bottom: 1px solid #e4e7ed;
1365
+ margin-bottom: 10px;
1366
+ }
1367
+
1368
+ .flatmap-radio {
1369
+ ::v-deep label {
1370
+ margin-right: 20px;
1371
+ &:last-child {
1372
+ margin-right: 0px;
1373
+ }
1374
+ }
1375
+ .el-radio__input {
1376
+ &.is-checked {
1377
+ & + .el-radio__label {
1378
+ color: $app-primary-color;
1379
+ }
1380
+ .el-radio__inner {
1381
+ border-color: $app-primary-color;
1382
+ background: $app-primary-color;
1383
+ }
1384
+ }
1385
+ }
1386
+ }
1387
+ </style>
1388
+