@abi-software/flatmapvuer 1.1.0-beta.3 → 1.1.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.
@@ -0,0 +1,360 @@
1
+ <template>
2
+ <div class="help-mode-dialog" :class="{'finish': lastItem}">
3
+ <h4>Help Mode</h4>
4
+
5
+ <template v-if="lastItem">
6
+ <p>
7
+ All caught up! <br>
8
+ Click 'Help' to restart.
9
+ </p>
10
+ <div>
11
+ <el-button class="button" @click="finishHelpMode">
12
+ Finish
13
+ </el-button>
14
+ </div>
15
+ </template>
16
+ <template v-else>
17
+ <p>Click "Next" to see the next item.</p>
18
+ <div>
19
+ <el-button class="button" @click="showNext">
20
+ Next
21
+ </el-button>
22
+ <el-button class="button secondary" @click="finishHelpMode">
23
+ Exit Help Mode
24
+ </el-button>
25
+ </div>
26
+ </template>
27
+ </div>
28
+ </template>
29
+
30
+ <script>
31
+ import {
32
+ ElButton as Button,
33
+ } from 'element-plus';
34
+
35
+ export default {
36
+ name: 'HelpModeDialog',
37
+ components: {
38
+ Button,
39
+ },
40
+ props: {
41
+ multiflatmapRef: {
42
+ type: Object,
43
+ default: null,
44
+ },
45
+ flatmapRef: {
46
+ type: Object,
47
+ default: null,
48
+ },
49
+ scaffoldRef: {
50
+ type: Object,
51
+ default: null,
52
+ },
53
+ lastItem: {
54
+ type: Boolean,
55
+ default: false,
56
+ required: false,
57
+ }
58
+ },
59
+ mounted: function () {
60
+ this.toggleHelpModeHighlight(true);
61
+ // For tooltips outside of Flatmap
62
+ this.toggleTooltipHighlight();
63
+ },
64
+ unmounted: function () {
65
+ this.toggleHelpModeHighlight(false);
66
+ },
67
+ watch: {
68
+ lastItem: function (isLastItem) {
69
+ if (isLastItem) {
70
+ this.toggleTooltipHighlight();
71
+ }
72
+ }
73
+ },
74
+ methods: {
75
+ showNext: function () {
76
+ this.$emit('show-next');
77
+ },
78
+ finishHelpMode: function () {
79
+ this.$emit('finish-help-mode');
80
+ },
81
+ /**
82
+ * This function must be called on 'shown-map-tooltip' event.
83
+ */
84
+ toggleTooltipPinHighlight: function () {
85
+ const currentFlatmapEl = this.getCurrentFlatmap();
86
+ this.resetHighlightedItems();
87
+
88
+ this.$nextTick(() => {
89
+ // Temporary solution to find the position of map marker from popover
90
+ const mapPins = currentFlatmapEl.querySelectorAll('.maplibregl-marker');
91
+ const mapPinPopover = currentFlatmapEl.querySelector('.flatmap-popup-popper');
92
+ const styleVal = mapPinPopover?.style?.transform || '';
93
+ const mapPopoverPosition = this.extractMarkerPosition(styleVal);
94
+
95
+ mapPins.forEach((mapPin) => {
96
+ const mapPinStyleVal = mapPin.style.transform;
97
+ const mapPinPosition = this.extractMarkerPosition(mapPinStyleVal);
98
+
99
+ if (mapPinPosition === mapPopoverPosition) {
100
+ mapPin.classList.add('in-help-highlight');
101
+ }
102
+ });
103
+ });
104
+ },
105
+ /**
106
+ * This function must be called on 'shown-tooltip' event.
107
+ */
108
+ toggleTooltipHighlight: function () {
109
+ this.resetHighlightedItems();
110
+
111
+ this.$nextTick(() => {
112
+ const activePoppers = document.querySelectorAll('.el-popper:not([style*="none"])');
113
+
114
+ activePoppers.forEach((activePopper) => {
115
+ const multiFlatmapTooltip = activePopper.classList.contains('flatmap-popper');
116
+ const flatmapTooltip = activePopper.classList.contains('el-fade-in-linear-enter-active');
117
+
118
+ if (multiFlatmapTooltip || flatmapTooltip) {
119
+ this.toggleHighlight(activePopper);
120
+ }
121
+ });
122
+ });
123
+ },
124
+ toggleHighlight: function (activePopper) {
125
+ const popperId = activePopper?.id || '';
126
+ const popperTrigger = document.querySelector(`[aria-describedby="${popperId}"]`);
127
+
128
+ if (popperTrigger) {
129
+ popperTrigger.classList.add('in-help-highlight');
130
+ }
131
+ },
132
+ resetHighlightedItems: function () {
133
+ const allHighlightedItems = document.querySelectorAll('.in-help-highlight');
134
+ allHighlightedItems.forEach((el) => {
135
+ el.classList.remove('in-help-highlight');
136
+ });
137
+ },
138
+ getCurrentScaffold: function () {
139
+ const scaffoldEl = this.scaffoldRef?.$el || null;
140
+ return scaffoldEl;
141
+ },
142
+ getCurrentMultiflatmap: function () {
143
+ const multiflatmapEl = this.multiflatmapRef?.$el || null;
144
+ return multiflatmapEl;
145
+ },
146
+ getCurrentFlatmap: function () {
147
+ const flatmap = this.flatmapRef || this.multiflatmapRef?.getCurrentFlatmap();
148
+ const flatmapEl = flatmap?.$el || null;
149
+ return flatmapEl;
150
+ },
151
+ toggleHelpModeHighlight: function (option) {
152
+ const currentMultiflatmapEl = this.getCurrentMultiflatmap();
153
+ const currentFlatmapEl = this.getCurrentFlatmap();
154
+ const currentScaffoldEl = this.getCurrentScaffold();
155
+ const allHighlightedItems = document.querySelectorAll('.in-help-highlight');
156
+
157
+ if (currentMultiflatmapEl) {
158
+ if (option) {
159
+ currentMultiflatmapEl.classList.add('in-help');
160
+ } else {
161
+ currentMultiflatmapEl.classList.remove('in-help');
162
+ }
163
+ }
164
+
165
+ if (currentFlatmapEl) {
166
+ if (option) {
167
+ currentFlatmapEl.classList.add('in-help');
168
+ } else {
169
+ currentFlatmapEl.classList.remove('in-help');
170
+ }
171
+ }
172
+
173
+ if (currentScaffoldEl) {
174
+ if (option) {
175
+ currentScaffoldEl.classList.add('in-help');
176
+ } else {
177
+ currentScaffoldEl.classList.remove('in-help');
178
+ }
179
+ }
180
+
181
+ if (!option) {
182
+ allHighlightedItems.forEach((el) => {
183
+ el.classList.remove('in-help-highlight');
184
+ });
185
+ }
186
+ },
187
+ /**
188
+ * Temporary solution to find the position of map marker from popover
189
+ */
190
+ extractMarkerPosition: function (str) {
191
+ const translateRegex = /translate\((.*?)\)/g;
192
+ const matches = str.match(translateRegex);
193
+ if (!matches) {
194
+ return '';
195
+ }
196
+ const lastMatch = matches[matches.length - 1];
197
+ const values = lastMatch.slice(10, -1);
198
+ return values;
199
+ },
200
+ }
201
+ }
202
+ </script>
203
+
204
+ <style lang="scss" scoped>
205
+ .help-mode-dialog {
206
+ display: flex;
207
+ flex-direction: column;
208
+ align-items: center;
209
+ justify-content: center;
210
+ gap: 1rem;
211
+ width: 300px;
212
+ padding: 1rem;
213
+ font-family: inherit;
214
+ font-size: 14px;
215
+ background: white;
216
+ border-radius: 4px 4px;
217
+ border: 1px solid $app-primary-color;
218
+ box-shadow: 0px 0px 160px 80px rgba(0,0,0,0.5);
219
+ position: absolute;
220
+ top: 0;
221
+ left: 50%;
222
+ transform: translateX(-50%);
223
+ z-index: 2;
224
+
225
+ &.finish {
226
+ animation: shake 0.35s;
227
+ animation-delay: 0.7s;
228
+ }
229
+
230
+ h4 {
231
+ color: $app-primary-color;
232
+ }
233
+
234
+ h4, p {
235
+ margin: 0;
236
+ }
237
+
238
+ p {
239
+ line-height: 1.5;
240
+ }
241
+
242
+ .button {
243
+ color: #fff;
244
+ background-color: $app-primary-color;
245
+ transform: scale(1);
246
+ transform-origin: 50% 50%;
247
+ transition: all var(--el-transition-duration);
248
+
249
+ &:hover {
250
+ color: #fff !important;
251
+ background: #ac76c5 !important;
252
+ border: 1px solid #ac76c5 !important;
253
+ }
254
+
255
+ &:active {
256
+ transform: scale(0.95);
257
+ }
258
+
259
+ &.secondary {
260
+ background: #f3e6f9;
261
+ border-color: $app-primary-color;
262
+ color: $app-primary-color;
263
+
264
+ &:hover {
265
+ color: $app-primary-color !important;
266
+ background: #fff !important;
267
+ }
268
+ }
269
+ }
270
+ }
271
+
272
+ @keyframes shake {
273
+ 0% {
274
+ transform: translateX(-50%) rotate(2deg);
275
+ }
276
+ 25% {
277
+ transform: translateX(-50%) rotate(-2deg);
278
+ }
279
+ 50% {
280
+ transform: translateX(-50%) rotate(2deg);
281
+ }
282
+ 75% {
283
+ transform: translateX(-50%) rotate(-2deg);
284
+ }
285
+ 100% {
286
+ transform: translateX(-50%) rotate(2deg);
287
+ }
288
+ }
289
+
290
+ // Just for App.vue with options popover on top
291
+ .help-mode-dialog {
292
+ .options-popover + .multi-container + & {
293
+ margin-top: 40px;
294
+ }
295
+ .options-popover:not([style*="display: none"]) + .multi-container + & {
296
+ margin-top: 175px;
297
+ }
298
+ }
299
+ </style>
300
+
301
+ <style lang="scss">
302
+ .scaffold-container.in-help,
303
+ .flatmap-container.in-help {
304
+ background: rgba(0,0,0,0.3);
305
+ }
306
+
307
+ .scaffold-container.in-help {
308
+ canvas {
309
+ opacity: 0.3;
310
+ }
311
+ }
312
+
313
+ .scaffold-container.in-help,
314
+ .flatmap-container.in-help {
315
+ .el-tooltip__trigger,
316
+ .el-popover {
317
+ opacity: 0.3;
318
+ }
319
+
320
+ .pathway-location:has(.in-help-highlight) {
321
+ opacity: 1;
322
+
323
+ .pathway-container {
324
+ background: transparent;
325
+ }
326
+
327
+ .container,
328
+ .legends-container,
329
+ .selections-container {
330
+ opacity: 0.3;
331
+ }
332
+ }
333
+
334
+ .maplibregl-canvas,
335
+ .maplibregl-ctrl-minimap {
336
+ opacity: 0.3;
337
+ }
338
+
339
+ .maplibregl-map,
340
+ .maplibregl-canvas {
341
+ pointer-events: none;
342
+ }
343
+ }
344
+
345
+ .in-help .el-popper:not([style*="none"]) {
346
+ opacity: 1 !important;
347
+ }
348
+
349
+ .in-help-highlight {
350
+ opacity: 1 !important;
351
+ background: white !important;
352
+ box-shadow: 0px 0px 128px 128px white !important;
353
+ animation: highlight-area 0.1s;
354
+
355
+ &.maplibregl-marker {
356
+ background: none !important;
357
+ box-shadow: 0px 0px 128px 128px rgba(255,255,255,0.5) !important;
358
+ }
359
+ }
360
+ </style>
@@ -8,7 +8,7 @@
8
8
  trigger="manual"
