@abi-software/flatmapvuer 0.5.10 → 0.6.0-vue3-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +105 -105
  3. package/babel.config.js +0 -14
  4. package/dist/favicon.ico +0 -0
  5. package/dist/flatmapvuer.js +69542 -0
  6. package/dist/flatmapvuer.umd.cjs +1021 -0
  7. package/dist/index.html +17 -0
  8. package/dist/style.css +1 -0
  9. package/package.json +87 -79
  10. package/public/index.html +17 -17
  11. package/src/App.vue +303 -228
  12. package/src/assets/_variables.scss +43 -43
  13. package/src/assets/styles.scss +6 -7
  14. package/src/components/AnnotationTool.vue +443 -403
  15. package/src/components/EventBus.js +3 -3
  16. package/src/components/ExternalResourceCard.vue +108 -99
  17. package/src/components/FlatmapVuer.vue +2117 -2070
  18. package/src/components/MultiFlatmapVuer.vue +603 -535
  19. package/src/components/ProvenancePopup.vue +496 -422
  20. package/src/components/SelectionsGroup.vue +258 -249
  21. package/src/components/Tooltip.vue +50 -52
  22. package/src/components/TreeControls.vue +234 -231
  23. package/src/components/index.js +6 -9
  24. package/src/components/legends/DynamicLegends.vue +106 -112
  25. package/src/components/legends/SvgLegends.vue +112 -67
  26. package/src/components.d.ts +46 -0
  27. package/src/icons/flatmap-marker.js +1 -1
  28. package/src/icons/fonts/mapicon-species.eot +0 -0
  29. package/src/icons/fonts/mapicon-species.svg +14 -14
  30. package/src/icons/fonts/mapicon-species.ttf +0 -0
  31. package/src/icons/fonts/mapicon-species.woff +0 -0
  32. package/src/icons/mapicon-species-style.css +42 -42
  33. package/src/icons/yellowstar.js +5 -5
  34. package/src/legends/legend.svg +25 -25
  35. package/src/main.js +4 -8
  36. package/src/services/flatmapQueries.js +451 -415
  37. package/vite.config.js +76 -0
  38. package/vue.config.js +45 -31
  39. package/CHANGELOG.md +0 -402
  40. package/package-lock.json +0 -18473
  41. package/src/nerve-map.js +0 -99
