@abi-software/flatmapvuer 0.5.7-alpha → 0.5.7

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