@abi-software/map-utilities 1.5.0-beta.0 → 1.5.0-beta.2

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.
@@ -1,11 +1,37 @@
1
1
  <template>
2
- <div v-if="tooltipEntry" class="main" v-loading="loading">
3
- <div class="block" v-if="tooltipEntry.title">
4
- <div class="title">{{ capitalise(tooltipEntry.title) }}</div>
2
+ <div v-if="entry" class="main" v-loading="loading">
3
+ <div v-if="tooltipEntry.length > 1" class="toggle-button">
4
+ <el-popover width="auto" trigger="hover" :teleported="false">
5
+ <template #reference>
6
+ <el-button
7
+ class="button"
8
+ @click="previous"
9
+ :disabled="this.entryIndex === 0"
10
+ >
11
+ Previous
12
+ </el-button>
13
+ </template>
14
+ <span>{{ previousLabel }}</span>
15
+ </el-popover>
16
+ <el-popover width="auto" trigger="hover" :teleported="false">
17
+ <template #reference>
18
+ <el-button
19
+ class="button"
20
+ @click="next"
21
+ :disabled="this.entryIndex === this.tooltipEntry.length - 1"
22
+ >
23
+ Next
24
+ </el-button>
25
+ </template>
26
+ <span>{{ nextLabel }}</span>
27
+ </el-popover>
28
+ </div>
29
+ <div class="block" v-if="entry.title">
30
+ <div class="title">{{ capitalise(entry.title) }}</div>
5
31
  <div
6
32
  v-if="
7
- tooltipEntry.provenanceTaxonomyLabel &&
8
- tooltipEntry.provenanceTaxonomyLabel.length > 0
33
+ entry.provenanceTaxonomyLabel &&
34
+ entry.provenanceTaxonomyLabel.length > 0
9
35
  "
10
36
  class="subtitle"
11
37
  >
@@ -13,9 +39,9 @@
13
39
  </div>
14
40
  </div>
15
41
  <div class="block" v-else>
16
- <div class="title">{{ tooltipEntry.featureId }}</div>
42
+ <div class="title">{{ entry.featureId }}</div>
17
43
  </div>
18
- <div v-if="featuresAlert" class="attribute-title-container">
44
+ <div v-if="entry.featuresAlert" class="attribute-title-container">
19
45
  <span class="attribute-title">Alert</span>
20
46
  <el-popover
21
47
  width="250"
@@ -27,7 +53,7 @@
27
53
  <el-icon class="info"><el-icon-warning /></el-icon>
28
54
  </template>
29
55
  <span style="word-break: keep-all">
30
- {{ featuresAlert }}
56
+ {{ entry.featuresAlert }}
31
57
  </span>
32
58
  </el-popover>
33
59
  </div>
@@ -51,243 +77,170 @@
51
77
  </div>
52
78
  <transition name="slide-fade">
53
79
  <div v-show="showDetails" class="content-container scrollbar">
