@abi-software/map-utilities 0.0.0-beta.5 → 0.0.0-beta.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.
@@ -15,7 +15,7 @@
15
15
  <div class="block" v-else>
16
16
  <div class="title">{{ tooltipEntry.featureId }}</div>
17
17
  </div>
18
- <div v-if="featuresAlert">
18
+ <div v-if="featuresAlert" class="attribute-title-container">
19
19
  <span class="attribute-title">Alert</span>
20
20
  <el-popover
21
21
  width="250"
@@ -31,6 +31,24 @@
31
31
  </span>
32
32
  </el-popover>
33
33
  </div>
34
+ <div class="block">
35
+ <el-button
36
+ class="button"
37
+ @click="showImages = !showImages"
38
+ >
39
+ <span v-if="showImages">Hide images</span>
40
+ <span v-else>View images at this location (Gallery)</span>
41
+ </el-button>
42
+ <div v-if="showImages" class="image-gallery-container">
43
+ <Gallery :items="galleryItems" />
44
+ </div>
45
+ <el-button
46
+ class="button"
47
+ @click="viewImage(imageIframeURL[this.tooltipEntry.featureId[0]])"
48
+ >
49
+ <span>View images at this location (iFrame)</span>
50
+ </el-button>
51
+ </div>
34
52
  <div
35
53
  v-show="showDetails"
36
54
  class="hide"
@@ -53,7 +71,7 @@
53
71
  <div v-show="showDetails" class="content-container scrollbar">
54
72
  {{ tooltipEntry.paths }}
55
73
  <div v-if="tooltipEntry.origins && tooltipEntry.origins.length > 0" class="block">
56
- <div>
74
+ <div class="attribute-title-container">
57
75
  <span class="attribute-title">Origin</span>
58
76
  <el-popover
59
77
  width="250"
@@ -93,7 +111,9 @@
93
111
  v-if="tooltipEntry.components && tooltipEntry.components.length > 0"
94
112
  class="block"
95
113
  >
96
- <div class="attribute-title">Components</div>
114
+ <div class="attribute-title-container">
115
+ <div class="attribute-title">Components</div>
116
+ </div>
97
117
  <div
98
118
  v-for="(component, i) in tooltipEntry.components"
99
119
  class="attribute-content"
@@ -111,7 +131,7 @@
111
131
  v-if="tooltipEntry.destinations && tooltipEntry.destinations.length > 0"
112
132
  class="block"
113
133
  >
114
- <div>
134
+ <div class="attribute-title-container">
115
135
  <span class="attribute-title">Destination</span>
116
136
  <el-popover
117
137
  width="250"
@@ -169,6 +189,20 @@
169
189
  </template>
170
190
 
171
191
  <script>
192
+ import Gallery from "@abi-software/gallery";
193
+ import "@abi-software/gallery/dist/style.css";
194
+ import {
195
+ ArrowUp as ElIconArrowUp,
196
+ ArrowDown as ElIconArrowDown,
197
+ Warning as ElIconWarning,
198
+ } from '@element-plus/icons-vue'
199
+ /* eslint-disable no-alert, no-console */
200
+ import {
201
+ ElButton as Button,
202
+ ElContainer as Container,
203
+ ElIcon as Icon,
204
+ } from 'element-plus'
205
+
172
206
  import EventBus from "../EventBus.js";
173
207
 
