@abi-software/flatmapvuer 1.1.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +120 -120
  3. package/cypress.config.js +23 -23
  4. package/dist/flatmapvuer.js +43580 -38546
  5. package/dist/flatmapvuer.umd.cjs +189 -181
  6. package/dist/index.html +17 -17
  7. package/dist/style.css +1 -1
  8. package/package.json +95 -95
  9. package/public/index.html +17 -17
  10. package/reporter-config.json +9 -9
  11. package/src/App.vue +379 -379
  12. package/src/assets/_variables.scss +43 -43
  13. package/src/assets/styles.scss +5 -5
  14. package/src/components/AnnotationTool.vue +501 -501
  15. package/src/components/ConnectionDialog.vue +134 -134
  16. package/src/components/DrawTool.vue +502 -502
  17. package/src/components/EventBus.js +3 -3
  18. package/src/components/ExternalResourceCard.vue +109 -109
  19. package/src/components/FlatmapVuer.vue +3515 -3455
  20. package/src/components/HelpModeDialog.vue +360 -360
  21. package/src/components/MultiFlatmapVuer.vue +814 -814
  22. package/src/components/ProvenancePopup.vue +530 -530
  23. package/src/components/SelectionsGroup.vue +363 -363
  24. package/src/components/Tooltip.vue +50 -50
  25. package/src/components/TreeControls.vue +236 -236
  26. package/src/components/index.js +8 -8
  27. package/src/components/legends/DynamicLegends.vue +106 -106
  28. package/src/components/legends/SvgLegends.vue +112 -112
  29. package/src/icons/flatmap-marker.js +9 -1
  30. package/src/icons/fonts/mapicon-species.svg +14 -14
  31. package/src/icons/fonts/mapicon-species.ttf +0 -0
  32. package/src/icons/fonts/mapicon-species.woff +0 -0
  33. package/src/icons/mapicon-species-style.css +42 -42
  34. package/src/icons/yellowstar.js +5 -5
  35. package/src/legends/legend.svg +25 -25
  36. package/src/main.js +19 -19
  37. package/src/services/flatmapQueries.js +475 -475
  38. package/src/store/index.js +23 -23
  39. package/vite.config.js +73 -73
  40. package/vite.static-build.js +12 -12
  41. package/vuese-generator.js +64 -64