54
- {{ tooltipEntry.paths }}
55
- <div v-if="tooltipEntry.origins && tooltipEntry.origins.length > 0" class="block">
56
- <div class="attribute-title-container">
57
- <span class="attribute-title">Origin</span>
58
- <el-popover
59
- width="250"
60
- trigger="hover"
61
- :teleported="false"
62
- popper-class="popover-origin-help"
63
- >
64
- <template #reference>
65
- <el-icon class="info"><el-icon-warning /></el-icon>
66
- </template>
67
- <span style="word-break: keep-all">
68
- <i>Origin</i> {{ originDescription }}
69
- </span>
70
- </el-popover>
71
- </div>
72
- <div
73
- v-for="(origin, i) in tooltipEntry.origins"
74
- class="attribute-content"
75
- :origin-item-label="origin"
76
- :key="origin"
77
- >
78
- {{ capitalise(origin) }}
79
- <div v-if="i != tooltipEntry.origins.length - 1" class="separator"></div>
80
- </div>
81
- <el-button
82
- v-show="
83
- tooltipEntry.originsWithDatasets && tooltipEntry.originsWithDatasets.length > 0
84
- "
85
- class="button"
86
- id="open-dendrites-button"
87
- @click="openDendrites"
88
- >
89
- Explore origin data
90
- </el-button>
91
- </div>
92
- <div
93
- v-if="tooltipEntry.components && tooltipEntry.components.length > 0"
94
- class="block"
95
- >
96
- <div class="attribute-title-container">
97
- <div class="attribute-title">Components</div>
98
- </div>
99
- <div
100
- v-for="(component, i) in tooltipEntry.components"
101
- class="attribute-content"
102
- :component-item-label="component"
103
- :key="component"
104
- >
105
- {{ capitalise(component) }}
106
- <div
107
- v-if="i != tooltipEntry.components.length - 1"
108
- class="separator"
109
- ></div>
110
- </div>
111
- </div>
112
- <div
113
- v-if="tooltipEntry.destinations && tooltipEntry.destinations.length > 0"
114
- class="block"
115
- >
116
- <div class="attribute-title-container">
117
- <span class="attribute-title">Destination</span>
118
- <el-popover
119
- width="250"
120
- trigger="hover"
121
- :teleported="false"
122
- popper-class="popover-origin-help"
123
- >
124
- <template #reference>
125
- <el-icon class="info"><el-icon-warning /></el-icon>
126
- </template>
127
- <span style="word-break: keep-all">
128
- <i>Destination</i> is where the axons terminate
129
- </span>
130
- </el-popover>
131
- </div>
132
- <div
133
- v-for="(destination, i) in tooltipEntry.destinations"
134
- class="attribute-content"
135
- :destination-item-label="destination"
136
- :key="destination"
137
- >
138
- {{ capitalise(destination) }}
139
- <div
140
- v-if="i != tooltipEntry.destinations.length - 1"
141
- class="separator"
142
- ></div>
143
- </div>
144
- <el-button
145
- v-show="
146
- tooltipEntry.destinationsWithDatasets &&
147
- tooltipEntry.destinationsWithDatasets.length > 0
148
- "
149
- class="button"
150
- @click="openAxons"
151
- >
152
- Explore destination data
153
- </el-button>
154
- </div>
155
-
156
- <el-button
157
- v-show="
158
- tooltipEntry.componentsWithDatasets &&
159
- tooltipEntry.componentsWithDatasets.length > 0
160
- "
161
- class="button"
162
- @click="openAll"
163
- >
164
- Search for data on components
165
- </el-button>
166
-
167
- <external-resource-card :resources="resources" v-if="resources.length"></external-resource-card>
80
+ <connectivity-list
81
+ :key="entry.featureId[0]"
82
+ :entry="entry"
83
+ :origins="origins"
84
+ :components="components"
85
+ :destinations="destinations"
86
+ :originsWithDatasets="originsWithDatasets"
87
+ :componentsWithDatasets="componentsWithDatasets"
88
+ :destinationsWithDatasets="destinationsWithDatasets"
89
+ :availableAnatomyFacets="availableAnatomyFacets"
90
+ @connectivity-action-click="onConnectivityActionClick"
91
+ />
92
+ <external-resource-card
93
+ v-if="resources.length"
94
+ :resources="resources"
95
+ />
168
96
  </div>
169
97
  </transition>
170
98
  </div>
171
99
  </template>
172
100
 
173
101
  <script>
102
+ import {
103
+ ArrowUp as ElIconArrowUp,
104
+ ArrowDown as ElIconArrowDown,
105
+ Warning as ElIconWarning,
106
+ } from "@element-plus/icons-vue";
174
107
  import EventBus from "../EventBus.js";
