@abi-software/flatmapvuer 1.20.0 → 1.20.1-demo.1

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.
@@ -2,86 +2,80 @@
2
2
  <div class="multi-container" ref="multiContainer">
3
3
  <div style="position: absolute; z-index: 100" v-if="!disableUI">
4
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)"
5
+ <el-select
6
+ id="flatmap-select"
7
+ ref="speciesSelect"
8
+ v-help-mode="{
9
+ id: 'multiflatmap-species-select',
10
+ area: 'map-info',
11
+ title: 'Select a species',
12
+ description: 'Switch between the maps of the available species.',
13
+ placement: 'right',
14
+ }"
12
15
  :teleported="false"
13
- ref="selectPopover"
16
+ v-model="activeSpecies"
17
+ placeholder="Select"
18
+ class="select-box"
19
+ popper-class="flatmap-dropdown"
20
+ @change="setSpecies"
14
21
  >
15
- <template #reference>
16
- <el-select
17
- id="flatmap-select"
18
- ref="speciesSelect"
19
- :teleported="false"
20
- v-model="activeSpecies"
21
- placeholder="Select"
22
- class="select-box"
23
- popper-class="flatmap-dropdown"
24
- @change="setSpecies"
25
- >
26
- <el-option v-for="(item, key) in speciesList" :key="key" :label="key" :value="key">
27
- <span class="option-label">
28
- <el-tooltip
29
- v-if="activeSpecies !== key"
30
- :content="`Change species to ${key}`"
31
- placement="top"
32
- effect="light"
33
- :show-after="200"
34
- popper-class="flatmap-species-option-tooltip"
35
- >
36
- <span class="option-title">
37
- <span class="select-box-icon">
38
- <i :class="item.iconClass"></i>
39
- </span>
40
- {{ key }}
41
- </span>
42
- </el-tooltip>
43
- <span v-else class="option-title active-species">
44
- <span class="select-box-icon">
45
- <i :class="item.iconClass"></i>
46
- </span>
47
- {{ key }}
22
+ <el-option v-for="(item, key) in speciesList" :key="key" :label="key" :value="key">
23
+ <span class="option-label">
24
+ <el-tooltip
25
+ v-if="activeSpecies !== key"
26
+ :content="`Change species to ${key}`"
27
+ placement="top"
28
+ effect="light"
29
+ :show-after="200"
30
+ popper-class="flatmap-species-option-tooltip"
31
+ >
32
+ <span class="option-title">
33
+ <span class="select-box-icon">
34
+ <i :class="item.iconClass"></i>
48
35
  </span>
49
- <el-tooltip
50
- v-if="enableOpenMapUI"
51
- :content="`Open ${key} in a new view`"
52
- placement="top"
53
- effect="light"
54
- :show-after="200"
55
- popper-class="flatmap-open-new-view-tooltip"
56
- >
57
- <button
58
- type="button"
59
- class="open-new-view-button"
60
- :aria-label="`Open ${key} in a new view`"
61
- @click.stop="openSpeciesInNewView(key)"
62
- >
63
- <svg
64
- viewBox="0 0 24 24"
65
- width="14"
66
- height="14"
67
- fill="none"
68
- stroke="currentColor"
69
- stroke-width="2"
70
- stroke-linecap="round"
71
- stroke-linejoin="round"
72
- aria-hidden="true"
73
- >
74
- <rect x="8" y="8" width="13" height="13" rx="2" />
75
- <path d="M16 8V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3" />
76
- <path d="M14.5 11.5v6M11.5 14.5h6" />
77
- </svg>
78
- </button>
79
- </el-tooltip>
36
+ {{ key }}
80
37
  </span>
81
- </el-option>
82
- </el-select>
83
- </template>
84
- </el-popover>
38
+ </el-tooltip>
39
+ <span v-else class="option-title active-species">
40
+ <span class="select-box-icon">
41
+ <i :class="item.iconClass"></i>
42
+ </span>
43
+ {{ key }}
44
+ </span>
45
+ <el-tooltip
46
+ v-if="enableOpenMapUI"
47
+ :content="`Open ${key} in a new view`"
48
+ placement="top"
49
+ effect="light"
50
+ :show-after="200"
51
+ popper-class="flatmap-open-new-view-tooltip"
52
+ >
53
+ <button
54
+ type="button"
55
+ class="open-new-view-button"
56
+ :aria-label="`Open ${key} in a new view`"
57
+ @click.stop="openSpeciesInNewView(key)"
58
+ >
59
+ <svg
60
+ viewBox="0 0 24 24"
61
+ width="14"
62
+ height="14"
63
+ fill="none"
64
+ stroke="currentColor"
65
+ stroke-width="2"
66
+ stroke-linecap="round"
67
+ stroke-linejoin="round"
68
+ aria-hidden="true"
69
+ >
70
+ <rect x="8" y="8" width="13" height="13" rx="2" />
71
+ <path d="M16 8V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3" />
72
+ <path d="M14.5 11.5v6M11.5 14.5h6" />
73
+ </svg>
74
+ </button>
75
+ </el-tooltip>
76
+ </span>
77
+ </el-option>
78
+ </el-select>
85
79
  </div>