9
9
  popper-class="flatmap-popper flatmap-teleport-popper right-popper"
10
10
  width="max-content"
11
- :visible="helpMode"
11
+ :visible="activateTooltipByIndex(0)"
12
12
  :teleported="false"
13
13
  ref="selectPopover"
14
14
  >
@@ -66,6 +66,12 @@
66
66
  @pathway-selection-changed="onSelectionsDataChanged"
67
67
  :minZoom="minZoom"
68
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"
69
75
  :renderAtMounted="renderAtMounted"
70
76
  :displayMinimap="displayMinimap"
71
77
  :showStarInLegend="showStarInLegend"
@@ -463,6 +469,45 @@ export default {
463
469
  })
464
470
  }
465
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
+ },
466
511
  },
467
512
  props: {
468
513
  /**
@@ -494,6 +539,29 @@ export default {
494
539
  type: Boolean,
495
540
  default: false,
496
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
+ },
497
565
  /**
498
566
  * The option to display minimap at the top-right corner of the map.
499
567
  */
@@ -251,7 +251,7 @@ export default {
251
251
  }
252
252
  },
253
253
  provSpeciesDescription: function () {
254
- let text = 'Observed in'
254
+ let text = 'Studied in'
255
255
  this.entry.provenanceTaxonomyLabel.forEach((label) => {
256
256
  text += ` ${label},`
257
257
  })
@@ -341,7 +341,7 @@ export default {
341
341
  .el-popper__arrow {
342
342
  &:before {
343
343
  border-color: $app-primary-color;
344
- background-color: #f3ecf6;
344
+ background-color: #ffffff;
345
345
  }
346
346
  }
347
347
  }
@@ -2,7 +2,21 @@
2
2
  <div class="selections-container">
3
3
  <el-row>
4
4
  <el-col :span="12">
5
- <div class="checkall-display-text">{{ title }}</div>
5
+ <span class="checkall-display-text">{{ title }}</span>
6
+ <el-popover
7
+ width="250"
8
+ trigger="hover"
9
+ :teleported="false"
10
+ popper-class="popover-origin-help"
11
+ v-if="helpMessage"
12
+ >
13
+ <template v-if="helpMessage" #reference>
14
+ <el-icon class="info"><el-icon-warning /></el-icon>
15
+ </template>
16
+ <span style="word-break: keep-all">
17
+ {{ helpMessage }}
18
+ </span>
19
+ </el-popover>
6
20
  </el-col>
7
21
  <el-col :span="12">
8
22
  <el-checkbox
@@ -59,9 +73,13 @@
59
73
 
60
74
  <script>
61
75
  /* eslint-disable no-alert, no-console */
76
+ import {
77
+ Warning as ElIconWarning,
78
+ } from '@element-plus/icons-vue'
62
79
  import {
63
80
  ElCheckbox as Checkbox,
64
81
  ElCheckboxGroup as CheckboxGroup,
82
+ ElIcon as Icon,
65
83
  ElCol as Col,
66
84
  ElRow as Row,
67
85
  } from 'element-plus'
@@ -72,7 +90,9 @@ export default {
72
90
  Checkbox,
73
91
  CheckboxGroup,
74
92
  Col,
93
+ Icon,
75
94
  Row,
95
+ ElIconWarning,
76
96
  },
77
97
  methods: {
78
98
  /**
@@ -187,6 +207,10 @@ export default {
187
207
  type: String,
188
208
  default: 'line',
189
209
  },
210
+ helpMessage: {
211
+ type: String,
212
+ default: '',
213
+ },
190
214
  identifierKey: {
191
215
  type: String,
192
216
  default: 'id',
@@ -318,4 +342,22 @@ export default {
318
342
  width: 100%;
319
343
  top: 2px;
320
344
  }
345
+
346
+ .info {
347
+ transform: rotate(180deg);
348
+ color: #8300bf;
349
+ margin-left: 8px;
350
+ }
351
+
352
+
353
+ :deep(.popover-origin-help.el-popover) {
354
+ text-transform: none !important; // need to overide the tooltip text transform
355
+ border: 1px solid $app-primary-color;
356
+ .el-popper__arrow {
357
+ &:before {
358
+ border-color: $app-primary-color;
359
+ background-color: #ffffff;
360
+ }
361
+ }
362
+ }
321
363
  </style>
@@ -3,5 +3,6 @@
3
3
  import FlatmapVuer from './FlatmapVuer.vue'
4
4
  import MultiFlatmapVuer from './MultiFlatmapVuer.vue'
5
5
  import Tooltip from './Tooltip.vue'
6
+ import HelpModeDialog from './HelpModeDialog.vue'
6
7
 
7
- export { FlatmapVuer, MultiFlatmapVuer, Tooltip}
8
+ export { FlatmapVuer, MultiFlatmapVuer, Tooltip, HelpModeDialog }
@@ -12,6 +12,7 @@ declare module 'vue' {
12
12
  DrawTool: typeof import('./components/DrawTool.vue')['default']
13
13
  DynamicLegends: typeof import('./components/legends/DynamicLegends.vue')['default']
14
14
  ElButton: typeof import('element-plus/es')['ElButton']
15
+ ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
15
16
  ElCard: typeof import('element-plus/es')['ElCard']
16
17
  ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
17
18
  ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
@@ -20,7 +21,6 @@ declare module 'vue' {
20
21
  ElIconArrowDown: typeof import('@element-plus/icons-vue')['ArrowDown']
21
22
  ElIconArrowLeft: typeof import('@element-plus/icons-vue')['ArrowLeft']
22
23
  ElIconArrowUp: typeof import('@element-plus/icons-vue')['ArrowUp']
23
- ElIconCircleClose: typeof import('@element-plus/icons-vue')['CircleClose']
24
24
  ElIconClose: typeof import('@element-plus/icons-vue')['Close']
25
25
  ElIconDelete: typeof import('@element-plus/icons-vue')['Delete']
26
26
  ElIconEdit: typeof import('@element-plus/icons-vue')['Edit']
@@ -38,6 +38,7 @@ declare module 'vue' {
38
38
  ElTree: typeof import('element-plus/es')['ElTree']
39
39
  ExternalResourceCard: typeof import('./components/ExternalResourceCard.vue')['default']
40
40
  FlatmapVuer: typeof import('./components/FlatmapVuer.vue')['default']
41
+ HelpModeDialog: typeof import('./components/HelpModeDialog.vue')['default']
41
42
  MultiFlatmapVuer: typeof import('./components/MultiFlatmapVuer.vue')['default']
42
43
  ProvenancePopup: typeof import('./components/ProvenancePopup.vue')['default']
43
44
  SelectionsGroup: typeof import('./components/SelectionsGroup.vue')['default']
@@ -231,7 +231,6 @@ let FlatmapQueries = function () {
231
231
 
232
232
  this.queryForConnectivity = function (keastIds, signal, processConnectivity=true) {
233
233
  const data = { sql: this.buildConnectivitySqlStatement(keastIds) }
234
-
235
234
  const headers = {
236
235
  method: 'POST',
237
236
  headers: {