@@ -1,814 +1,814 @@
1
- <template>
2
- <div class="multi-container" ref="multiContainer">
3
- <div style="position: absolute; z-index: 10" v-if="!disableUI">
4
- <div class="species-display-text">Species</div>
5
- <el-popover
6
- content="Select a species"
7
- placement="right"
8
- trigger="manual"
9
- popper-class="flatmap-popper flatmap-teleport-popper right-popper"
10
- width="max-content"
11
- :visible="activateTooltipByIndex(0)"
12
- :teleported="false"
13
- ref="selectPopover"
14
- >
15
- <template #reference>
16
- <el-select
17
- id="flatmap-select"
18
- :teleported="false"
19
- v-model="activeSpecies"
20
- placeholder="Select"
21
- class="select-box"
22
- popper-class="flatmap-dropdown"
23
- @change="setSpecies"
24
- >
25
- <el-option
26
- v-for="(item, key) in speciesList"
27
- :key="key"
28
- :label="key"
29
- :value="key"
30
- >
31
- <span class="select-box-icon">
32
- <i :class="item.iconClass"></i>
33
- </span>
34
- {{ key }}
35
- </el-option>
36
- </el-select>
37
- </template>
38
-
39
- </el-popover>
40
- </div>
41
- <FlatmapVuer
42
- v-for="(item, key) in speciesList"
43
- :key="key"
44
- v-show="activeSpecies == key"
45
- :entry="item.taxo"
46
- :uuid="item.uuid"
47
- :biologicalSex="item.biologicalSex"
48
- :displayWarning="item.displayWarning"
49
- :displayLatestChanges="item.displayLatestChanges"
50
- :isLegacy="item.isLegacy"
51
- :ref="key"
52
- :enableOpenMapUI="enableOpenMapUI"
53
- :openMapOptions="openMapOptions"
54
- :disableUI="disableUI"
55
- @view-latest-map="viewLatestMap"
56
- @resource-selected="resourceSelected"
57
- @ready="FlatmapReady"
58
- @pan-zoom-callback="panZoomCallback"
59
- @open-map="
60
- /**
61
- * This event is emitted when the user chooses a different map option
62
- * from ``openMapOptions`` props.
63
- * @arg $event
64
- */
65
- $emit('open-map', $event)"
66
- @pathway-selection-changed="onSelectionsDataChanged"
67
- :minZoom="minZoom"
68
- :helpMode="activeSpecies == key && helpMode"
69
- :helpModeActiveItem="helpModeActiveItem"
70
- :helpModeDialog="helpModeDialog"
71
- :helpModeInitialIndex="-2"
72
- @help-mode-last-item="onHelpModeLastItem"
73
- @shown-tooltip="onTooltipShown"
74
- @shown-map-tooltip="onMapTooltipShown"
75
- :renderAtMounted="renderAtMounted"
76
- :displayMinimap="displayMinimap"
77
- :showStarInLegend="showStarInLegend"
78
- style="height: 100%"
79
- :flatmapAPI="flatmapAPI"
80
- :sparcAPI="sparcAPI"
81
- />
82
- </div>
83
- </template>
84
-
85
- <script>
86
- /* eslint-disable no-alert, no-console */
87
- import { reactive } from 'vue'
88
- import EventBus from './EventBus'
89
- import FlatmapVuer from './FlatmapVuer.vue'
90
- import * as flatmap from '@abi-software/flatmap-viewer'
91
- import {
92
- ElCol as Col,
93
- ElOption as Option,
94
- ElSelect as Select,
95
- ElRow as Row,
96
- ElPopover as Popover,
97
- } from 'element-plus'
98
-
99
- const TAXON_UUID = {
100
- 'NCBITaxon:10114': '01fedbf9-d783-509c-a10c-827941ab13da',
101
- 'NCBITaxon:9823': 'a336ac04-24db-561f-a25f-1c994fe17410',
102
- 'NCBITaxon:9606': '42ed6323-f645-5fbe-bada-9581819cf689',
103
- 'NCBITaxon:10090': '25285fab-48a0-5620-a6a0-f9a0374837d5',
104
- 'NCBITaxon:9685': '73060497-46a6-52bf-b975-cac511c127cb',
105
- }
106
-
107
- /**
108
- * A vue component to show a flatmap from the list of multiple flatmap data.
109
- */
110
- export default {
111
- name: 'MultiFlatmapVuer',
112
- components: {
113
- Col,
114
- Row,
115
- Option,
116
- Select,
117
- Popover,
118
- FlatmapVuer,
119
- },
120
- beforeMount() {
121
- //List for resolving the promise in initialise
122
- //if initialise is called multiple times
123
- this._resolveList = []
124
- this._initialised = false
125
- },
126
- mounted: function () {
127
- this.initialise()
128
- EventBus.on('onActionClick', (action) => {
129
- this.resourceSelected(action)
130
- })
131
- EventBus.on('open-pubmed-url', (url) => {
132
- /**
133
- * This event is emitted when the user clicks
134
- * on "Open publications in pubmed" button
135
- * from provenance popup.
136
- * @arg url
137
- */
138
- this.$emit('open-pubmed-url', url);
139
- });
140
- },
141
- methods: {
142
- /**
143
- * @vuese
144
- * Function to initialise the component when mounted.
145
- * It returns a promise.
146
- */
147
- initialise: function () {
148
- return new Promise((resolve) => {
149
- if (this.requireInitialisation) {
150
- //It has not been initialised yet
151
- this.requireInitialisation = false
152
- fetch(this.flatmapAPI)
153
- .then((response) => response.json())
154
- .then((data) => {
155
- //Check each key in the provided availableSpecies against the one
156
- Object.keys(this.availableSpecies).forEach((key) => {
157
- // FIrst look through the uuid
158
- const uuid = this.availableSpecies[key].uuid
159
- if (uuid && data.map((e) => e.uuid).indexOf(uuid) > 0) {
160
- this.speciesList[key] = reactive(this.availableSpecies[key])
161
- } else {
162
- for (let i = 0; i < data.length; i++) {
163
- if (this.availableSpecies[key].taxo === data[i].taxon) {
164
- if (this.availableSpecies[key].biologicalSex) {
165
- if (
166
- data[i].biologicalSex &&
167
- data[i].biologicalSex ===
168
- this.availableSpecies[key].biologicalSex
169
- ) {
170
- this.speciesList[key] = reactive(this.availableSpecies[key])
171
- break
172
- }
173
- } else {
174
- this.speciesList[key] = reactive(this.availableSpecies[key])
175
- break
176
- }
177
- }
178
- }
179
- }
180
- })
181
- //Use the state species if it does not have any other species information
182
- let species = this.initial
183
- if (this.state) {
184
- const mapState = this.state.state
185
- if (
186
- (!mapState || (!mapState.uuid && !mapState.entry)) &&
187
- this.state.species
188
- )
189
- species = this.state.species
190
- else species = undefined
191
- }
192
- if (species) {
193
- //No state resuming, set the current flatmap to {this.initial}
194
- if (species && this.speciesList[species] !== undefined) {
195
- this.activeSpecies = species
196
- } else {
197
- this.activeSpecies = Object.keys(this.speciesList)[0]
198
- }
199
- this.setSpecies(
200
- this.activeSpecies,
201
- this.state ? this.state.state : undefined,
202
- 5
203
- )
204
- }
205
- this._initialised = true
206
- resolve()
207
- //Resolve all other promises resolve in the list
208
- this._resolveList.forEach((other) => {
209
- other()
210
- })
211
- })
212
- } else if (this._initialised) {
213
- //resolve as it has been initialised
214
- resolve()
215
- } else {
216
- //resolve when the async initialisation is finished
217
- this._resolveList.push(resolve)
218
- }
219
- })
220
- },
221
- /**
222
- * @vuese
223
- * Function to emit ``resource-selected`` event with provided ``resource``.
224
- * @arg action
225
- */
226
- resourceSelected: function (action) {
227
- /**
228
- * This event is emitted by ``resourceSelected`` method.
229
- */
230
- this.$emit('resource-selected', action)
231
- },
232
- /**
233
- * @vuese
234
- * Function to emit ``ready`` event after the flatmap is loaded.
235
- * @arg component
236
- */
237
- FlatmapReady: function (component) {
238
- /**
239
- * This event is emitted by ``FlatmapReady`` method after the flatmap is loaded.
240
- * @arg component
241
- */
242
- this.$emit('ready', component)
243
- },
244
- /**
245
- * @vuese
246
- * Function to get the current active map.
247
- */
248
- getCurrentFlatmap: function () {
249
- return this.$refs[this.activeSpecies][0]
250
- },
251
- /**
252
- * @vuese
253
- * Function to emit ``pan-zoom-callback`` event
254
- * from the event emitted in ``callback`` function from ``MapManager.loadMap()``.
255
- * @arg payload
256
- */
257
- panZoomCallback: function (payload) {
258
- /**
259
- * The event emitted by ``panZoomCallback`` method.
260
- * @arg payload
261
- */
262
- this.$emit('pan-zoom-callback', payload)
263
- },
264
- onSelectionsDataChanged: function (data) {
265
- this.$emit('pathway-selection-changed', data);
266
- },
267
- /**
268
- * @vuese
269
- * Function to show popup on map.
270
- * @arg featureId,
271
- * @arg node,
272
- * @arg options
273
- */
274
- showPopup: function (featureId, node, options) {
275
- let map = this.getCurrentFlatmap()
276
- map.showPopup(featureId, node, options)
277
- },
278
- /**
279
- * @vuese
280
- * Function to show marker popup.
281
- * @arg featureId,
282
- * @arg node,
283
- * @arg options
284
- */
285
- showMarkerPopup: function (featureId, node, options) {
286
- let map = this.getCurrentFlatmap()
287
- map.showMarkerPopup(featureId, node, options)
288
- },
289
- /**
290
- * @vuese
291
- * Function to set species.
292
- * This function is called on the first load and
293
- * when user changes the species.
294
- * @arg species,
295
- * @arg state,
296
- * @arg numberOfRetry
297
- */
298
- setSpecies: function (species, state, numberOfRetry) {
299
- if (this.$refs && species in this.$refs) {
300
- this.activeSpecies = species
301
- this.$refs[this.activeSpecies][0].createFlatmap(state)
302
- /**
303
- * This event is emitted by ``setSpecies`` method.
304
- * Emitted on first load and when user changes species.
305
- * @arg activeSpecies
306
- */
307
- this.$emit('flatmapChanged', this.activeSpecies)
308
- } else if (numberOfRetry) {
309
- const retry = numberOfRetry - 1
310
- if (retry >= 0) {
311
- this.$nextTick(() => {
312
- this.setSpecies(species, state, retry)
313
- })
314
- }
315
- }
316
- },
317
- /**
318
- * @vuese
319
- * Function to switch to the latest existing map from
320
- * a legacy map of the same species.
321
- * @arg state
322
- *
323
- * @private
324
- */
325
- viewLatestMap: function (state) {
326
- const keys = Object.keys(this.speciesList)
327
- for (let i = 0; i < keys.length; i++) {
328
- const species = this.speciesList[keys[i]]
329
- if (
330
- !species.isLegacy &&
331
- species.taxo === state.entry &&
332
- species.biologicalSex === state.biologicalSex
333
- ) {
334
- this.setSpecies(keys[i], state, 0)
335
- return
336
- }
337
- }
338
- },
339
- /**
340
- * @vuese
341
- * Create a legacy entry with the provided information
342
- * @arg state,
343
- * @arg taxo,
344
- * @arg uuid
345
- *
346
- * @private
347
- */
348
- createLegacyEntry: function (state, taxo, uuid) {
349
- if (uuid && taxo) {
350
- let name = 'Legacy'
351
- if (state.species) {
352
- if (state.species.slice(0, 6) === 'Legacy') name = state.species
353
- else name = name + ` ${state.species}`
354
- }
355
- this.speciesList[name] = reactive({
356
- taxo: taxo,
357
- isLegacy: true,
358
- displayWarning: true,
359
- })
360
- return {
361
- species: name,
362
- state: {
363
- entry: taxo,
364
- uuid: uuid,
365
- viewport: state.state.viewport,
366
- searchTerm: state.state.searchTerm,
367
- },
368
- }
369
- }
370
- },
371
- /**
372
- * @vuese
373
- * Function used to translate the legacy map state to one that can be used in current
374
- * flatmap if required. If it is a legacy, an Select entry will be added
375
- * @arg state
376
- *
377
- * @private
378
- */
379
- updateState: function (state) {
380
- return new Promise((resolve) => {
381
- if (state && state.state) {
382
- const mapState = state.state
383
- //uuid is not in the state, this is a legacy map
384
- if (!mapState.uuid) {
385
- if (mapState.entry) {
386
- const uuid =
387
- mapState.entry in TAXON_UUID
388
- ? TAXON_UUID[mapState.entry]
389
- : undefined
390
- const newState = this.createLegacyEntry(
391
- state,
392
- mapState.entry,
393
- uuid
394
- )
395
- resolve(newState ? newState : state)
396
- }
397
- } else if (mapState.entry) {
398
- //uuid is in the state but should be checked if it is the latest map
399
- //for that taxon
400
- return new Promise(() => {
401
- const mapManager = new flatmap.MapManager(this.flatmapAPI)
402
- //mapManager.findMap_ is an async function so we need to wrap this with a promise
403
- const identifier = { taxon: mapState.entry }
404
- if (mapState.biologicalSex)
405
- identifier['biologicalSex'] = mapState.biologicalSex
406
- mapManager
407
- .findMap_(identifier)
408
- .then((map) => {
409
- if (map.uuid !== mapState.uuid) {
410
- return this.createLegacyEntry(
411
- state,
412
- mapState.entry,
413
- mapState.uuid
414
- )
415
- }
416
- })
417
- .then((newState) => {
418
- resolve(newState ? newState : state)
419
- })
420
- .catch(() => {
421
- resolve(state)
422
- })
423
- })
424
- }
425
- //Create a new state and add the legacy map to the select
426
- }
427
- resolve(state)
428
- })
429
- },
430
- /**
431
- * @vuese
432
- * Function used for getting the current states of the scene. This exported states
433
- * can be imported using the importStates method.
434
- *
435
- * @public
436
- */
437
- getState: function () {
438
- let state = {
439
- species: this.activeSpecies,
440
- state: undefined,
441
- }
442
- let map = this.getCurrentFlatmap()
443
- state.state = map.getState()
444
- return state
445
- },
446
- /**
447
- * @vuese
448
- * Function used for importing the states of the scene. This exported states
449
- * can be imported using the read states method.
450
- * @arg state
451
- *
452
- * @public
453
- */
454
- setState: function (state) {
455
- if (state) {
456
- //Update state if required
457
- this.updateState(state).then((currentState) => {
458
- this.initialise().then(() => {
459
- if (
460
- currentState.species &&
461
- currentState.species !== this.activeSpecies
462
- ) {
463
- this.setSpecies(currentState.species, currentState.state, 5)
464
- } else if (currentState.state) {
465
- let map = this.getCurrentFlatmap()
466
- map.setState(currentState.state)
467
- }
468
- })
469
- })
470
- }
471
- },
472
- /**
473
- * @vuese
474
- * Function to activate help mode tooltip by item index number
475
- */
476
- activateTooltipByIndex: function (index) {
477
- return (
478
- index === this.helpModeActiveItem
479
- && this.helpMode
480
- );
481
- },
482
- /**
483
- * @vuese
484
- * Function to check the last item of help mode
485
- */
486
- onHelpModeLastItem: function (isLastItem) {
487
- if (isLastItem) {
488
- this.$emit('help-mode-last-item', true);
489
- }
490
- },
491
- /**
492
- * @vuese
493
- * Function to emit event after a tooltip is shown.
494
- */
495
- onTooltipShown: function () {
496
- /**
497
- * This event is emitted after a tooltip in Flatmap is shown.
498
- */
499
- this.$emit('shown-tooltip');
500
- },
501
- /**
502
- * @vuese
503
- * Function to emit event after a tooltip on the map is shown.
504
- */
505
- onMapTooltipShown: function () {
506
- /**
507
- * This event is emitted after a tooltip on Flatmap's map is shown.
508
- */
509
- this.$emit('shown-map-tooltip');
510
- },
511
- },
512
- props: {
513
- /**
514
- * Initial species for the flatmap.
515
- * This value will be ignored if a valid state object is provided.
516
- */
517
- initial: {
518
- type: String,
519
- default: '',
520
- },
521
- /**
522
- * The minimum zoom level of the map.
523
- */
524
- minZoom: {
525
- type: Number,
526
- default: 4,
527
- },
528
- /**
529
- * The option to create map on component mounted.
530
- */
531
- renderAtMounted: {
532
- type: Boolean,
533
- default: false,
534
- },
535
- /**
536
- * The option to show tooltips for help mode.
537
- */
538
- helpMode: {
539
- type: Boolean,
540
- default: false,
541
- },
542
- /**
543
- * The active item index of help mode.
544
- */
545
- helpModeActiveItem: {
546
- type: Number,
547
- default: 0,
548
- },
549
- /**
550
- * The option to use helpModeDialog.
551
- * On default, `false`, clicking help will show all tooltips.
552
- * If `true`, clicking help will show the help-mode-dialog.
553
- */
554
- helpModeDialog: {
555
- type: Boolean,
556
- default: false,
557
- },
558
- /**
559
- * The last item of help mode.
560
- */
561
- helpModeLastItem: {
562
- type: Boolean,
563
- default: false,
564
- },
565
- /**
566
- * The option to display minimap at the top-right corner of the map.
567
- */
568
- displayMinimap: {
569
- type: Boolean,
570
- default: false,
571
- },
572
- /**
573
- * The option to show star in legend area.
574
- */
575
- showStarInLegend: {
576
- type: Boolean,
577
- default: false,
578
- },
579
- /**
580
- * Flag to determine rather open map UI should be
581
- * presented or not.
582
- */
583
- enableOpenMapUI: {
584
- type: Boolean,
585
- default: false,
586
- },
587
- /**
588
- * The data to show different map options.
589
- * Available at the bottom-left corner ("Open new map" tooltip).
590
- */
591
- openMapOptions: {
592
- type: Array,
593
- },
594
- /**
595
- * The available species data for different maps.
596
- * This data is used for multi flatmaps.
597
- */
598
- availableSpecies: {
599
- type: Object,
600
- /**
601
- * ```{
602
- 'Human Female': {
603
- taxo: 'NCBITaxon:9606',
604
- biologicalSex: 'PATO:0000383',
605
- iconClass: 'mapicon-icon_human',
606
- displayWarning: true,
607
- },
608
- 'Human Male': {
609
- taxo: 'NCBITaxon:9606',
610
- biologicalSex: 'PATO:0000384',
611
- iconClass: 'mapicon-icon_human',
612
- displayWarning: true,
613
- },
614
- Rat: {
615
- taxo: 'NCBITaxon:10114',
616
- iconClass: 'mapicon-icon_rat',
617
- displayLatestChanges: true,
618
- },
619
- Mouse: {
620
- taxo: 'NCBITaxon:10090',
621
- iconClass: 'mapicon-icon_mouse',
622
- displayWarning: true,
623
- },
624
- Pig: {
625
- taxo: 'NCBITaxon:9823',
626
- iconClass: 'mapicon-icon_pig',
627
- displayWarning: true,
628
- },
629
- Cat: {
630
- taxo: 'NCBITaxon:9685',
631
- iconClass: 'mapicon-icon_cat',
632
- displayWarning: true,
633
- },
634
- }```
635
- */
636
- default: function () {
637
- return {
638
- 'Human Female': {
639
- taxo: 'NCBITaxon:9606',
640
- biologicalSex: 'PATO:0000383',
641
- iconClass: 'mapicon-icon_human',
642
- displayWarning: true,
643
- },
644
- 'Human Male': {
645
- taxo: 'NCBITaxon:9606',
646
- biologicalSex: 'PATO:0000384',
647
- iconClass: 'mapicon-icon_human',
648
- displayWarning: true,
649
- },
650
- Rat: {
651
- taxo: 'NCBITaxon:10114',
652
- iconClass: 'mapicon-icon_rat',
653
- displayLatestChanges: true,
654
- },
655
- Mouse: {
656
- taxo: 'NCBITaxon:10090',
657
- iconClass: 'mapicon-icon_mouse',
658
- displayWarning: true,
659
- },
660
- Pig: {
661
- taxo: 'NCBITaxon:9823',
662
- iconClass: 'mapicon-icon_pig',
663
- displayWarning: true,
664
- },
665
- Cat: {
666
- taxo: 'NCBITaxon:9685',
667
- iconClass: 'mapicon-icon_cat',
668
- displayWarning: true,
669
- },
670
- }
671
- },
672
- },
673
- /**
674
- * State containing state of the flatmap.
675
- */
676
- state: {
677
- type: Object,
678
- default: undefined,
679
- },
680
- /**
681
- * Specify the endpoint of the flatmap server.
682
- */
683
- flatmapAPI: {
684
- type: String,
685
- default: 'https://mapcore-demo.org/current/flatmap/v3/',
686
- },
687
- /**
688
- * Specify the endpoint of the SPARC API.
689
- */
690
- sparcAPI: {
691
- type: String,
692
- default: 'https://api.sparc.science/',
693
- },
694
- /**
695
- * Flag to disable UIs on Map
696
- */
697
- disableUI: {
698
- type: Boolean,
699
- default: false,
700
- }
701
- },
702
- data: function () {
703
- return {
704
- activeSpecies: undefined,
705
- speciesList: {},
706
- requireInitialisation: true,
707
- }
708
- },
709
- watch: {
710
- state: {
711
- handler: function (state) {
712
- this.setState(state)
713
- },
714
- immediate: true,
715
- deep: true,
716
- },
717
- },
718
- }
719
- </script>
720
-
721
- <style lang="scss" scoped>
722
- .multi-container {
723
- height: 100%;
724
- width: 100%;
725
- }
726
-
727
- .species-display-text {
728
- width: 47px;
729
- height: 20px;
730
- color: rgb(48, 49, 51);
731
- font-size: 14px;
732
- font-weight: normal;
733
- line-height: 20px;
734
- left: 24px;
735
- top: 16px;
736
- position: absolute;
737
- }
738
-
739
- .select-box {
740
- width: 120px;
741
- border-radius: 4px;
742
- border: 1px solid rgb(144, 147, 153);
743
- background-color: var(--white);
744
- font-weight: 500;
745
- color: rgb(48, 49, 51);
746
- left: 16px;
747
- top: 44px;
748
- position: absolute;
749
- :deep(.el-input__inner) {
750
- color: rgb(48, 49, 51);
751
- padding-top: 0.25em;
752
- }
753
- :deep() {
754
- .el-input {
755
- .el-input__wrapper{
756
- &is-focus,
757
- &:focus {
758
- border: 1px solid $app-primary-color;
759
- }
760
- }
761
- }
762
- }
763
-
764
- .select-box-icon {
765
- display: inline-block;
766
- width: 24px;
767
- margin-right: 5px;
768
- text-align: center;
769
- }
770
- }
771
-
772
- .flatmap-dropdown {
773
- min-width: 160px !important;
774
- .el-select-dropdown__item {
775
- white-space: nowrap;
776
- text-align: left;
777
- &.selected {
778
- color: $app-primary-color;
779
- font-weight: normal;
780
- }
781
- }
782
- }
783
-
784
- .flatmap-popper {
785
- padding: 6px 4px;
786
- font-size: 12px;
787
- color: rgb(48, 49, 51);
788
- background-color: #f3ecf6;
789
- border: 1px solid $app-primary-color;
790
- white-space: nowrap;
791
- min-width: unset;
792
- &.right-popper {
793
- .popper__arrow {
794
- border-right-color: $app-primary-color !important;
795
- &:after {
796
- border-right-color: #f3ecf6 !important;
797
- }
798
- }
799
- }
800
- }
801
-
802
- :deep(.flatmap-marker-popup) {
803
- background-color: #f0f0f000 !important;
804
- box-shadow: none !important;
805
- }
806
- </style>
807
-
808
- <style lang="scss">
809
-
810
- .multi-container {
811
- --el-color-primary: #8300BF;
812
- }
813
-
814
- </style>
1
+ <template>
2
+ <div class="multi-container" ref="multiContainer">
3
+ <div style="position: absolute; z-index: 10" v-if="!disableUI">
4
+ <div class="species-display-text">Species</div>
5
+ <el-popover
6
+ content="Select a species"
7
+ placement="right"
8
+ trigger="manual"
9
+ popper-class="flatmap-popper flatmap-teleport-popper right-popper"
10
+ width="max-content"
11
+ :visible="activateTooltipByIndex(0)"
12
+ :teleported="false"
13
+ ref="selectPopover"
14
+ >
15
+ <template #reference>
16
+ <el-select
17
+ id="flatmap-select"
18
+ :teleported="false"
19
+ v-model="activeSpecies"
20
+ placeholder="Select"
21
+ class="select-box"
22
+ popper-class="flatmap-dropdown"
23
+ @change="setSpecies"
24
+ >
25
+ <el-option
26
+ v-for="(item, key) in speciesList"
27
+ :key="key"
28
+ :label="key"
29
+ :value="key"
30
+ >
31
+ <span class="select-box-icon">
32
+ <i :class="item.iconClass"></i>
33
+ </span>
34
+ {{ key }}
35
+ </el-option>
36
+ </el-select>
37
+ </template>
38
+
39
+ </el-popover>
40
+ </div>
41
+ <FlatmapVuer
42
+ v-for="(item, key) in speciesList"
43
+ :key="key"
44
+ v-show="activeSpecies == key"
45
+ :entry="item.taxo"
46
+ :uuid="item.uuid"
47
+ :biologicalSex="item.biologicalSex"
48
+ :displayWarning="item.displayWarning"
49
+ :displayLatestChanges="item.displayLatestChanges"
50
+ :isLegacy="item.isLegacy"
51
+ :ref="key"
52
+ :enableOpenMapUI="enableOpenMapUI"
53
+ :openMapOptions="openMapOptions"
54
+ :disableUI="disableUI"
55
+ @view-latest-map="viewLatestMap"
56
+ @resource-selected="resourceSelected"
57
+ @ready="FlatmapReady"
58
+ @pan-zoom-callback="panZoomCallback"
59
+ @open-map="
60
+ /**
61
+ * This event is emitted when the user chooses a different map option
62
+ * from ``openMapOptions`` props.
63
+ * @arg $event
64
+ */
65
+ $emit('open-map', $event)"
66
+ @pathway-selection-changed="onSelectionsDataChanged"
67
+ :minZoom="minZoom"
68
+ :helpMode="activeSpecies == key && helpMode"
69
+ :helpModeActiveItem="helpModeActiveItem"
70
+ :helpModeDialog="helpModeDialog"
71
+ :helpModeInitialIndex="-2"
72
+ @help-mode-last-item="onHelpModeLastItem"
73
+ @shown-tooltip="onTooltipShown"
74
+ @shown-map-tooltip="onMapTooltipShown"
75
+ :renderAtMounted="renderAtMounted"
76
+ :displayMinimap="displayMinimap"
77
+ :showStarInLegend="showStarInLegend"
78
+ style="height: 100%"
79
+ :flatmapAPI="flatmapAPI"
80
+ :sparcAPI="sparcAPI"
81
+ />
82
+ </div>
83
+ </template>
84
+
85
+ <script>
86
+ /* eslint-disable no-alert, no-console */
87
+ import { reactive } from 'vue'
88
+ import EventBus from './EventBus'
89
+ import FlatmapVuer from './FlatmapVuer.vue'
90
+ import * as flatmap from '@abi-software/flatmap-viewer'
91
+ import {
92
+ ElCol as Col,
93
+ ElOption as Option,
94
+ ElSelect as Select,
95
+ ElRow as Row,
96
+ ElPopover as Popover,
97
+ } from 'element-plus'
98
+
99
+ const TAXON_UUID = {
100
+ 'NCBITaxon:10114': '01fedbf9-d783-509c-a10c-827941ab13da',
101
+ 'NCBITaxon:9823': 'a336ac04-24db-561f-a25f-1c994fe17410',
102
+ 'NCBITaxon:9606': '42ed6323-f645-5fbe-bada-9581819cf689',
103
+ 'NCBITaxon:10090': '25285fab-48a0-5620-a6a0-f9a0374837d5',
104
+ 'NCBITaxon:9685': '73060497-46a6-52bf-b975-cac511c127cb',
105
+ }
106
+
107
+ /**
108
+ * A vue component to show a flatmap from the list of multiple flatmap data.
109
+ */
110
+ export default {
111
+ name: 'MultiFlatmapVuer',
112
+ components: {
113
+ Col,
114
+ Row,
115
+ Option,
116
+ Select,
117
+ Popover,
118
+ FlatmapVuer,
119
+ },
120
+ beforeMount() {
121
+ //List for resolving the promise in initialise
122
+ //if initialise is called multiple times
123
+ this._resolveList = []
124
+ this._initialised = false
125
+ },
126
+ mounted: function () {
127
+ this.initialise()
128
+ EventBus.on('onActionClick', (action) => {
129
+ this.resourceSelected(action)
130
+ })
131
+ EventBus.on('open-pubmed-url', (url) => {
132
+ /**
133
+ * This event is emitted when the user clicks
134
+ * on "Open publications in pubmed" button
135
+ * from provenance popup.
136
+ * @arg url
137
+ */
138
+ this.$emit('open-pubmed-url', url);
139
+ });
140
+ },
141
+ methods: {
142
+ /**
143
+ * @vuese
144
+ * Function to initialise the component when mounted.
145
+ * It returns a promise.
146
+ */
147
+ initialise: function () {
148
+ return new Promise((resolve) => {
149
+ if (this.requireInitialisation) {
150
+ //It has not been initialised yet
151
+ this.requireInitialisation = false
152
+ fetch(this.flatmapAPI)
153
+ .then((response) => response.json())
154
+ .then((data) => {
155
+ //Check each key in the provided availableSpecies against the one
156
+ Object.keys(this.availableSpecies).forEach((key) => {
157
+ // FIrst look through the uuid
158
+ const uuid = this.availableSpecies[key].uuid
159
+ if (uuid && data.map((e) => e.uuid).indexOf(uuid) > 0) {
160
+ this.speciesList[key] = reactive(this.availableSpecies[key])
161
+ } else {
162
+ for (let i = 0; i < data.length; i++) {
163
+ if (this.availableSpecies[key].taxo === data[i].taxon) {
164
+ if (this.availableSpecies[key].biologicalSex) {
165
+ if (
166
+ data[i].biologicalSex &&
167
+ data[i].biologicalSex ===
168
+ this.availableSpecies[key].biologicalSex
169
+ ) {
170
+ this.speciesList[key] = reactive(this.availableSpecies[key])
171
+ break
172
+ }
173
+ } else {
174
+ this.speciesList[key] = reactive(this.availableSpecies[key])
175
+ break
176
+ }
177
+ }
178
+ }
179
+ }
180
+ })
181
+ //Use the state species if it does not have any other species information
182
+ let species = this.initial
183
+ if (this.state) {
184
+ const mapState = this.state.state
185
+ if (
186
+ (!mapState || (!mapState.uuid && !mapState.entry)) &&
187
+ this.state.species
188
+ )
189
+ species = this.state.species
190
+ else species = undefined
191
+ }
192
+ if (species) {
193
+ //No state resuming, set the current flatmap to {this.initial}
194
+ if (species && this.speciesList[species] !== undefined) {
195
+ this.activeSpecies = species
196
+ } else {
197
+ this.activeSpecies = Object.keys(this.speciesList)[0]
198
+ }
199
+ this.setSpecies(
200
+ this.activeSpecies,
201
+ this.state ? this.state.state : undefined,
202
+ 5
203
+ )
204
+ }
205
+ this._initialised = true
206
+ resolve()
207
+ //Resolve all other promises resolve in the list
208
+ this._resolveList.forEach((other) => {
209
+ other()
210
+ })
211
+ })
212
+ } else if (this._initialised) {
213
+ //resolve as it has been initialised
214
+ resolve()
215
+ } else {
216
+ //resolve when the async initialisation is finished
217
+ this._resolveList.push(resolve)
218
+ }
219
+ })
220
+ },
221
+ /**
222
+ * @vuese
223
+ * Function to emit ``resource-selected`` event with provided ``resource``.
224
+ * @arg action
225
+ */
226
+ resourceSelected: function (action) {
227
+ /**
228
+ * This event is emitted by ``resourceSelected`` method.
229
+ */
230
+ this.$emit('resource-selected', action)
231
+ },
232
+ /**
233
+ * @vuese
234
+ * Function to emit ``ready`` event after the flatmap is loaded.
235
+ * @arg component
236
+ */
237
+ FlatmapReady: function (component) {
238
+ /**
239
+ * This event is emitted by ``FlatmapReady`` method after the flatmap is loaded.
240
+ * @arg component
241
+ */
242
+ this.$emit('ready', component)
243
+ },
244
+ /**
245
+ * @vuese
246
+ * Function to get the current active map.
247
+ */
248
+ getCurrentFlatmap: function () {
249
+ return this.$refs[this.activeSpecies][0]
250
+ },
251
+ /**
252
+ * @vuese
253
+ * Function to emit ``pan-zoom-callback`` event
254
+ * from the event emitted in ``callback`` function from ``MapManager.loadMap()``.
255
+ * @arg payload
256
+ */
257
+ panZoomCallback: function (payload) {
258
+ /**
259
+ * The event emitted by ``panZoomCallback`` method.
260
+ * @arg payload
261
+ */
262
+ this.$emit('pan-zoom-callback', payload)
263
+ },
264
+ onSelectionsDataChanged: function (data) {
265
+ this.$emit('pathway-selection-changed', data);
266
+ },
267
+ /**
268
+ * @vuese
269
+ * Function to show popup on map.
270
+ * @arg featureId,
271
+ * @arg node,
272
+ * @arg options
273
+ */
274
+ showPopup: function (featureId, node, options) {
275
+ let map = this.getCurrentFlatmap()
276
+ map.showPopup(featureId, node, options)
277
+ },
278
+ /**
279
+ * @vuese
280
+ * Function to show marker popup.
281
+ * @arg featureId,
282
+ * @arg node,
283
+ * @arg options
284
+ */
285
+ showMarkerPopup: function (featureId, node, options) {
286
+ let map = this.getCurrentFlatmap()
287
+ map.showMarkerPopup(featureId, node, options)
288
+ },
289
+ /**
290
+ * @vuese
291
+ * Function to set species.
292
+ * This function is called on the first load and
293
+ * when user changes the species.
294
+ * @arg species,
295
+ * @arg state,
296
+ * @arg numberOfRetry
297
+ */
298
+ setSpecies: function (species, state, numberOfRetry) {
299
+ if (this.$refs && species in this.$refs) {
300
+ this.activeSpecies = species
301
+ this.$refs[this.activeSpecies][0].createFlatmap(state)
302
+ /**
303
+ * This event is emitted by ``setSpecies`` method.
304
+ * Emitted on first load and when user changes species.
305
+ * @arg activeSpecies
306
+ */
307
+ this.$emit('flatmapChanged', this.activeSpecies)
308
+ } else if (numberOfRetry) {
309
+ const retry = numberOfRetry - 1
310
+ if (retry >= 0) {
311
+ this.$nextTick(() => {
312
+ this.setSpecies(species, state, retry)
313
+ })
314
+ }
315
+ }
316
+ },
317
+ /**
318
+ * @vuese
319
+ * Function to switch to the latest existing map from
320
+ * a legacy map of the same species.
321
+ * @arg state
322
+ *
323
+ * @private
324
+ */
325
+ viewLatestMap: function (state) {
326
+ const keys = Object.keys(this.speciesList)
327
+ for (let i = 0; i < keys.length; i++) {
328
+ const species = this.speciesList[keys[i]]
329
+ if (
330
+ !species.isLegacy &&
331
+ species.taxo === state.entry &&
332
+ species.biologicalSex === state.biologicalSex
333
+ ) {
334
+ this.setSpecies(keys[i], state, 0)
335
+ return
336
+ }
337
+ }
338
+ },
339
+ /**
340
+ * @vuese
341
+ * Create a legacy entry with the provided information
342
+ * @arg state,
343
+ * @arg taxo,
344
+ * @arg uuid
345
+ *
346
+ * @private
347
+ */
348
+ createLegacyEntry: function (state, taxo, uuid) {
349
+ if (uuid && taxo) {
350
+ let name = 'Legacy'
351
+ if (state.species) {
352
+ if (state.species.slice(0, 6) === 'Legacy') name = state.species
353
+ else name = name + ` ${state.species}`
354
+ }
355
+ this.speciesList[name] = reactive({
356
+ taxo: taxo,
357
+ isLegacy: true,
358
+ displayWarning: true,
359
+ })
360
+ return {
361
+ species: name,
362
+ state: {
363
+ entry: taxo,
364
+ uuid: uuid,
365
+ viewport: state.state.viewport,
366
+ searchTerm: state.state.searchTerm,
367
+ },
368
+ }
369
+ }
370
+ },
371
+ /**
372
+ * @vuese
373
+ * Function used to translate the legacy map state to one that can be used in current
374
+ * flatmap if required. If it is a legacy, an Select entry will be added
375
+ * @arg state
376
+ *
377
+ * @private
378
+ */
379
+ updateState: function (state) {
380
+ return new Promise((resolve) => {
381
+ if (state && state.state) {
382
+ const mapState = state.state
383
+ //uuid is not in the state, this is a legacy map
384
+ if (!mapState.uuid) {
385
+ if (mapState.entry) {
386
+ const uuid =
387
+ mapState.entry in TAXON_UUID
388
+ ? TAXON_UUID[mapState.entry]
389
+ : undefined
390
+ const newState = this.createLegacyEntry(
391
+ state,
392
+ mapState.entry,
393
+ uuid
394
+ )
395
+ resolve(newState ? newState : state)
396
+ }
397
+ } else if (mapState.entry) {
398
+ //uuid is in the state but should be checked if it is the latest map
399
+ //for that taxon
400
+ return new Promise(() => {
401
+ const mapManager = new flatmap.MapManager(this.flatmapAPI)
402
+ //mapManager.findMap_ is an async function so we need to wrap this with a promise
403
+ const identifier = { taxon: mapState.entry }
404
+ if (mapState.biologicalSex)
405
+ identifier['biologicalSex'] = mapState.biologicalSex
406
+ mapManager
407
+ .findMap_(identifier)
408
+ .then((map) => {
409
+ if (map.uuid !== mapState.uuid) {
410
+ return this.createLegacyEntry(
411
+ state,
412
+ mapState.entry,
413
+ mapState.uuid
414
+ )
415
+ }
416
+ })
417
+ .then((newState) => {
418
+ resolve(newState ? newState : state)
419
+ })
420
+ .catch(() => {
421
+ resolve(state)
422
+ })
423
+ })
424
+ }
425
+ //Create a new state and add the legacy map to the select
426
+ }
427
+ resolve(state)
428
+ })
429
+ },
430
+ /**
431
+ * @vuese
432
+ * Function used for getting the current states of the scene. This exported states
433
+ * can be imported using the importStates method.
434
+ *
435
+ * @public
436
+ */
437
+ getState: function () {
438
+ let state = {
439
+ species: this.activeSpecies,
440
+ state: undefined,
441
+ }
442
+ let map = this.getCurrentFlatmap()
443
+ state.state = map.getState()
444
+ return state
445
+ },
446
+ /**
447
+ * @vuese
448
+ * Function used for importing the states of the scene. This exported states
449
+ * can be imported using the read states method.
450
+ * @arg state
451
+ *
452
+ * @public
453
+ */
454
+ setState: function (state) {
455
+ if (state) {
456
+ //Update state if required
457
+ this.updateState(state).then((currentState) => {
458
+ this.initialise().then(() => {
459
+ if (
460
+ currentState.species &&
461
+ currentState.species !== this.activeSpecies
462
+ ) {
463
+ this.setSpecies(currentState.species, currentState.state, 5)
464
+ } else if (currentState.state) {
465
+ let map = this.getCurrentFlatmap()
466
+ map.setState(currentState.state)
467
+ }
468
+ })
469
+ })
470
+ }
471
+ },
472
+ /**
473
+ * @vuese
474
+ * Function to activate help mode tooltip by item index number
475
+ */
476
+ activateTooltipByIndex: function (index) {
477
+ return (
478
+ index === this.helpModeActiveItem
479
+ && this.helpMode
480
+ );
481
+ },
482
+ /**
483
+ * @vuese
484
+ * Function to check the last item of help mode
485
+ */
486
+ onHelpModeLastItem: function (isLastItem) {
487
+ if (isLastItem) {
488
+ this.$emit('help-mode-last-item', true);
489
+ }
490
+ },
491
+ /**
492
+ * @vuese
493
+ * Function to emit event after a tooltip is shown.
494
+ */
495
+ onTooltipShown: function () {
496
+ /**
497
+ * This event is emitted after a tooltip in Flatmap is shown.
498
+ */
499
+ this.$emit('shown-tooltip');
500
+ },
501
+ /**
502
+ * @vuese
503
+ * Function to emit event after a tooltip on the map is shown.
504
+ */
505
+ onMapTooltipShown: function () {
506
+ /**
507
+ * This event is emitted after a tooltip on Flatmap's map is shown.
508
+ */
509
+ this.$emit('shown-map-tooltip');
510
+ },
511
+ },
512
+ props: {
513
+ /**
514
+ * Initial species for the flatmap.
515
+ * This value will be ignored if a valid state object is provided.
516
+ */
517
+ initial: {
518
+ type: String,
519
+ default: '',
520
+ },
521
+ /**
522
+ * The minimum zoom level of the map.
523
+ */
524
+ minZoom: {
525
+ type: Number,
526
+ default: 4,
527
+ },
528
+ /**
529
+ * The option to create map on component mounted.
530
+ */
531
+ renderAtMounted: {
532
+ type: Boolean,
533
+ default: false,
534
+ },
535
+ /**
536
+ * The option to show tooltips for help mode.
537
+ */
538
+ helpMode: {
539
+ type: Boolean,
540
+ default: false,
541
+ },
542
+ /**
543
+ * The active item index of help mode.
544
+ */
545
+ helpModeActiveItem: {
546
+ type: Number,
547
+ default: 0,
548
+ },
549
+ /**
550
+ * The option to use helpModeDialog.
551
+ * On default, `false`, clicking help will show all tooltips.
552
+ * If `true`, clicking help will show the help-mode-dialog.
553
+ */
554
+ helpModeDialog: {
555
+ type: Boolean,
556
+ default: false,
557
+ },
558
+ /**
559
+ * The last item of help mode.
560
+ */
561
+ helpModeLastItem: {
562
+ type: Boolean,
563
+ default: false,
564
+ },
565
+ /**
566
+ * The option to display minimap at the top-right corner of the map.
567
+ */
568
+ displayMinimap: {
569
+ type: Boolean,
570
+ default: false,
571
+ },
572
+ /**
573
+ * The option to show star in legend area.
574
+ */
575
+ showStarInLegend: {
576
+ type: Boolean,
577
+ default: false,
578
+ },
579
+ /**
580
+ * Flag to determine rather open map UI should be
581
+ * presented or not.
582
+ */
583
+ enableOpenMapUI: {
584
+ type: Boolean,
585
+ default: false,
586
+ },
587
+ /**
588
+ * The data to show different map options.
589
+ * Available at the bottom-left corner ("Open new map" tooltip).
590
+ */
591
+ openMapOptions: {
592
+ type: Array,
593
+ },
594
+ /**
595
+ * The available species data for different maps.
596
+ * This data is used for multi flatmaps.
597
+ */
598
+ availableSpecies: {
599
+ type: Object,
600
+ /**
601
+ * ```{
602
+ 'Human Female': {
603
+ taxo: 'NCBITaxon:9606',
604
+ biologicalSex: 'PATO:0000383',
605
+ iconClass: 'mapicon-icon_human',
606
+ displayWarning: true,
607
+ },
608
+ 'Human Male': {
609
+ taxo: 'NCBITaxon:9606',
610
+ biologicalSex: 'PATO:0000384',
611
+ iconClass: 'mapicon-icon_human',
612
+ displayWarning: true,
613
+ },
614
+ Rat: {
615
+ taxo: 'NCBITaxon:10114',
616
+ iconClass: 'mapicon-icon_rat',
617
+ displayLatestChanges: true,
618
+ },
619
+ Mouse: {
620
+ taxo: 'NCBITaxon:10090',
621
+ iconClass: 'mapicon-icon_mouse',
622
+ displayWarning: true,
623
+ },
624
+ Pig: {
625
+ taxo: 'NCBITaxon:9823',
626
+ iconClass: 'mapicon-icon_pig',
627
+ displayWarning: true,
628
+ },
629
+ Cat: {
630
+ taxo: 'NCBITaxon:9685',
631
+ iconClass: 'mapicon-icon_cat',
632
+ displayWarning: true,
633
+ },
634
+ }```
635
+ */
636
+ default: function () {
637
+ return {
638
+ 'Human Female': {
639
+ taxo: 'NCBITaxon:9606',
640
+ biologicalSex: 'PATO:0000383',
641
+ iconClass: 'mapicon-icon_human',
642
+ displayWarning: true,
643
+ },
644
+ 'Human Male': {
645
+ taxo: 'NCBITaxon:9606',
646
+ biologicalSex: 'PATO:0000384',
647
+ iconClass: 'mapicon-icon_human',
648
+ displayWarning: true,
649
+ },
650
+ Rat: {
651
+ taxo: 'NCBITaxon:10114',
652
+ iconClass: 'mapicon-icon_rat',
653
+ displayLatestChanges: true,
654
+ },
655
+ Mouse: {
656
+ taxo: 'NCBITaxon:10090',
657
+ iconClass: 'mapicon-icon_mouse',
658
+ displayWarning: true,
659
+ },
660
+ Pig: {
661
+ taxo: 'NCBITaxon:9823',
662
+ iconClass: 'mapicon-icon_pig',
663
+ displayWarning: true,
664
+ },
665
+ Cat: {
666
+ taxo: 'NCBITaxon:9685',
667
+ iconClass: 'mapicon-icon_cat',
668
+ displayWarning: true,
669
+ },
670
+ }
671
+ },
672
+ },
673
+ /**
674
+ * State containing state of the flatmap.
675
+ */
676
+ state: {
677
+ type: Object,
678
+ default: undefined,
679
+ },
680
+ /**
681
+ * Specify the endpoint of the flatmap server.
682
+ */
683
+ flatmapAPI: {
684
+ type: String,
685
+ default: 'https://mapcore-demo.org/current/flatmap/v3/',
686
+ },
687
+ /**
688
+ * Specify the endpoint of the SPARC API.
689
+ */
690
+ sparcAPI: {
691
+ type: String,
692
+ default: 'https://api.sparc.science/',
693
+ },
694
+ /**
695
+ * Flag to disable UIs on Map
696
+ */
697
+ disableUI: {
698
+ type: Boolean,
699
+ default: false,
700
+ }
701
+ },
702
+ data: function () {
703
+ return {
704
+ activeSpecies: undefined,
705
+ speciesList: {},
706
+ requireInitialisation: true,
707
+ }
708
+ },
709
+ watch: {
710
+ state: {
711
+ handler: function (state) {
712
+ this.setState(state)
713
+ },
714
+ immediate: true,
715
+ deep: true,
716
+ },
717
+ },
718
+ }
719
+ </script>
720
+
721
+ <style lang="scss" scoped>
722
+ .multi-container {
723
+ height: 100%;
724
+ width: 100%;
725
+ }
726
+
727
+ .species-display-text {
728
+ width: 47px;
729
+ height: 20px;
730
+ color: rgb(48, 49, 51);
731
+ font-size: 14px;
732
+ font-weight: normal;
733
+ line-height: 20px;
734
+ left: 24px;
735
+ top: 16px;
736
+ position: absolute;
737
+ }
738
+
739
+ .select-box {
740
+ width: 120px;
741
+ border-radius: 4px;
742
+ border: 1px solid rgb(144, 147, 153);
743
+ background-color: var(--white);
744
+ font-weight: 500;
745
+ color: rgb(48, 49, 51);
746
+ left: 16px;
747
+ top: 44px;
748
+ position: absolute;
749
+ :deep(.el-input__inner) {
750
+ color: rgb(48, 49, 51);
751
+ padding-top: 0.25em;
752
+ }
753
+ :deep() {
754
+ .el-input {
755
+ .el-input__wrapper{
756
+ &is-focus,
757
+ &:focus {
758
+ border: 1px solid $app-primary-color;
759
+ }
760
+ }
761
+ }
762
+ }
763
+
764
+ .select-box-icon {
765
+ display: inline-block;
766
+ width: 24px;
767
+ margin-right: 5px;
768
+ text-align: center;
769
+ }
770
+ }
771
+
772
+ .flatmap-dropdown {
773
+ min-width: 160px !important;
774
+ .el-select-dropdown__item {
775
+ white-space: nowrap;
776
+ text-align: left;
777
+ &.selected {
778
+ color: $app-primary-color;
779
+ font-weight: normal;
780
+ }
781
+ }
782
+ }
783
+
784
+ .flatmap-popper {
785
+ padding: 6px 4px;
786
+ font-size: 12px;
787
+ color: rgb(48, 49, 51);
788
+ background-color: #f3ecf6;
789
+ border: 1px solid $app-primary-color;
790
+ white-space: nowrap;
791
+ min-width: unset;
792
+ &.right-popper {
793
+ .popper__arrow {
794
+ border-right-color: $app-primary-color !important;
795
+ &:after {
796
+ border-right-color: #f3ecf6 !important;
797
+ }
798
+ }
799
+ }
800
+ }
801
+
802
+ :deep(.flatmap-marker-popup) {
803
+ background-color: #f0f0f000 !important;
804
+ box-shadow: none !important;
805
+ }
806
+ </style>
807
+
808
+ <style lang="scss">
809
+
810
+ .multi-container {
811
+ --el-color-primary: #8300BF;
812
+ }
813
+
814
+ </style>