@@ -1,535 +1,603 @@
1
- <template>
2
- <div class="multi-container" ref="multiContainer">
3
- <div style="position:absolute;z-index:10;">
4
- <div class="species-display-text">
5
- Species
6
- </div>
7
- <el-popover content="Select a species" placement="right"
8
- :appendToBody=false trigger="manual" popper-class="flatmap-popper right-popper" v-model="helpMode" ref="selectPopover">
9
- </el-popover>
10
- <el-select
11
- id="flatmap-select"
12
- :popper-append-to-body="appendToBody"
13
- v-model="activeSpecies"
14
- placeholder="Select"
15
- class="select-box"
16
- popper-class="flatmap_dropdown"
17
- @change="setSpecies"
18
- v-popover:selectPopover
19
- >
20
- <el-option v-for="(item, key) in speciesList" :key="key" :label="key" :value="key">
21
- <el-row>
22
- <el-col :span="8"><i :class="item.iconClass"></i></el-col>
23
- <el-col :span="12">{{ key }}</el-col>
24
- </el-row>
25
- </el-option>
26
- </el-select>
27
- </div>
28
- <FlatmapVuer
29
- v-for="(item, key) in speciesList"
30
- :key="key"
31
- :showLayer="showLayer"
32
- v-show="activeSpecies==key"
33
- :entry="item.taxo"
34
- :uuid="item.uuid"
35
- :biologicalSex="item.biologicalSex"
36
- :displayWarning="item.displayWarning"
37
- :displayLatestChanges="item.displayLatestChanges"
38
- :isLegacy="item.isLegacy"
39
- :ref="key"
40
- :enableOpenMapUI="enableOpenMapUI"
41
- :openMapOptions="openMapOptions"
42
- @view-latest-map="viewLatestMap"
43
- @resource-selected="FlatmapSelected"
44
- @ready="FlatmapReady"
45
- @pan-zoom-callback="panZoomCallback"
46
- @open-map="$emit('open-map', $event)"
47
- :featureInfo="featureInfo"
48
- :minZoom="minZoom"
49
- :pathControls="pathControls"
50
- :searchable="searchable"
51
- :layerControl="layerControl"
52
- :helpMode="helpMode"
53
- :renderAtMounted="renderAtMounted"
54
- :displayMinimap="displayMinimap"
55
- :showStarInLegend="showStarInLegend"
56
- style="height:100%"
57
- :flatmapAPI="flatmapAPI"
58
- :sparcAPI="sparcAPI"
59
- />
60
- </div>
61
- </template>
62
-
63
-
64
- <script>
65
- /* eslint-disable no-alert, no-console */
66
- import EventBus from './EventBus'
67
- import Vue from "vue";
68
- import FlatmapVuer from "./FlatmapVuer.vue";
69
- import { Col, Option, Select, Row, Popover } from "element-ui";
70
- import lang from "element-ui/lib/locale/lang/en";
71
- import locale from "element-ui/lib/locale";
72
- locale.use(lang);
73
- Vue.use(Col);
74
- Vue.use(Row);
75
- Vue.use(Option);
76
- Vue.use(Select);
77
- Vue.use(Popover)
78
-
79
- const TAXON_UUID = {
80
- "NCBITaxon:10114": "01fedbf9-d783-509c-a10c-827941ab13da",
81
- "NCBITaxon:9823": "a336ac04-24db-561f-a25f-1c994fe17410",
82
- "NCBITaxon:9606": "42ed6323-f645-5fbe-bada-9581819cf689",
83
- "NCBITaxon:10090": "25285fab-48a0-5620-a6a0-f9a0374837d5",
84
- "NCBITaxon:9685": "73060497-46a6-52bf-b975-cac511c127cb"
85
- }
86
-
87
- export default {
88
- name: "MultiFlatmapVuer",
89
- components: {
90
- FlatmapVuer
91
- },
92
- beforeMount() {
93
- //List for resolving the promise in initialise
94
- //if initialise is called multiple times
95
- this._resolveList = [];
96
- this._initialised = false;
97
- },
98
- mounted: function() {
99
- this.initialise();
100
- EventBus.$on('onActionClick', (action) =>{
101
- this.FlatmapSelected(action)
102
- })
103
- },
104
- methods: {
105
- initialise: function() {
106
- return new Promise(resolve => {
107
- if (this.requireInitialisation) {
108
- //It has not been initialised yet
109
- this.requireInitialisation = false;
110
- fetch(this.flatmapAPI)
111
- .then(response => response.json())
112
- .then(data => {
113
- //Check each key in the provided availableSpecies against the one
114
- Object.keys(this.availableSpecies).forEach(key => {
115
- // FIrst look through the uuid
116
- const uuid = this.availableSpecies[key].uuid;
117
- if (uuid && data.map(e => e.uuid).indexOf(uuid) > 0) {
118
- this.$set(this.speciesList, key, this.availableSpecies[key]);
119
- } else {
120
- for (let i = 0; i < data.length; i++) {
121
- if (this.availableSpecies[key].taxo === data[i].taxon) {
122
- if (this.availableSpecies[key].biologicalSex) {
123
- if (data[i].biologicalSex &&
124
- data[i].biologicalSex === this.availableSpecies[key].biologicalSex) {
125
- this.$set(this.speciesList, key, this.availableSpecies[key]);
126
- break;
127
- }
128
- } else {
129
- this.$set(this.speciesList, key, this.availableSpecies[key]);
130
- break;
131
- }
132
- }
133
- }
134
- }
135
- });
136
- //Use the state species if it does not have any other species information
137
- let species = this.initial;
138
- if (this.state) {
139
- const mapState = this.state.state;
140
- if ((!mapState || ( !mapState.uuid && !mapState.entry )) && this.state.species)
141
- species = this.state.species;
142
- else
143
- species = undefined;
144
- }
145
- if (species) {
146
- //No state resuming, set the current flatmap to {this.initial}
147
- if (species && this.speciesList[species] !== undefined) {
148
- this.activeSpecies = species;
149
- } else {
150
- this.activeSpecies = Object.keys(this.speciesList)[0];
151
- }
152
- this.setSpecies(this.activeSpecies, this.state ? this.state.state : undefined, 5);
153
- }
154
- this._initialised = true;
155
- resolve();
156
- //Resolve all other promises resolve in the list
157
- this._resolveList.forEach(other => { other(); });
158
- });
159
- } else if (this._initialised) {
160
- //resolve as it has been initialised
161
- resolve();
162
- } else {
163
- //resolve when the async initialisation is finished
164
- this._resolveList.push(resolve);
165
- }
166
- })
167
- },
168
- FlatmapSelected: function(resource) {
169
- this.$emit("resource-selected", resource);
170
- },
171
- FlatmapReady: function(component) {
172
- this.$emit("ready", component);
173
- },
174
- getCoordinatesOfLastClick: function() {
175
- const flatmap = this.$refs[this.activeSpecies];
176
- if (flatmap && flatmap[0]) {
177
- return flatmap[0].getCoordinatesOfLastClick();
178
- }
179
- return undefined;
180
- },
181
- getCurrentFlatmap: function() {
182
- return this.$refs[this.activeSpecies][0];
183
- },
184
- panZoomCallback: function(payload) {
185
- this.$emit("pan-zoom-callback", payload);
186
- },
187
- showPopup: function(featureId, node, options) {
188
- let map = this.getCurrentFlatmap();
189
- map.showPopup(featureId, node, options);
190
- },
191
- showMarkerPopup: function(featureId, node, options) {
192
- let map = this.getCurrentFlatmap();
193
- map.showMarkerPopup(featureId, node, options);
194
- },
195
- setSpecies: function(species, state, numberOfRetry) {
196
- if (this.$refs && species in this.$refs) {
197
- this.activeSpecies = species;
198
- this.$refs[this.activeSpecies][0].createFlatmap(state);
199
- this.$emit('flatmapChanged', this.activeSpecies);
200
- } else if (numberOfRetry) {
201
- const retry = numberOfRetry - 1;
202
- if (retry >= 0) {
203
- Vue.nextTick(() => {
204
- this.setSpecies(species, state, retry);
205
- });
206
- }
207
- }
208
- },
209
- /**
210
- * Function to switch to the latest existing map from
211
- * a legacy map of the same species.
212
- *
213
- * @private
214
- */
215
- viewLatestMap: function(state) {
216
- const keys = Object.keys(this.speciesList);
217
- for (let i = 0; i < keys.length; i++) {
218
- const species = this.speciesList[keys[i]];
219
- if (!species.isLegacy &&
220
- (species.taxo === state.entry) &&
221
- (species.biologicalSex === state.biologicalSex)) {
222
- this.setSpecies(keys[i], state, 0);
223
- return;
224
- }
225
- }
226
- },
227
- /**
228
- * Create a legacy entry with the provided information
229
- *
230
- * @private
231
- */
232
- createLegacyEntry: function(state, taxo, uuid) {
233
- if (uuid && taxo) {
234
- let name = "Legacy";
235
- if (state.species) {
236
- if (state.species.slice(0, 6) === "Legacy")
237
- name = state.species;
238
- else
239
- name = name + ` ${state.species}`;
240
- }
241
- this.$set(
242
- this.speciesList,
243
- name,
244
- {
245
- taxo: taxo,
246
- isLegacy: true,
247
- displayWarning: true
248
- }
249
- );
250
- return {
251
- species: name,
252
- state: {
253
- entry: taxo,
254
- uuid: uuid,
255
- viewport: state.state.viewport,
256
- searchTerm: state.state.searchTerm
257
- },
258
- }
259
- }
260
- },
261
- /**
262
- * Function used to translate the legacy map state to one that can be used in current
263
- * flatmap if required. If it is a legacy, an Select entry will be added
264
- *
265
- * @private
266
- */
267
- updateState: function(state) {
268
- return new Promise((resolve) => {
269
- if (state && state.state) {
270
- const mapState = state.state;
271
- //uuid is not in the state, this is a legacy map
272
- if (!mapState.uuid) {
273
- if (mapState.entry) {
274
- const uuid = mapState.entry in TAXON_UUID ? TAXON_UUID[mapState.entry] : undefined;
275
- const newState = this.createLegacyEntry(state, mapState.entry, uuid);
276
- resolve(newState ? newState : state);
277
- }
278
- } else if (mapState.entry) {
279
- //uuid is in the state but should be checked if it is the latest map
280
- //for that taxon
281
- return new Promise(() => {
282
- const mapManager = new (require("@abi-software/flatmap-viewer")).MapManager(this.flatmapAPI);
283
- //mapManager.findMap_ is an async function so we need to wrap this with a promise
284
- const identifier = { taxon: mapState.entry };
285
- if (mapState.biologicalSex)
286
- identifier['biologicalSex'] = mapState.biologicalSex;
287
- mapManager.findMap_(identifier).then(map => {
288
- if (map.uuid !== mapState.uuid) {
289
- return this.createLegacyEntry(state, mapState.entry, mapState.uuid);
290
- }
291
- }).then(newState => {
292
- resolve(newState ? newState : state);
293
- })
294
- .catch(() => {
295
- resolve(state);
296
- });
297
- });
298
- }
299
- //Create a new state and add the legacy map to the select
300
- }
301
- resolve(state);
302
- });
303
- },
304
- /**
305
- * Function used for getting the current states of the scene. This exported states
306
- * can be imported using the importStates method.
307
- *
308
- * @public
309
- */
310
- getState: function() {
311
- let state = {
312
- species: this.activeSpecies,
313
- state: undefined,
314
- };
315
- let map = this.getCurrentFlatmap();
316
- state.state = map.getState();
317
- return state;
318
- },
319
- /**
320
- * Function used for importing the states of the scene. This exported states
321
- * can be imported using the read states method.
322
- *
323
- * @public
324
- */
325
- setState: function(state) {
326
- if (state) {
327
- //Update state if required
328
- this.updateState(state).then(currentState => {
329
- this.initialise().then(() => {
330
- if (currentState.species && (currentState.species !== this.activeSpecies)) {
331
- this.setSpecies(currentState.species, currentState.state, 5);
332
- } else if (currentState.state) {
333
- let map = this.getCurrentFlatmap();
334
- map.setState(currentState.state);
335
- }
336
- });
337
- });
338
- }
339
- },
340
- resourceSelected: function(action) {
341
- this.$emit("resource-selected", action);
342
- },
343
- },
344
- props: {
345
- showLayer: {
346
- type: Boolean,
347
- default: false
348
- },
349
- featureInfo: {
350
- type: Boolean,
351
- default: false
352
- },
353
- pathControls: {
354
- type: Boolean,
355
- default: true
356
- },
357
- searchable: {
358
- type: Boolean,
359
- default: false
360
- },
361
- layerControl: {
362
- type: Boolean,
363
- default: false
364
- },
365
- /**
366
- * Initial species for the flatmap.
367
- * This value will be ignored if a valid state object is provided.
368
- */
369
- initial: {
370
- type: String,
371
- default: ""
372
- },
373
- minZoom: {
374
- type: Number,
375
- default: 4
376
- },
377
- renderAtMounted: {
378
- type: Boolean,
379
- default: false
380
- },
381
- helpMode: {
382
- type: Boolean,
383
- default: false
384
- },
385
- displayMinimap: {
386
- type: Boolean,
387
- default: false
388
- },
389
- showStarInLegend: {
390
- type: Boolean,
391
- default: false
392
- },
393
- /**
394
- * Flag to determine rather open map UI should be
395
- * presented or not.
396
- */
397
- enableOpenMapUI: {
398
- type: Boolean,
399
- default: false,
400
- },
401
- openMapOptions: {
402
- type: Array
403
- },
404
- availableSpecies: {
405
- type: Object,
406
- default: function() {
407
- return {
408
- "Human Female":{taxo: "NCBITaxon:9606", biologicalSex: "PATO:0000383", iconClass:"mapicon-icon_human", displayWarning:true},
409
- "Human Male":{taxo: "NCBITaxon:9606", biologicalSex: "PATO:0000384", iconClass:"mapicon-icon_human", displayWarning:true},
410
- "Rat":{taxo: "NCBITaxon:10114", iconClass:"mapicon-icon_rat", displayLatestChanges: true},
411
- "Mouse":{taxo: "NCBITaxon:10090", iconClass:"mapicon-icon_mouse", displayWarning: true},
412
- "Pig":{taxo: "NCBITaxon:9823", iconClass:"mapicon-icon_pig", displayWarning: true},
413
- "Cat":{taxo: "NCBITaxon:9685", iconClass:"mapicon-icon_cat", displayWarning: true},
414
- }
415
- }
416
- },
417
- /**
418
- * State containing state of the flatmap.
419
- */
420
- state: {
421
- type: Object,
422
- default: undefined,
423
- },
424
- /**
425
- * Specify the endpoint of the flatmap server.
426
- */
427
- flatmapAPI: {
428
- type: String,
429
- default: "https://mapcore-demo.org/current/flatmap/v3/"
430
- },
431
- sparcAPI: {
432
- type: String,
433
- default: "https://api.sparc.science/"
434
- }
435
- },
436
- data: function() {
437
- return {
438
- activeSpecies: undefined,
439
- appendToBody: false,
440
- speciesList: {},
441
- requireInitialisation: true
442
- };
443
- },
444
- watch: {
445
- state: {
446
- handler: function(state) {
447
- this.setState(state);
448
- },
449
- immediate: true,
450
- deep: true,
451
- }
452
- }
453
- };
454
- </script>
455
-
456
- <style scoped lang="scss">
457
- @import "~element-ui/packages/theme-chalk/src/select";
458
- @import "~element-ui/packages/theme-chalk/src/option";
459
-
460
- .multi-container {
461
- height: 100%;
462
- width: 100%;
463
- }
464
-
465
- .species-display-text {
466
- width: 47px;
467
- height: 20px;
468
- color: rgb(48, 49, 51);
469
- font-size: 14px;
470
- font-weight: normal;
471
- line-height: 20px;
472
- left:24px;
473
- top:16px;
474
- position: absolute;
475
- }
476
-
477
- .select-box {
478
- width: 120px;
479
- border-radius: 4px;
480
- border: 1px solid rgb(144, 147, 153);
481
- background-color: var(--white);
482
- font-weight: 500;
483
- color:rgb(48, 49, 51);
484
- left: 16px;
485
- top: 44px;
486
- position: absolute;
487
- ::v-deep .el-input__inner {
488
- color: rgb(48, 49, 51);
489
- padding-top: 0.25em;
490
- }
491
- ::v-deep .el-input__inner {
492
- &is-focus, &:focus {
493
- border: 1px solid $app-primary-color;
494
- }
495
- }
496
- }
497
-
498
-
499
- ::v-deep .flatmap_dropdown {
500
- min-width: 160px!important;
501
- .el-select-dropdown__item {
502
- white-space: nowrap;
503
- text-align: left;
504
- &.selected {
505
- color: $app-primary-color;
506
- font-weight: normal;
507
- }
508
- }
509
- }
510
-
511
- ::v-deep .flatmap-popper {
512
- padding: 6px 4px;
513
- font-size:12px;
514
- color: rgb(48, 49, 51);
515
- background-color: #f3ecf6;
516
- border: 1px solid $app-primary-color;
517
- white-space: nowrap;
518
- min-width: unset;
519
- &.right-popper {
520
- .popper__arrow {
521
- border-right-color: $app-primary-color !important;
522
- &:after {
523
- border-right-color: #f3ecf6 !important;
524
- }
525
- }
526
- }
527
- }
528
-
529
- ::v-deep .flatmap-marker-popup{
530
- background-color: #f0f0f000 !important;
531
- box-shadow: none !important;
532
- }
533
-
534
- </style>
535
-
1
+ <template>
2
+ <div class="multi-container" ref="multiContainer">
3
+ <div style="position: absolute; z-index: 10">
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 right-popper"
10
+ :visible="helpMode"
11
+ :teleported="false"
12
+ ref="selectPopover"
13
+ >
14
+ <template #reference>
15
+ <el-select
16
+ id="flatmap-select"
17
+ :teleported="false"
18
+ v-model="activeSpecies"
19
+ placeholder="Select"
20
+ class="select-box"
21
+ popper-class="flatmap-dropdown"
22
+ @change="setSpecies"
23
+ >
24
+ <el-option
25
+ v-for="(item, key) in speciesList"
26
+ :key="key"
27
+ :label="key"
28
+ :value="key"
29
+ >
30
+ <el-row>
31
+ <el-col :span="8"><i :class="item.iconClass"></i></el-col>
32
+ <el-col :span="12">{{ key }}</el-col>
33
+ </el-row>
34
+ </el-option>
35
+ </el-select>
36
+ </template>
37
+
38
+ </el-popover>
39
+ </div>
40
+ <FlatmapVuer
41
+ v-for="(item, key) in speciesList"
42
+ :key="key"
43
+ :showLayer="showLayer"
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
+ @view-latest-map="viewLatestMap"
55
+ @resource-selected="FlatmapSelected"
56
+ @ready="FlatmapReady"
57
+ @pan-zoom-callback="panZoomCallback"
58
+ @open-map="$emit('open-map', $event)"
59
+ :featureInfo="featureInfo"
60
+ :minZoom="minZoom"
61
+ :pathControls="pathControls"
62
+ :searchable="searchable"
63
+ :layerControl="layerControl"
64
+ :helpMode="helpMode"
65
+ :renderAtMounted="renderAtMounted"
66
+ :displayMinimap="displayMinimap"
67
+ :showStarInLegend="showStarInLegend"
68
+ style="height: 100%"
69
+ :flatmapAPI="flatmapAPI"
70
+ :sparcAPI="sparcAPI"
71
+ />
72
+ </div>
73
+ </template>
74
+
75
+ <script>
76
+ /* eslint-disable no-alert, no-console */
77
+ import { reactive } from 'vue'
78
+ import EventBus from './EventBus'
79
+ import FlatmapVuer from './FlatmapVuer.vue'
80
+ import {
81
+ ElCol as Col,
82
+ ElOption as Option,
83
+ ElSelect as Select,
84
+ ElRow as Row,
85
+ ElPopover as Popover,
86
+ } from 'element-plus'
87
+
88
+ const TAXON_UUID = {
89
+ 'NCBITaxon:10114': '01fedbf9-d783-509c-a10c-827941ab13da',
90
+ 'NCBITaxon:9823': 'a336ac04-24db-561f-a25f-1c994fe17410',
91
+ 'NCBITaxon:9606': '42ed6323-f645-5fbe-bada-9581819cf689',
92
+ 'NCBITaxon:10090': '25285fab-48a0-5620-a6a0-f9a0374837d5',
93
+ 'NCBITaxon:9685': '73060497-46a6-52bf-b975-cac511c127cb',
94
+ }
95
+
96
+ export default {
97
+ name: 'MultiFlatmapVuer',
98
+ components: {
99
+ Col,
100
+ Row,
101
+ Option,
102
+ Select,
103
+ Popover,
104
+ FlatmapVuer,
105
+ },
106
+ beforeMount() {
107
+ //List for resolving the promise in initialise
108
+ //if initialise is called multiple times
109
+ this._resolveList = []
110
+ this._initialised = false
111
+ },
112
+ mounted: function () {
113
+ this.initialise()
114
+ EventBus.on('onActionClick', (action) => {
115
+ this.FlatmapSelected(action)
116
+ })
117
+ },
118
+ methods: {
119
+ initialise: function () {
120
+ return new Promise((resolve) => {
121
+ if (this.requireInitialisation) {
122
+ //It has not been initialised yet
123
+ this.requireInitialisation = false
124
+ fetch(this.flatmapAPI)
125
+ .then((response) => response.json())
126
+ .then((data) => {
127
+ //Check each key in the provided availableSpecies against the one
128
+ Object.keys(this.availableSpecies).forEach((key) => {
129
+ // FIrst look through the uuid
130
+ const uuid = this.availableSpecies[key].uuid
131
+ if (uuid && data.map((e) => e.uuid).indexOf(uuid) > 0) {
132
+ this.speciesList[key] = reactive(this.availableSpecies[key])
133
+ } else {
134
+ for (let i = 0; i < data.length; i++) {
135
+ if (this.availableSpecies[key].taxo === data[i].taxon) {
136
+ if (this.availableSpecies[key].biologicalSex) {
137
+ if (
138
+ data[i].biologicalSex &&
139
+ data[i].biologicalSex ===
140
+ this.availableSpecies[key].biologicalSex
141
+ ) {
142
+ this.speciesList[key] = reactive(this.availableSpecies[key])
143
+ break
144
+ }
145
+ } else {
146
+ this.speciesList[key] = reactive(this.availableSpecies[key])
147
+ break
148
+ }
149
+ }
150
+ }
151
+ }
152
+ })
153
+ //Use the state species if it does not have any other species information
154
+ let species = this.initial
155
+ if (this.state) {
156
+ const mapState = this.state.state
157
+ if (
158
+ (!mapState || (!mapState.uuid && !mapState.entry)) &&
159
+ this.state.species
160
+ )
161
+ species = this.state.species
162
+ else species = undefined
163
+ }
164
+ if (species) {
165
+ //No state resuming, set the current flatmap to {this.initial}
166
+ if (species && this.speciesList[species] !== undefined) {
167
+ this.activeSpecies = species
168
+ } else {
169
+ this.activeSpecies = Object.keys(this.speciesList)[0]
170
+ }
171
+ this.setSpecies(
172
+ this.activeSpecies,
173
+ this.state ? this.state.state : undefined,
174
+ 5
175
+ )
176
+ }
177
+ this._initialised = true
178
+ resolve()
179
+ //Resolve all other promises resolve in the list
180
+ this._resolveList.forEach((other) => {
181
+ other()
182
+ })
183
+ })
184
+ } else if (this._initialised) {
185
+ //resolve as it has been initialised
186
+ resolve()
187
+ } else {
188
+ //resolve when the async initialisation is finished
189
+ this._resolveList.push(resolve)
190
+ }
191
+ })
192
+ },
193
+ FlatmapSelected: function (resource) {
194
+ this.$emit('resource-selected', resource)
195
+ },
196
+ FlatmapReady: function (component) {
197
+ this.$emit('ready', component)
198
+ },
199
+ getCoordinatesOfLastClick: function () {
200
+ const flatmap = this.$refs[this.activeSpecies]
201
+ if (flatmap && flatmap[0]) {
202
+ return flatmap[0].getCoordinatesOfLastClick()
203
+ }
204
+ return undefined
205
+ },
206
+ getCurrentFlatmap: function () {
207
+ return this.$refs[this.activeSpecies][0]
208
+ },
209
+ panZoomCallback: function (payload) {
210
+ this.$emit('pan-zoom-callback', payload)
211
+ },
212
+ showPopup: function (featureId, node, options) {
213
+ let map = this.getCurrentFlatmap()
214
+ map.showPopup(featureId, node, options)
215
+ },
216
+ showMarkerPopup: function (featureId, node, options) {
217
+ let map = this.getCurrentFlatmap()
218
+ map.showMarkerPopup(featureId, node, options)
219
+ },
220
+ setSpecies: function (species, state, numberOfRetry) {
221
+ if (this.$refs && species in this.$refs) {
222
+ this.activeSpecies = species
223
+ this.$refs[this.activeSpecies][0].createFlatmap(state)
224
+ this.$emit('flatmapChanged', this.activeSpecies)
225
+ } else if (numberOfRetry) {
226
+ const retry = numberOfRetry - 1
227
+ if (retry >= 0) {
228
+ this.$nextTick(() => {
229
+ this.setSpecies(species, state, retry)
230
+ })
231
+ }
232
+ }
233
+ },
234
+ /**
235
+ * Function to switch to the latest existing map from
236
+ * a legacy map of the same species.
237
+ *
238
+ * @private
239
+ */
240
+ viewLatestMap: function (state) {
241
+ const keys = Object.keys(this.speciesList)
242
+ for (let i = 0; i < keys.length; i++) {
243
+ const species = this.speciesList[keys[i]]
244
+ if (
245
+ !species.isLegacy &&
246
+ species.taxo === state.entry &&
247
+ species.biologicalSex === state.biologicalSex
248
+ ) {
249
+ this.setSpecies(keys[i], state, 0)
250
+ return
251
+ }
252
+ }
253
+ },
254
+ /**
255
+ * Create a legacy entry with the provided information
256
+ *
257
+ * @private
258
+ */
259
+ createLegacyEntry: function (state, taxo, uuid) {
260
+ if (uuid && taxo) {
261
+ let name = 'Legacy'
262
+ if (state.species) {
263
+ if (state.species.slice(0, 6) === 'Legacy') name = state.species
264
+ else name = name + ` ${state.species}`
265
+ }
266
+ this.speciesList[name] = reactive({
267
+ taxo: taxo,
268
+ isLegacy: true,
269
+ displayWarning: true,
270
+ })
271
+ return {
272
+ species: name,
273
+ state: {
274
+ entry: taxo,
275
+ uuid: uuid,
276
+ viewport: state.state.viewport,
277
+ searchTerm: state.state.searchTerm,
278
+ },
279
+ }
280
+ }
281
+ },
282
+ /**
283
+ * Function used to translate the legacy map state to one that can be used in current
284
+ * flatmap if required. If it is a legacy, an Select entry will be added
285
+ *
286
+ * @private
287
+ */
288
+ updateState: function (state) {
289
+ return new Promise((resolve) => {
290
+ if (state && state.state) {
291
+ const mapState = state.state
292
+ //uuid is not in the state, this is a legacy map
293
+ if (!mapState.uuid) {
294
+ if (mapState.entry) {
295
+ const uuid =
296
+ mapState.entry in TAXON_UUID
297
+ ? TAXON_UUID[mapState.entry]
298
+ : undefined
299
+ const newState = this.createLegacyEntry(
300
+ state,
301
+ mapState.entry,
302
+ uuid
303
+ )
304
+ resolve(newState ? newState : state)
305
+ }
306
+ } else if (mapState.entry) {
307
+ //uuid is in the state but should be checked if it is the latest map
308
+ //for that taxon
309
+ return new Promise(() => {
310
+ const mapManager =
311
+ new (require('@abi-software/flatmap-viewer').MapManager)(
312
+ this.flatmapAPI
313
+ )
314
+ //mapManager.findMap_ is an async function so we need to wrap this with a promise
315
+ const identifier = { taxon: mapState.entry }
316
+ if (mapState.biologicalSex)
317
+ identifier['biologicalSex'] = mapState.biologicalSex
318
+ mapManager
319
+ .findMap_(identifier)
320
+ .then((map) => {
321
+ if (map.uuid !== mapState.uuid) {
322
+ return this.createLegacyEntry(
323
+ state,
324
+ mapState.entry,
325
+ mapState.uuid
326
+ )
327
+ }
328
+ })
329
+ .then((newState) => {
330
+ resolve(newState ? newState : state)
331
+ })
332
+ .catch(() => {
333
+ resolve(state)
334
+ })
335
+ })
336
+ }
337
+ //Create a new state and add the legacy map to the select
338
+ }
339
+ resolve(state)
340
+ })
341
+ },
342
+ /**
343
+ * Function used for getting the current states of the scene. This exported states
344
+ * can be imported using the importStates method.
345
+ *
346
+ * @public
347
+ */
348
+ getState: function () {
349
+ let state = {
350
+ species: this.activeSpecies,
351
+ state: undefined,
352
+ }
353
+ let map = this.getCurrentFlatmap()
354
+ state.state = map.getState()
355
+ return state
356
+ },
357
+ /**
358
+ * Function used for importing the states of the scene. This exported states
359
+ * can be imported using the read states method.
360
+ *
361
+ * @public
362
+ */
363
+ setState: function (state) {
364
+ if (state) {
365
+ //Update state if required
366
+ this.updateState(state).then((currentState) => {
367
+ this.initialise().then(() => {
368
+ if (
369
+ currentState.species &&
370
+ currentState.species !== this.activeSpecies
371
+ ) {
372
+ this.setSpecies(currentState.species, currentState.state, 5)
373
+ } else if (currentState.state) {
374
+ let map = this.getCurrentFlatmap()
375
+ map.setState(currentState.state)
376
+ }
377
+ })
378
+ })
379
+ }
380
+ },
381
+ resourceSelected: function (action) {
382
+ this.$emit('resource-selected', action)
383
+ },
384
+ },
385
+ props: {
386
+ showLayer: {
387
+ type: Boolean,
388
+ default: false,
389
+ },
390
+ featureInfo: {
391
+ type: Boolean,
392
+ default: false,
393
+ },
394
+ pathControls: {
395
+ type: Boolean,
396
+ default: true,
397
+ },
398
+ searchable: {
399
+ type: Boolean,
400
+ default: false,
401
+ },
402
+ layerControl: {
403
+ type: Boolean,
404
+ default: false,
405
+ },
406
+ /**
407
+ * Initial species for the flatmap.
408
+ * This value will be ignored if a valid state object is provided.
409
+ */
410
+ initial: {
411
+ type: String,
412
+ default: '',
413
+ },
414
+ minZoom: {
415
+ type: Number,
416
+ default: 4,
417
+ },
418
+ renderAtMounted: {
419
+ type: Boolean,
420
+ default: false,
421
+ },
422
+ helpMode: {
423
+ type: Boolean,
424
+ default: false,
425
+ },
426
+ displayMinimap: {
427
+ type: Boolean,
428
+ default: false,
429
+ },
430
+ showStarInLegend: {
431
+ type: Boolean,
432
+ default: false,
433
+ },
434
+ /**
435
+ * Flag to determine rather open map UI should be
436
+ * presented or not.
437
+ */
438
+ enableOpenMapUI: {
439
+ type: Boolean,
440
+ default: false,
441
+ },
442
+ openMapOptions: {
443
+ type: Array,
444
+ },
445
+ availableSpecies: {
446
+ type: Object,
447
+ default: function () {
448
+ return {
449
+ 'Human Female': {
450
+ taxo: 'NCBITaxon:9606',
451
+ biologicalSex: 'PATO:0000383',
452
+ iconClass: 'mapicon-icon_human',
453
+ displayWarning: true,
454
+ },
455
+ 'Human Male': {
456
+ taxo: 'NCBITaxon:9606',
457
+ biologicalSex: 'PATO:0000384',
458
+ iconClass: 'mapicon-icon_human',
459
+ displayWarning: true,
460
+ },
461
+ Rat: {
462
+ taxo: 'NCBITaxon:10114',
463
+ iconClass: 'mapicon-icon_rat',
464
+ displayLatestChanges: true,
465
+ },
466
+ Mouse: {
467
+ taxo: 'NCBITaxon:10090',
468
+ iconClass: 'mapicon-icon_mouse',
469
+ displayWarning: true,
470
+ },
471
+ Pig: {
472
+ taxo: 'NCBITaxon:9823',
473
+ iconClass: 'mapicon-icon_pig',
474
+ displayWarning: true,
475
+ },
476
+ Cat: {
477
+ taxo: 'NCBITaxon:9685',
478
+ iconClass: 'mapicon-icon_cat',
479
+ displayWarning: true,
480
+ },
481
+ }
482
+ },
483
+ },
484
+ /**
485
+ * State containing state of the flatmap.
486
+ */
487
+ state: {
488
+ type: Object,
489
+ default: undefined,
490
+ },
491
+ /**
492
+ * Specify the endpoint of the flatmap server.
493
+ */
494
+ flatmapAPI: {
495
+ type: String,
496
+ default: 'https://mapcore-demo.org/current/flatmap/v3/',
497
+ },
498
+ sparcAPI: {
499
+ type: String,
500
+ default: 'https://api.sparc.science/',
501
+ },
502
+ },
503
+ data: function () {
504
+ return {
505
+ activeSpecies: undefined,
506
+ speciesList: {},
507
+ requireInitialisation: true,
508
+ }
509
+ },
510
+ watch: {
511
+ state: {
512
+ handler: function (state) {
513
+ this.setState(state)
514
+ },
515
+ immediate: true,
516
+ deep: true,
517
+ },
518
+ },
519
+ }
520
+ </script>
521
+
522
+ <style lang="scss" scoped>
523
+ @use 'element-plus/theme-chalk/src/select';
524
+ @use 'element-plus/theme-chalk/src/option';
525
+
526
+ .multi-container {
527
+ height: 100%;
528
+ width: 100%;
529
+ }
530
+
531
+ .species-display-text {
532
+ width: 47px;
533
+ height: 20px;
534
+ color: rgb(48, 49, 51);
535
+ font-size: 14px;
536
+ font-weight: normal;
537
+ line-height: 20px;
538
+ left: 24px;
539
+ top: 16px;
540
+ position: absolute;
541
+ }
542
+
543
+ .select-box {
544
+ width: 120px;
545
+ border-radius: 4px;
546
+ border: 1px solid rgb(144, 147, 153);
547
+ background-color: var(--white);
548
+ font-weight: 500;
549
+ color: rgb(48, 49, 51);
550
+ left: 16px;
551
+ top: 44px;
552
+ position: absolute;
553
+ :deep(.el-input__inner) {
554
+ color: rgb(48, 49, 51);
555
+ padding-top: 0.25em;
556
+ }
557
+ :deep() {
558
+ .el-input {
559
+ .el-input__wrapper{
560
+ &is-focus,
561
+ &:focus {
562
+ border: 1px solid $app-primary-color;
563
+ }
564
+ }
565
+ }
566
+ }
567
+ }
568
+
569
+ .flatmap-dropdown {
570
+ min-width: 160px !important;
571
+ .el-select-dropdown__item {
572
+ white-space: nowrap;
573
+ text-align: left;
574
+ &.selected {
575
+ color: $app-primary-color;
576
+ font-weight: normal;
577
+ }
578
+ }
579
+ }
580
+
581
+ .flatmap-popper {
582
+ padding: 6px 4px;
583
+ font-size: 12px;
584
+ color: rgb(48, 49, 51);
585
+ background-color: #f3ecf6;
586
+ border: 1px solid $app-primary-color;
587
+ white-space: nowrap;
588
+ min-width: unset;
589
+ &.right-popper {
590
+ .popper__arrow {
591
+ border-right-color: $app-primary-color !important;
592
+ &:after {
593
+ border-right-color: #f3ecf6 !important;
594
+ }
595
+ }
596
+ }
597
+ }
598
+
599
+ :deep(.flatmap-marker-popup) {
600
+ background-color: #f0f0f000 !important;
601
+ box-shadow: none !important;
602
+ }
603
+ </style>