175
-
176
- const titleCase = (str) => {
177
- return str.replace(/\w\S*/g, (t) => {
178
- return t.charAt(0).toUpperCase() + t.substr(1).toLowerCase();
179
- });
180
- };
181
-
182
- const capitalise = function (str) {
183
- if (str) return str.charAt(0).toUpperCase() + str.slice(1);
184
- return "";
185
- };
108
+ import ConnectivityList from "../ConnectivityList/ConnectivityList.vue";
109
+ import ExternalResourceCard from "./ExternalResourceCard.vue";
110
+ import { capitalise, titleCase } from "../utilities.js";
186
111
 
187
112
  export default {
188
113
  name: "ProvenancePopup",
114
+ components: {
115
+ ElIconArrowUp,
116
+ ElIconArrowDown,
117
+ ElIconWarning,
118
+ ConnectivityList,
119
+ ExternalResourceCard,
120
+ },
189
121
  props: {
190
122
  tooltipEntry: {
191
- type: Object,
192
- default: () => ({
193
- destinations: [],
194
- origins: [],
195
- components: [],
196
- destinationsWithDatasets: [],
197
- originsWithDatasets: [],
198
- componentsWithDatasets: [],
199
- resource: undefined,
200
- }),
123
+ type: Array,
124
+ default: [],
201
125
  },
202
126
  },
203
- inject: ["getFeaturesAlert"],
204
127
  data: function () {
205
128
  return {
206
- controller: undefined,
207
- activeSpecies: undefined,
208
- pubmedSearchUrl: "",
209
129
  loading: false,
210
- showToolip: false,
211
130
  showDetails: false,
212
131
  originDescriptions: {
213
132
  motor: "is the location of the initial cell body of the circuit",
214
133
  sensory: "is the location of the initial cell body in the PNS circuit",
215
134
  },
216
- componentsWithDatasets: [],
217
- uberons: [{ id: undefined, name: undefined }],
135
+ entryIndex: 0,
136
+ availableAnatomyFacets: [],
218
137
  };
219
138
  },
220
139
  computed: {
221
- featuresAlert() {
222
- return this.getFeaturesAlert();
140
+ entry: function () {
141
+ return this.tooltipEntry[this.entryIndex];
223
142
  },
224
- resources: function () {
225
- let resources = [];
226
- if (this.tooltipEntry && this.tooltipEntry.hyperlinks) {
227
- resources = this.tooltipEntry.hyperlinks;
143
+ previousLabel: function () {
144
+ if (this.entryIndex === 0) {
145
+ return "This is the first item. Click 'Next' to see more information.";
228
146
  }
229
- return resources;
147
+ return this.tooltipEntry[this.entryIndex - 1]?.title;
230
148
  },
231
- originDescription: function () {
232
- if (
233
- this.tooltipEntry &&
234
- this.tooltipEntry.title &&
235
- this.tooltipEntry.title.toLowerCase().includes("motor")
236
- ) {
237
- return this.originDescriptions.motor;
238
- } else {
239
- return this.originDescriptions.sensory;
149
+ nextLabel: function () {
150
+ if (this.entryIndex === this.tooltipEntry.length - 1) {
151
+ return "This is the last item. Click 'Previous' to see more information.";
240
152
  }
153
+ return this.tooltipEntry[this.entryIndex + 1]?.title;
241
154
  },
242
155
  provSpeciesDescription: function () {
243
156
  let text = "Studied in";
244
- this.tooltipEntry.provenanceTaxonomyLabel.forEach((label) => {
157
+ this.entry.provenanceTaxonomyLabel.forEach((label) => {
245
158
  text += ` ${label},`;
246
159
  });
247
160
  text = text.slice(0, -1); // remove last comma
248
161
  text += " species";
249
162
  return text;
250
163
  },
164
+ origins: function () {
165
+ return this.entry.origins;
166
+ },
167
+ components: function () {
168
+ return this.entry.components;
169
+ },
170
+ destinations: function () {
171
+ return this.entry.destinations;
172
+ },
173
+ originsWithDatasets: function () {
174
+ return this.entry.originsWithDatasets;
175
+ },
176
+ componentsWithDatasets: function () {
177
+ return this.entry.componentsWithDatasets;
178
+ },
179
+ destinationsWithDatasets: function () {
180
+ return this.entry.destinationsWithDatasets;
181
+ },
182
+ resources: function () {
183
+ return this.entry.hyperlinks;
184
+ },
185
+ },
186
+ watch: {
187
+ tooltipEntry: {
188
+ deep: true,
189
+ immediate: true,
190
+ handler: function (newVal, oldVal) {
191
+ if (newVal !== oldVal) {
192
+ this.entryIndex = 0;
193
+ }
194
+ },
195
+ },
196
+ },
197
+ mounted: function () {
198
+ this.loadAvailableAnatomyFacets();
251
199
  },
252
200
  methods: {
201
+ previous: function () {
202
+ if (this.entryIndex !== 0) {
203
+ this.entryIndex = this.entryIndex - 1;
204
+ }
205
+ },
206
+ next: function () {
207
+ if (this.entryIndex !== this.tooltipEntry.length - 1) {
208
+ this.entryIndex = this.entryIndex + 1;
209
+ }
210
+ },
253
211
  titleCase: function (title) {
254
212
  return titleCase(title);
255
213
  },
256
214
  capitalise: function (text) {
257
215
  return capitalise(text);
258
216
  },
259
- openUrl: function (url) {
260
- window.open(url, "_blank");
261
- },
262
- openAll: function () {
263
- EventBus.emit("onActionClick", {
264
- type: "Facets",
265
- labels: this.tooltipEntry.componentsWithDatasets.map((a) => a.name),
266
- });
267
- },
268
- openAxons: function () {
269
- EventBus.emit("onActionClick", {
270
- type: "Facets",
271
- labels: this.tooltipEntry.destinationsWithDatasets.map((a) => a.name),
272
- });
273
- },
274
- openDendrites: function () {
275
- EventBus.emit("onActionClick", {
276
- type: "Facets",
277
- labels: this.tooltipEntry.originsWithDatasets.map((a) => a.name),
278
- });
217
+ onConnectivityActionClick: function (data) {
218
+ EventBus.emit("onActionClick", data);
279
219
  },
280
- pubmedSearchUrlUpdate: function (val) {
281
- this.pubmedSearchUrl = val;
220
+ // Load available anatomy facets from the local storage if available.
221
+ // The data is from Algolia in Sidebar.
222
+ loadAvailableAnatomyFacets: function () {
223
+ const availableAnatomyFacets = localStorage.getItem(
224
+ "available-anatomy-facets"
225
+ );
226
+ if (availableAnatomyFacets) {
227
+ this.availableAnatomyFacets = JSON.parse(availableAnatomyFacets);
228
+ }
282
229
  },
283
230
  },
284
231
  };
285
232
  </script>
286
233
 
287
234
  <style lang="scss" scoped>
288
- .display {
289
- width: 44px;
290
- word-break: normal;
235
+ .toggle-button {
236
+ display: flex;
237
+ justify-content: space-between;
238
+
239
+ .is-disabled {
240
+ color: #fff !important;
241
+ background-color: #ac76c5 !important;
242
+ border: 1px solid #ac76c5 !important;
243
+ }
291
244
  }
292
245
 
293
246
  .title {
@@ -309,43 +262,12 @@ export default {
309
262
  }
310
263
  }
311
264
 
312
- .pub {
313
- width: 16rem;
314
- }
315
-
316
- .icon {
317
- right: 0px;
318
- position: absolute;
319
- top: 10px;
320
- }
321
-
322
- .icon:hover {
323
- cursor: pointer;
324
- }
325
-
326
- :deep(.popover-origin-help.el-popover) {
327
- text-transform: none !important; // need to overide the tooltip text transform
328
- border: 1px solid $app-primary-color;
329
- .el-popper__arrow {
330
- &:before {
331
- border-color: $app-primary-color;
332
- background-color: #ffffff;
333
- }
334
- }
335
- }
336
-
337
265
  .info {
338
266
  transform: rotate(180deg);
339
267
  color: #8300bf;
340
268
  margin-left: 8px;
341
269
  }
342
270
 
343
- .separator {
344
- width: 90%;
345
- height: 1px;
346
- background-color: #bfbec2;
347
- }
348
-
349
271
  .hide {
350
272
  color: $app-primary-color;
351
273
  cursor: pointer;
@@ -353,17 +275,6 @@ export default {
353
275
  margin-top: 3px;
354
276
  }
355
277
 
356
- .slide-fade-enter-active {
357
- transition: opacity 0.5s, transform 0.5s;
358
- }
359
- .slide-fade-leave-active {
360
- transition: opacity 0.2s, transform 0.2s;
361
- }
362
- .slide-fade-enter, .slide-fade-leave-to /* .slide-fade-leave-active in <2.1.8 */ {
363
- opacity: 0;
364
- transform: translateY(-8px);
365
- }
366
-
367
278
  .main {
368
279
  font-size: 14px;
369
280
  text-align: left;
@@ -396,11 +307,6 @@ export default {
396
307
  }
397
308
  }
398
309
 
399
- .popover-container {
400
- height: 100%;
401
- width: 100%;
402
- }
403
-
404
310
  .main {
405
311
  .el-button.is-round {
406
312
  border-radius: 4px;
@@ -416,9 +322,11 @@ export default {
416
322
  font-size: 14px !important;
417
323
  background-color: $app-primary-color;
418
324
  color: #fff;
325
+
419
326
  & + .button {
420
327
  margin-top: 10px !important;
421
328
  }
329
+
422
330
  &:hover {
423
331
  color: #fff !important;
424
332
  background: #ac76c5 !important;
@@ -426,27 +334,6 @@ export default {
426
334
  }
427
335
  }
428
336
 
429
- .tooltip-container {
430
- &::after,
431
- &::before {
432
- content: "";
433
- display: block;
434
- position: absolute;
435
- width: 0;
436
- height: 0;
437
- border-style: solid;
438
- flex-shrink: 0;
439
- }
440
- .tooltip {
441
- &::after {
442
- display: none;
443
- }
444
- &::before {
445
- display: none;
446
- }
447
- }
448
- }
449
-
450
337
  .maplibregl-popup-anchor-bottom {
451
338
  .tooltip-container {
452
339
  &::after,
@@ -454,10 +341,12 @@ export default {
454
341
  top: 100%;
455
342
  border-width: 12px;
456
343
  }
344
+
457
345
  &::after {
458
346
  margin-top: -1px;
459
347
  border-color: rgb(255, 255, 255) transparent transparent transparent;
460
348
  }
349
+
461
350
  &::before {
462
351
  margin: 0 auto;
463
352
  border-color: $app-primary-color transparent transparent transparent;
@@ -472,10 +361,12 @@ export default {
472
361
  top: -24px;
473
362
  border-width: 12px;
474
363
  }
364
+
475
365
  &::after {
476
366
  margin-top: 1px;
477
367
  border-color: transparent transparent rgb(255, 255, 255) transparent;
478
368
  }
369
+
479
370
  &::before {
480
371
  margin: 0 auto;
481
372
  border-color: transparent transparent $app-primary-color transparent;
@@ -491,6 +382,10 @@ export default {
491
382
  .block {
492
383
  padding-top: 0.5em;
493
384
  }
385
+
386
+ .connectivity-list {
387
+ padding-top: 1rem;
388
+ }
494
389
  }
495
390
 
496
391
  .scrollbar::-webkit-scrollbar-track {
@@ -509,10 +404,4 @@ export default {
509
404
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.06);
510
405
  background-color: #979797;
511
406
  }
512
-
513
- /* Fix for chrome bug where under triangle pops up above one on top of it */
514
- .selector:not(*:root),
515
- .tooltip-container::after {
516
- top: 99.4%;
517
- }
518
407
  </style>
@@ -19,14 +19,14 @@ export default {
19
19
  name: "Tooltip",
20
20
  props: {
21
21
  tooltipEntry: {
22
- type: Object,
22
+ type: Array,
23
23
  },
24
24
  annotationDisplay: {
25
25
  type: Boolean,
26
26
  default: false,
27
27
  },
28
28
  annotationEntry: {
29
- type: Object,
29
+ type: Array,
30
30
  },
31
31
  },
32
32
  mounted: function() {
@@ -1,6 +1,7 @@
1
1
  import AnnotationPopup from "./Tooltip/AnnotationPopup.vue";
2
2
  import CreateTooltipContent from "./Tooltip/CreateTooltipContent.vue";
3
3
  import ConnectivityGraph from "./ConnectivityGraph/ConnectivityGraph.vue";
4
+ import ConnectivityList from "./ConnectivityList/ConnectivityList.vue";
4
5
  import CopyToClipboard from "./CopyToClipboard/CopyToClipboard.vue";
5
6
  import DrawToolbar from "./DrawToolbar/DrawToolbar.vue";
6
7
  import HelpModeDialog from "./HelpModeDialog/HelpModeDialog.vue";
@@ -12,6 +13,7 @@ export {
12
13
  AnnotationPopup,
13
14
  CreateTooltipContent,
14
15
  ConnectivityGraph,
16
+ ConnectivityList,
15
17
  CopyToClipboard,
16
18
  DrawToolbar,
17
19
  HelpModeDialog,
@@ -4,6 +4,12 @@ const capitalise = term => {
4
4
  return term;
5
5
  };
6
6
 
7
+ const titleCase = (str) => {
8
+ return str.replace(/\w\S*/g, (t) => {
9
+ return t.charAt(0).toUpperCase() + t.substr(1).toLowerCase();
10
+ });
11
+ };
12
+
7
13
  const convertNodeToObject = (node) => {
8
14
  const obj = {};
9
15
 
@@ -50,6 +56,7 @@ const delay = (ms) => {
50
56
 
51
57
  export {
52
58
  capitalise,
59
+ titleCase,
53
60
  xmlToJSON,
54
61
  delay,
55
62
  };
@@ -10,6 +10,7 @@ declare module 'vue' {
10
10
  AnnotationPopup: typeof import('./components/Tooltip/AnnotationPopup.vue')['default']
11
11
  ConnectionDialog: typeof import('./components/DrawToolbar/ConnectionDialog.vue')['default']
12
12
  ConnectivityGraph: typeof import('./components/ConnectivityGraph/ConnectivityGraph.vue')['default']
13
+ ConnectivityList: typeof import('./components/ConnectivityList/ConnectivityList.vue')['default']
13
14
  CopyToClipboard: typeof import('./components/CopyToClipboard/CopyToClipboard.vue')['default']
14
15
  CreateTooltipContent: typeof import('./components/Tooltip/CreateTooltipContent.vue')['default']
15
16
  DrawToolbar: typeof import('./components/DrawToolbar/DrawToolbar.vue')['default']
@@ -29,6 +30,7 @@ declare module 'vue' {
29
30
  ElIconEdit: typeof import('@element-plus/icons-vue')['Edit']
30
31
  ElIconFinished: typeof import('@element-plus/icons-vue')['Finished']
31
32
  ElIconLock: typeof import('@element-plus/icons-vue')['Lock']
33
+ ElIconSearch: typeof import('@element-plus/icons-vue')['Search']
32
34
  ElIconUnlock: typeof import('@element-plus/icons-vue')['Unlock']
33
35
  ElIconWarning: typeof import('@element-plus/icons-vue')['Warning']
34
36
  ElIconZoomIn: typeof import('@element-plus/icons-vue')['ZoomIn']