86
80
  <!--
87
81
  This event is emitted when the user chooses a different map option
@@ -127,13 +121,6 @@
127
121
  @open-map="$emit('open-map', $event)"
128
122
  @pathway-selection-changed="onSelectionsDataChanged"
129
123
  :minZoom="minZoom"
130
- :helpMode="activeSpecies == key && helpMode"
131
- :helpModeActiveItem="helpModeActiveItem"
132
- :helpModeDialog="helpModeDialog"
133
- :helpModeInitialIndex="-2"
134
- @help-mode-last-item="onHelpModeLastItem"
135
- @shown-tooltip="onTooltipShown"
136
- @shown-map-tooltip="onMapTooltipShown"
137
124
  :renderAtMounted="renderAtMounted"
138
125
  :render="render && activeSpecies == key"
139
126
  :displayMinimap="displayMinimap"
@@ -158,6 +145,7 @@
158
145
  import { markRaw } from 'vue';
159
146
  import EventBus from './EventBus';
160
147
  import FlatmapVuer from './FlatmapVuer.vue';
148
+ import { collectHelpModeSteps, helpModeDirective } from '@abi-software/map-utilities';
161
149
  import flatmap from '../services/flatmapLoader.js';
162
150
 
163
151
  const TAXON_UUID = {
@@ -176,6 +164,9 @@ export default {
176
164
  components: {
177
165
  FlatmapVuer,
178
166
  },
167
+ directives: {
168
+ helpMode: helpModeDirective,
169
+ },
179
170
  created: function () {
180
171
  this.loadMapManager();
181
172
  },
@@ -387,6 +378,17 @@ export default {
387
378
  getCurrentFlatmap: function () {
388
379
  return this.$refs[this.activeSpecies][0];
389
380
  },
381
+ /**
382
+ * @public
383
+ * Function to get the help mode steps of this component and the current flatmap,
384
+ * from the elements with ``v-help-mode``, to be used with ``HelpModeTour`` and
385
+ * ``HelpModeHover`` from ``@abi-software/map-utilities``.
386
+ * The flatmaps of the other species are hidden and left out.
387
+ * @returns {Array} The list of help steps.
388
+ */
389
+ getHelpModeSteps: function () {
390
+ return collectHelpModeSteps(this.$el);
391
+ },
390
392
  /**
391
393
  * @public
392
394
  * Function to request opening the given species in a new view/panel,
@@ -624,44 +626,6 @@ export default {
624
626
  });
625
627
  }
626
628
  },
627
- /**
628
- * @public
629
- * Function to activate help mode tooltip by item index number
630
- * @arg {Number} `index`
631
- */
632
- activateTooltipByIndex: function (index) {
633
- return index === this.helpModeActiveItem && this.helpMode;
634
- },
635
- /**
636
- * @public
637
- * Function to check the last item of help mode
638
- * @arg {Boolean} `isLastItem`
639
- */
640
- onHelpModeLastItem: function (isLastItem) {
641
- if (isLastItem) {
642
- this.$emit('help-mode-last-item', true);
643
- }
644
- },
645
- /**
646
- * @public
647
- * Function to emit event after a tooltip is shown.
648
- */
649
- onTooltipShown: function () {
650
- /**
651
- * This event is emitted after a tooltip in Flatmap is shown.
652
- */
653
- this.$emit('shown-tooltip');
654
- },
655
- /**
656
- * @public
657
- * Function to emit event after a tooltip on the map is shown.
658
- */
659
- onMapTooltipShown: function () {
660
- /**
661
- * This event is emitted after a tooltip on Flatmap's map is shown.
662
- */
663
- this.$emit('shown-map-tooltip');
664
- },
665
629
  /**
666
630
  * @public
667
631
  * Function to change the view mode of the map.
@@ -708,36 +672,6 @@ export default {
708
672
  type: Boolean,
709
673
  default: true,
710
674
  },
711
- /**
712
- * The option to show tooltips for help mode.
713
- */
714
- helpMode: {
715
- type: Boolean,
716
- default: false,
717
- },
718
- /**
719
- * The active item index of help mode.
720
- */
721
- helpModeActiveItem: {
722
- type: Number,
723
- default: 0,
724
- },
725
- /**
726
- * The option to use helpModeDialog.
727
- * On default, `false`, clicking help will show all tooltips.
728
- * If `true`, clicking help will show the help-mode-dialog.
729
- */
730
- helpModeDialog: {
731
- type: Boolean,
732
- default: false,
733
- },
734
- /**
735
- * The last item of help mode.
736
- */
737
- helpModeLastItem: {
738
- type: Boolean,
739
- default: false,
740
- },
741
675
  /**
742
676
  * The option to display minimap at the top-right corner of the map.
743
677
  */
@@ -15,11 +15,23 @@
15
15
  width="max-content"
16
16
  :offset="0"
17
17
  popper-class="flatmap-popper flatmap-teleport-popper"
18
- :visible="tooltipVisible"
18
+ :visible="isHovering"
19
19
  ref="featuredMarkerPopover"
20
20
  >
21
21
  <template #reference>
22
- <div v-popover:featuredMarkerPopover @mouseover="onMouseOver" @mouseout="onMouseOut">
22
+ <div
23
+ v-popover:featuredMarkerPopover
24
+ v-help-mode="{
25
+ id: 'flatmap-featured-marker',
26
+ area: 'legends',
27
+ title: 'Featured dataset marker',
28
+ description: 'Shows the location of the featured dataset on the map.',
29
+ placement: 'right',
30
+ onEnter: openHelpModeDrawer,
31
+ }"
32
+ @mouseover="onMouseOver"
33
+ @mouseout="onMouseOut"
34
+ >
23
35
  <LegendItem
24
36
  :item="item"
25
37
  :identifierKey="identifierKey"
@@ -44,12 +56,19 @@
44
56
 
45
57
  <script>
46
58
  import LegendItem from './LegendItem.vue';
59
+ import { helpModeDirective } from '@abi-software/map-utilities';
47
60
 
48
61
  export default {
49
62
  name: 'DynamicLegends',
50
63
  components: {
51
64
  LegendItem,
52
65
  },
66
+ directives: {
67
+ helpMode: helpModeDirective,
68
+ },
69
+ inject: {
70
+ openHelpModeDrawer: { default: () => () => {} },
71
+ },
53
72
  props: {
54
73
  identifierKey: {
55
74
  type: String,
@@ -73,10 +92,6 @@ export default {
73
92
  type: Boolean,
74
93
  default: false,
75
94
  },
76
- showDatasetMarkerTooltip: {
77
- type: Boolean,
78
- default: false,
79
- },
80
95
  },
81
96
  data() {
82
97
  return {
@@ -84,12 +99,6 @@ export default {
84
99
  hoverTimeout: null,
85
100
  };
86
101
  },
87
- computed: {
88
- tooltipVisible() {
89
- // Show tooltip when either help mode is active OR user is hovering
90
- return (this.showDatasetMarkerTooltip && this.showStarInLegend) || this.isHovering;
91
- },
92
- },
93
102
  methods: {
94
103
  onMouseOver() {
95
104
  clearTimeout(this.hoverTimeout);
@@ -0,0 +1,129 @@
1
+ const SOMA_MARKER_COLOUR = '#1b7f6b';
2
+ const SOMA_MARKER_SECONDARY_COLOUR = '#f4f1de';
3
+ const SOMA_MARKER_TEXT_COLOUR = '#12312b';
4
+ const SOMA_MARKER_MAX_COUNT_LABEL = '99+';
5
+
6
+ const normalizeSomaLocations = function (somaLocations) {
7
+ return (Array.isArray(somaLocations) ? somaLocations : [])
8
+ .map((item) => ({
9
+ label: String(item?.label || '').trim(),
10
+ curie: String(item?.curie || '').trim(),
11
+ count: Number(item?.count || 0),
12
+ }))
13
+ .filter((item) => item.curie && item.count > 0);
14
+ };
15
+
16
+ const formatCount = function (count) {
17
+ if (count > 99) return SOMA_MARKER_MAX_COUNT_LABEL;
18
+ return String(count);
19
+ };
20
+
21
+ const createSomaLocationMarkerElement = function (somaLocation) {
22
+ const wrapper = document.createElement('div');
23
+ wrapper.className = 'flatmapvuer-soma-location-marker';
24
+ wrapper.title = somaLocation.label || somaLocation.curie;
25
+ wrapper.style.width = '34px';
26
+ wrapper.style.height = '48px';
27
+ wrapper.style.display = 'flex';
28
+ wrapper.style.alignItems = 'center';
29
+ wrapper.style.justifyContent = 'center';
30
+ wrapper.style.transform = 'translate(-50%, -100%)';
31
+
32
+ const countLabel = formatCount(somaLocation.count);
33
+ wrapper.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="-1 -1 27 42" width="34" height="48" aria-hidden="true">
34
+ <ellipse style="fill: rgb(0, 0, 0); fill-opacity: 0.18;" cx="12" cy="36" rx="8" ry="4"/>
35
+ <path d="M12.25.25a12.254 12.254 0 0 0-12 12.494
36
+ c0 6.444 6.488 12.109 11.059 22.564.549 1.256 1.333 1.256 1.882 0
37
+ C17.762 24.853 24.25 19.186 24.25 12.744A12.254 12.254 0 0 0 12.25.25Z"
38
+ style="fill:${SOMA_MARKER_COLOUR};stroke:${SOMA_MARKER_SECONDARY_COLOUR};stroke-width:1.1"/>
39
+ <circle cx="12.5" cy="12.5" r="8" fill="${SOMA_MARKER_SECONDARY_COLOUR}"/>
40
+ <text x="12.5" y="16.1" text-anchor="middle" style="font-size:7.5px;font-weight:700;fill:${SOMA_MARKER_TEXT_COLOUR};font-family:Arial, sans-serif">${countLabel}</text>
41
+ </svg>`;
42
+
43
+ return wrapper;
44
+ };
45
+
46
+ const resolveMarkerPlacement = function (mapImp, curie) {
47
+ const featureIds = Array.isArray(mapImp?.modelFeatureIds?.(curie))
48
+ ? mapImp.modelFeatureIds(curie)
49
+ : [];
50
+ const placements = [];
51
+ const seenFeatureUris = new Set();
52
+
53
+ for (const featureId of featureIds) {
54
+ const annotation = mapImp.annotation(featureId);
55
+ const featureUri = String(annotation?.uri || '').trim();
56
+ if (featureUri && !seenFeatureUris.has(featureUri)) {
57
+ seenFeatureUris.add(featureUri);
58
+ placements.push({
59
+ type: 'feature-uri',
60
+ value: featureUri,
61
+ });
62
+ }
63
+ }
64
+
65
+ // Fall back to model placement only when no feature URI can be resolved.
66
+ if (!placements.length && featureIds.length) {
67
+ placements.push({
68
+ type: 'model',
69
+ value: curie,
70
+ });
71
+ }
72
+
73
+ return placements;
74
+ };
75
+
76
+ export const attachSomaLocationMarkerMethods = function (mapImp) {
77
+ if (!mapImp || mapImp.addSomaLocationMarkers) {
78
+ return mapImp;
79
+ }
80
+
81
+ let markerIds = [];
82
+
83
+ mapImp.clearSomaLocationMarkers = function () {
84
+ markerIds.forEach((markerId) => {
85
+ mapImp.removeMarker(markerId);
86
+ });
87
+ markerIds = [];
88
+ };
89
+
90
+ mapImp.addSomaLocationMarkers = function (somaLocations) {
91
+ const normalizedSomaLocations = normalizeSomaLocations(somaLocations);
92
+ const placedSomaLocations = [];
93
+
94
+ mapImp.clearSomaLocationMarkers();
95
+
96
+ normalizedSomaLocations.forEach((somaLocation) => {
97
+ const placements = resolveMarkerPlacement(mapImp, somaLocation.curie);
98
+ if (!placements.length) return;
99
+
100
+ let somaLocationPlaced = false;
101
+ placements.forEach((placement) => {
102
+ const markerElement = createSomaLocationMarkerElement(somaLocation);
103
+ let addedMarkerIds = [];
104
+
105
+ if (placement.type === 'feature-uri') {
106
+ addedMarkerIds = mapImp.addMarkerByFeatureUri(placement.value, {
107
+ element: markerElement,
108
+ });
109
+ } else if (placement.type === 'model') {
110
+ const markerId = mapImp.addMarker(placement.value, { element: markerElement });
111
+ addedMarkerIds = markerId > -1 ? [markerId] : [];
112
+ }
113
+
114
+ if (!addedMarkerIds.length) return;
115
+
116
+ markerIds.push(...addedMarkerIds);
117
+ somaLocationPlaced = true;
118
+ });
119
+
120
+ if (somaLocationPlaced) {
121
+ placedSomaLocations.push(somaLocation);
122
+ }
123
+ });
124
+
125
+ return placedSomaLocations;
126
+ };
127
+
128
+ return mapImp;
129
+ };