174
208
  const titleCase = (str) => {
@@ -182,8 +216,41 @@ const capitalise = function (str) {
182
216
  return "";
183
217
  };
184
218
 
219
+ // TODO: temp data for testing
220
+ const galleryItems = [
221
+ {
222
+ title: 'Title 1',
223
+ type: 'data1',
224
+ userData: 'https://sparc.science/',
225
+ },
226
+ {
227
+ title: 'Title 2',
228
+ type: 'data2',
229
+ link: 'https://sparc.science/',
230
+ },
231
+ {
232
+ title: 'Title 3',
233
+ type: 'data3',
234
+ link: 'https://sparc.science/',
235
+ },
236
+ ]
237
+ const imageIframeURL = {
238
+ 'UBERON:0000948': 'https://sparc.biolucida.net/image?c=MjIzNzItY29sLTI1NA%3D%3D',
239
+ 'UBERON:0016508': 'https://sparc.biolucida.net/image?c=MjIzNzQtY29sLTI1NA%3D%3D',
240
+ 'ILX:0793082': 'https://sparc.biolucida.net/image?c=MjIzNzUtY29sLTI1NA%3D%3D'
241
+ }
242
+
185
243
  export default {
186
244
  name: "ProvenancePopup",
245
+ components: {
246
+ Button,
247
+ Container,
248
+ Icon,
249
+ ElIconArrowUp,
250
+ ElIconArrowDown,
251
+ ElIconWarning,
252
+ Gallery,
253
+ },
187
254
  props: {
188
255
  tooltipEntry: {
189
256
  type: Object,
@@ -207,6 +274,9 @@ export default {
207
274
  loading: false,
208
275
  showToolip: false,
209
276
  showDetails: false,
277
+ showImages: false,
278
+ galleryItems: galleryItems,
279
+ imageIframeURL: imageIframeURL,
210
280
  originDescriptions: {
211
281
  motor: "is the location of the initial cell body of the circuit",
212
282
  sensory: "is the location of the initial cell body in the PNS circuit",
@@ -278,6 +348,9 @@ export default {
278
348
  pubmedSearchUrlUpdate: function (val) {
279
349
  this.pubmedSearchUrl = val;
280
350
  },
351
+ viewImage: function (url) {
352
+ this.$emit('view-image', url);
353
+ },
281
354
  },
282
355
  };
283
356
  </script>
@@ -292,18 +365,18 @@ export default {
292
365
  text-align: left;
293
366
  // width: 16em;
294
367
  line-height: 1.5em !important;
295
- font-size: 1em;
368
+ font-size: 18px;
296
369
  font-family: Helvetica;
297
- font-weight: 500;
298
- /* font-weight: bold; */
370
+ font-weight: bold;
299
371
  padding-bottom: 8px;
372
+ color: $app-primary-color;
300
373
  }
301
374
 
302
375
  .block {
303
376
  margin-bottom: 0.5em;
304
377
 
305
378
  .main > &:first-of-type {
306
- margin-right: 0.5em;
379
+ margin-right: 1em;
307
380
  }
308
381
  }
309
382
 
@@ -374,12 +447,8 @@ export default {
374
447
  min-width: 16rem;
375
448
  }
376
449
 
377
- .title {
378
- font-size: 18px;
379
- font-weight: 500;
380
- font-weight: bold;
381
- padding-bottom: 8px;
382
- color: rgb(131, 0, 191);
450
+ .attribute-title-container {
451
+ margin-bottom: 0.5em;
383
452
  }
384
453
 
385
454
  .attribute-title {
@@ -392,6 +461,10 @@ export default {
392
461
  .attribute-content {
393
462
  font-size: 14px;
394
463
  font-weight: 500;
464
+
465
+ &:last-of-type {
466
+ margin-bottom: 0.5em;
467
+ }
395
468
  }
396
469
 
397
470
  .popover-container {
@@ -508,6 +581,18 @@ export default {
508
581
  background-color: #979797;
509
582
  }
510
583
 
584
+ .image-gallery-container {
585
+ :deep(.gallery) {
586
+ .gallery-strip {
587
+ padding: 1rem 0;
588
+ }
589
+
590
+ > div {
591
+ min-height: max-content !important;
592
+ }
593
+ }
594
+ }
595
+
511
596
  /* Fix for chrome bug where under triangle pops up above one on top of it */
512
597
  .selector:not(*:root),
513
598
  .tooltip-container::after {
@@ -1,24 +1,39 @@
1
1
  <template>
2
2
  <div class="tooltip-container" id="tooltip-container">
3
- <template v-if="annotationDisplay">
3
+ <template v-if="tooltipType === 'annotation' && annotationDisplay">
4
4
  <annotation-popup
5
5
  :annotationEntry="annotationEntry"
6
6
  @annotation="$emit('annotation', $event)"
7
7
  />
8
8
  </template>
9
- <template v-else>
10
- <provenance-popup :tooltipEntry="tooltipEntry" />
9
+ <template v-if="tooltipType === 'provenance'">
10
+ <provenance-popup
11
+ :tooltipEntry="tooltipEntry"
12
+ @view-image="viewImage"
13
+ />
14
+ </template>
15
+ <template v-if="tooltipType === 'image-gallery'">
16
+ <image-gallery-popup
17
+ :galleryItems="galleryItems"
18
+ @viewImage="viewImage"
19
+ />
11
20
  </template>
12
21
  </div>
13
22
  </template>
14
23
 
15
24
  <script>
25
+ import EventBus from '../EventBus.js';
26
+
16
27
  export default {
17
28
  name: "Tooltip",
18
29
  props: {
19
30
  tooltipEntry: {
20
31
  type: Object,
21
32
  },
33
+ tooltipType: {
34
+ type: String,
35
+ default: 'provenance',
36
+ },
22
37
  annotationDisplay: {
23
38
  type: Boolean,
24
39
  default: false,
@@ -26,7 +41,22 @@ export default {
26
41
  annotationEntry: {
27
42
  type: Object,
28
43
  },
44
+ galleryItems: {
45
+ type: Array,
46
+ default: () => [],
47
+ },
48
+ },
49
+ mounted: function() {
50
+ // Emit events from child components
51
+ EventBus.on("onActionClick", (data) => {
52
+ this.$emit("onActionClick", data);
53
+ });
29
54
  },
55
+ methods: {
56
+ viewImage: function (url) {
57
+ this.$emit('view-image', url)
58
+ }
59
+ }
30
60
  };
31
61
  </script>
32
62
 
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div>
2
+ <div class="selections-container">
3
3
  <el-row v-if="title">
4
4
  <el-col :span="12">
5
5
  <div class="title-text">
@@ -7,7 +7,24 @@
7
7
  </div>
8
8
  </el-col>
9
9
  </el-row>
10
- <div class="tree-container">
10
+ <div class="tree-container" ref="treeContainer">
11
+ <div :class="['tree-tooltip', tooltipAtBottom ? 'bottom' : '']" >
12
+ <el-popover
13
+ ref="tooltip"
14
+ :visible="tooltipVisible"
15
+ placement="top"
16
+ :show-arrow="false"
17
+ :teleported="false"
18
+ trigger="manual"
19
+ popper-class="tree-tooltip-popper"
20
+ virtual-triggering
21
+ :width="260"
22
+ >
23
+ <template #default>
24
+ <div class="tooltip-text">{{ tooltipLabel }}</div>
25
+ </template>
26
+ </el-popover>
27
+ </div>
11
28
  <el-tree
12
29
  ref="regionTree"
13
30
  v-loading="!isReady"
@@ -20,6 +37,8 @@
20
37
  :render-after-expand="false"
21
38
  :default-expanded-keys="expandedKeys"
22
39
  @check="checkChanged"
40
+ :indent="8"
41
+ :class="[mapType === 'flatmap' ? 'hide_grandchildren_checkbox': '']"
23
42
  >
24
43
  <template #default="{ node, data }">
25
44
  <span
@@ -30,9 +49,11 @@
30
49
  hoverItem: nodeIsHover(data),
31
50
  }"
32
51
  @click="changeActiveByNode(data)"
33
- @mouseover="changeHoverByNode(data)"
52
+ @mouseover="changeHoverByNode(data, false)"
53
+ @mouseenter="displayTooltip(node.label, true, $event)"
54
+ @mouseleave="displayTooltip('', false, $event)"
34
55
  >
35
- <div :style="getBackgroundStyles(data)">
56
+ <div :style="getBackgroundStyles(data)" class="lastChildInItem">
36
57
  {{ node.label }}
37
58
  </div>
38
59
  </span>
@@ -44,7 +65,9 @@
44
65
  hoverItem: hover.includes(data.id),
45
66
  }"
46
67
  @click="changeActiveByNode(data, true)"
47
- @mouseover="changeHoverByNode(data, true)"
68
+ @mouseover="changeHoverByNode(data, true, $event)"
69
+ @mouseenter="displayTooltip(node.label, true, $event)"
70
+ @mouseleave="displayTooltip('', false, $event)"
48
71
  >
49
72
  <el-color-picker
50
73
  v-if="data.isPrimitives"
@@ -54,10 +77,12 @@
54
77
  :popper-class="myPopperClass"
55
78
  @change="setColour(data, $event)"
56
79
  />
57
- <span>{{ node.label }}</span>
58
- <span v-if="data.isTextureSlides" class="node-options">
59
- (Texture)
60
- </span>
80
+ <div class="lastChildInItem">
81
+ <span>{{ node.label }}</span>
82
+ <span v-if="data.isTextureSlides" class="node-options">
83
+ (Texture)
84
+ </span>
85
+ </div>
61
86
  </span>
62
87
  </template>
63
88
  </el-tree>
@@ -118,6 +143,9 @@ export default {
118
143
  return {
119
144
  defaultExpandedKeys: ["All"],
120
145
  myPopperClass: "hide-scaffold-colour-popup",
146
+ tooltipVisible: false,
147
+ tooltipLabel: "",
148
+ tooltipAtBottom: false,
121
149
  };
122
150
  },
123
151
  computed: {
@@ -201,6 +229,23 @@ export default {
201
229
  this.$emit("checkChanged", node, data);
202
230
  }
203
231
  },
232
+ displayTooltip: function (tooltipLabel, visible, e) {
233
+ const hoverItem = e.target;
234
+ const containerItem = hoverItem.closest('.el-tree-node__content');
235
+ const containerItemWidth = containerItem.clientWidth;
236
+ const xOffset = containerItem.getBoundingClientRect().x;
237
+ const lastElement = containerItem.querySelector('.lastChildInItem');
238
+ let childrenWidth = 0;
239
+ if (lastElement) {
240
+ const rect = lastElement.getBoundingClientRect();
241
+ childrenWidth = rect.x + rect.width - xOffset;
242
+ }
243
+ const longLabel = childrenWidth > containerItemWidth;
244
+ this.tooltipVisible = longLabel && visible;
245
+ this.tooltipLabel = tooltipLabel;
246
+ this.tooltipAtBottom =
247
+ 0.5 > (e.layerY / this.$refs.treeContainer.clientHeight) ? true : false;
248
+ }
204
249
  },
205
250
  unmounted: function () {
206
251
  this.sortedPrimitiveGroups = undefined;
@@ -219,6 +264,10 @@ export default {
219
264
  }
220
265
  }
221
266
 
267
+ .selections-container {
268
+ padding-top: 5px;
269
+ }
270
+
222
271
  .title-text {
223
272
  width: 59px;
224
273
  height: 20px;
@@ -236,6 +285,8 @@ export default {
236
285
  background: #ffffff;
237
286
  margin-top: 6px;
238
287
  scrollbar-width: thin;
288
+ overflow: hidden;
289
+ position:relative;
239
290
 
240
291
  :deep(.el-tree) {
241
292
  max-height: 240px;
@@ -267,13 +318,15 @@ export default {
267
318
  }
268
319
  }
269
320
 
270
- :deep(
271
- .el-tree-node__children
321
+ .hide_grandchildren_checkbox {
322
+ :deep(
272
323
  .el-tree-node__children
273
- .el-tree-node__content
274
- > label.el-checkbox
275
- ) {
276
- display: none;
324
+ .el-tree-node__children
325
+ .el-tree-node__content
326
+ > label.el-checkbox
327
+ ) {
328
+ display: none;
329
+ }
277
330
  }
278
331
 
279
332
  :deep(.el-checkbox__label) {
@@ -342,4 +395,24 @@ export default {
342
395
  .node-options {
343
396
  text-align: right;
344
397
  }
398
+
399
+ :deep(.tree-tooltip-popper.el-popover) {
400
+ text-transform: none !important; // need to overide the tooltip text transform
401
+ border: 1px solid $app-primary-color;
402
+ padding: 4px;
403
+ font-size: 12px;
404
+ .el-popper__arrow {
405
+ &:before {
406
+ border-color: $app-primary-color;
407
+ background-color: #ffffff;
408
+ }
409
+ }
410
+ }
411
+
412
+ .tree-tooltip {
413
+ position:absolute;
414
+ &.bottom {
415
+ top: 70% ;
416
+ }
417
+ }
345
418
  </style>
@@ -2,5 +2,6 @@ import DrawToolbar from "./DrawToolbar/DrawToolbar.vue";
2
2
  import HelpModeDialog from "./HelpModeDialog/HelpModeDialog.vue";
3
3
  import Tooltip from "./Tooltip/Tooltip.vue";
4
4
  import TreeControls from "./TreeControls/TreeControls.vue";
5
+ import IframeImageDialog from "./ImageDialog/IframeImageDialog.vue";
5
6
 
6
- export { DrawToolbar, HelpModeDialog, Tooltip, TreeControls };
7
+ export { DrawToolbar, HelpModeDialog, Tooltip, TreeControls, IframeImageDialog };
@@ -29,9 +29,12 @@ declare module 'vue' {
29
29
  ElPopover: typeof import('element-plus/es')['ElPopover']
30
30
  ElRow: typeof import('element-plus/es')['ElRow']
31
31
  ElSelect: typeof import('element-plus/es')['ElSelect']
32
+ ElTag: typeof import('element-plus/es')['ElTag']
32
33
  ElTree: typeof import('element-plus/es')['ElTree']
33
34
  ExternalResourceCard: typeof import('./components/Tooltip/ExternalResourceCard.vue')['default']
34
35
  HelpModeDialog: typeof import('./components/HelpModeDialog/HelpModeDialog.vue')['default']
36
+ IframeImageDialog: typeof import('./components/ImageDialog/IframeImageDialog.vue')['default']
37
+ ImageGalleryPopup: typeof import('./components/Tooltip/ImageGalleryPopup.vue')['default']
35
38
  ProvenancePopup: typeof import('./components/Tooltip/ProvenancePopup.vue')['default']
36
39
  Tooltip: typeof import('./components/Tooltip/Tooltip.vue')['default']
37
40
  TreeControls: typeof import('./components/TreeControls/TreeControls.vue')['default']
@@ -0,0 +1,42 @@
1
+ export default {
2
+ // Note that the setting store is included in MapContent.vue
3
+ methods: {
4
+ findImagesForSpeciesFromGalleryItems: function (galleryItems, speciesToFind) {
5
+ let imageList = []
6
+ galleryItems.forEach((image) => {
7
+ if (image.species && image.species.length > 0) {
8
+ image.species.forEach((species) => {
9
+ if (species.species && species.species.curie === speciesToFind) {
10
+ imageList.push(image)
11
+ }
12
+ })
13
+ }
14
+ })
15
+ return imageList
16
+ },
17
+ findAllSpeciesFromGalleryItems: function (galleryItems) {
18
+ let speciesList = [];
19
+ let speciesSet = new Set();
20
+
21
+ galleryItems.forEach((image) => {
22
+ if (image.species && image.species.length > 0) {
23
+ image.species.forEach((species) => {
24
+ if (species.species) {
25
+ let ispc = species.species;
26
+ if (!speciesSet.has(ispc.curie)) {
27
+ speciesSet.add(ispc.curie);
28
+ speciesList.push({ 'taxon': ispc.curie, 'name': ispc.name, 'count': 1});
29
+ } else {
30
+ speciesList.forEach((sp) => {
31
+ if (sp.taxon === ispc.curie) sp.count++;
32
+ });
33
+ }
34
+ }
35
+ });
36
+ }
37
+ });
38
+
39
+ return speciesList;
40
+ },
41
+ }
42
+ }
package/vite.config.js CHANGED
@@ -9,7 +9,7 @@ import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
9
9
  // https://vitejs.dev/config/
10
10
  export default defineConfig({
11
11
  server: {
12
- port: 8083,
12
+ port: 8081,
13
13
  },
14
14
  plugins: [
15
15
  vue(),