@abi-software/flatmapvuer 1.5.6 → 1.6.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.
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="multi-container" ref="multiContainer">
3
- <div style="position: absolute; z-index: 10" v-if="!disableUI">
3
+ <div style="position: absolute; z-index: 100" v-if="!disableUI">
4
4
  <div class="species-display-text">Species</div>
5
5
  <el-popover
6
6
  content="Select a species"
@@ -62,6 +62,9 @@
62
62
  @resource-selected="resourceSelected"
63
63
  @ready="FlatmapReady"
64
64
  @pan-zoom-callback="panZoomCallback"
65
+ :annotationSidebar="annotationSidebar"
66
+ @annotation-open="onAnnotationOpen"
67
+ @annotation-close="onAnnotationClose"
65
68
  :connectivityInfoSidebar="connectivityInfoSidebar"
66
69
  @connectivity-info-open="onConnectivityInfoOpen"
67
70
  @connectivity-info-close="onConnectivityInfoClose"
@@ -258,6 +261,12 @@ export default {
258
261
  */
259
262
  this.$emit('pan-zoom-callback', payload)
260
263
  },
264
+ onAnnotationClose: function () {
265
+ this.$emit('annotation-close');
266
+ },
267
+ onAnnotationOpen: function (payload) {
268
+ this.$emit('annotation-open', payload);
269
+ },
261
270
  onConnectivityInfoClose: function () {
262
271
  this.$emit('connectivity-info-close');
263
272
  },
@@ -529,7 +538,7 @@ export default {
529
538
  */
530
539
  minZoom: {
531
540
  type: Number,
532
- default: 4,
541
+ default: 1,
533
542
  },
534
543
  /**
535
544
  * The option to create map on component mounted.
@@ -711,6 +720,13 @@ export default {
711
720
  type: Boolean,
712
721
  default: false,
713
722
  },
723
+ /**
724
+ * The option to show connectivity information in sidebar
725
+ */
726
+ annotationSidebar: {
727
+ type: Boolean,
728
+ default: false,
729
+ },
714
730
  },
715
731
  data: function () {
716
732
  return {
@@ -752,9 +768,6 @@ export default {
752
768
  }
753
769
 
754
770
  .select-box {
755
- width: 120px;
756
- border-radius: 4px;
757
- border: 1px solid rgb(144, 147, 153);
758
771
  background-color: var(--white);
759
772
  font-weight: 500;
760
773
  color: rgb(48, 49, 51);
@@ -766,6 +779,27 @@ export default {
766
779
  padding-top: 0.25em;
767
780
  }
768
781
  :deep() {
782
+ .el-select__wrapper {
783
+ position: relative;
784
+ width: fit-content;
785
+ box-shadow: none;
786
+ border-radius: 4px;
787
+ border: 1px solid var(--el-border-color);
788
+ &.is-focused {
789
+ border-color: $app-primary-color;
790
+ }
791
+ }
792
+ .el-select__selection {
793
+ width: fit-content;
794
+ position: relative;
795
+ }
796
+ .el-select__placeholder {
797
+ position: relative;
798
+ top: auto;
799
+ transform: none;
800
+ min-width: 80px;
801
+ width: fit-content;
802
+ }
769
803
  .el-input {
770
804
  .el-input__wrapper{
771
805
  &is-focus,
@@ -42,13 +42,14 @@
42
42
  :key="item[identifierKey]"
43
43
  :label="item[identifierKey]"
44
44
  >
45
- <div class="checkbox-container"
45
+ <div class="checkbox-container"
46
46
  @mouseenter="checkboxMouseEnterEmit(item[identifierKey], true)"
47
47
  @mouseleave="checkboxMouseEnterEmit(item[identifierKey], false)"
48
48
  >
49
49
  <el-checkbox
50
50
  class="my-checkbox"
51
51
  :label="item[identifierKey]"
52
+ :value="item[identifierKey]"
52
53
  @change="visibilityToggle(item[identifierKey], $event)"
53
54
  @click="onCheckboxNativeChange"
54
55
  :checked="!('enabled' in item) || item.enabled === true"
@@ -161,7 +162,6 @@ export default {
161
162
  // Update the stated to send to the emit
162
163
  this.$emit('checkboxMouseEnter', { key: key, value: value, selections: this.selections, checked: this.checkedItems})
163
164
  },
164
-
165
165
  handleCheckedItemsChange: function (value) {
166
166
  let checkedCount = value.length
167
167
  this.checkAll = checkedCount === this.selections.length
@@ -170,7 +170,7 @@ export default {
170
170
  this.checkedItems = val
171
171
  ? this.selections.map((a) => a[this.identifierKey])
172
172
  : []
173
-
173
+
174
174
  this.$emit('checkAll', {
175
175
  keys: this.selections.map((a) => a[this.identifierKey]),
176
176
  value: val,
@@ -187,6 +187,33 @@ export default {
187
187
  }
188
188
  return {}
189
189
  },
190
+ getState: function() {
191
+ let checkedCount = this.checkedItems.length
192
+ const checkAll = checkedCount === this.selections.length
193
+ return {
194
+ checkAll,
195
+ checked: !checkAll ? this.checkedItems : []
196
+ }
197
+ },
198
+ setState: function(state) {
199
+ this.checkAll = state.checkAll
200
+ this.checkedItems.length = 0
201
+ if (state.checked?.length) {
202
+ this.checkedItems.push(...state.checked)
203
+ this.selections.forEach((item) => {
204
+ const key = item[this.identifierKey]
205
+ this.$emit('changed', {key, value: this.checkedItems.includes(key)})
206
+ })
207
+ } else {
208
+ const keys = this.selections.map((a) => a[this.identifierKey])
209
+ let value = false
210
+ if (this.checkAll) {
211
+ value = true
212
+ this.checkedItems.push(...keys)
213
+ }
214
+ this.$emit('checkAll', { keys, value })
215
+ }
216
+ },
190
217
  hasLineStyles: function(item) {
191
218
  return 'colour' in item && this.colourStyle === 'line'
192
219
  },
@@ -311,7 +338,7 @@ export default {
311
338
 
312
339
  :deep(.el-checkbox__label) {
313
340
  padding-left: 5px;
314
- color: $app-primary-color;
341
+ color: inherit !important;
315
342
  font-size: 12px;
316
343
  font-weight: 500;
317
344
  letter-spacing: 0px;
@@ -334,10 +361,6 @@ export default {
334
361
  margin-bottom: 0;
335
362
  }
336
363
 
337
- :deep(.el-checkbox__label) {
338
- color: $app-primary-color !important;
339
- }
340
-
341
364
  .checkbox-row {
342
365
  width: 100%;
343
366
  top: 2px;
@@ -8,6 +8,7 @@ const removeDuplicates = function (arrayOfAnything) {
8
8
  }
9
9
 
10
10
  const cachedLabels = {}
11
+ const cachedTaxonLabels = [];
11
12
 
12
13
  const findTaxonomyLabel = async function (flatmapAPI, taxonomy) {
13
14
  if (cachedLabels && cachedLabels.hasOwnProperty(taxonomy)) {
@@ -35,6 +36,38 @@ const findTaxonomyLabel = async function (flatmapAPI, taxonomy) {
35
36
  })
36
37
  }
37
38
 
39
+ const findTaxonomyLabels = async function (mapImp, taxonomies) {
40
+ const intersectionTaxonomies = taxonomies.filter((taxonomy) =>
41
+ cachedTaxonLabels.some((obj) => obj.taxon === taxonomy)
42
+ );
43
+
44
+ const foundCachedTaxonLabels = cachedTaxonLabels.filter((obj) =>
45
+ intersectionTaxonomies.includes(obj.taxon)
46
+ );
47
+
48
+ const leftoverTaxonomies = taxonomies.filter((taxonomy) =>
49
+ !intersectionTaxonomies.includes(taxonomy)
50
+ );
51
+
52
+ if (!leftoverTaxonomies.length) {
53
+ return foundCachedTaxonLabels;
54
+ } else {
55
+ const entityLabels = await mapImp.queryLabels(leftoverTaxonomies);
56
+ if (entityLabels.length) {
57
+ entityLabels.forEach((entityLabel) => {
58
+ let { entity: taxon, label } = entityLabel;
59
+ if (label === 'Mammalia') {
60
+ label = 'Mammalia not otherwise specified'
61
+ }
62
+ const item = { taxon, label };
63
+ foundCachedTaxonLabels.push(item);
64
+ cachedTaxonLabels.push(item);
65
+ });
66
+ return foundCachedTaxonLabels;
67
+ }
68
+ }
69
+ }
70
+
38
71
  const inArray = function (ar1, ar2) {
39
72
  if (!ar1 || !ar2) return false
40
73
  let as1 = JSON.stringify(ar1)
@@ -54,7 +87,7 @@ let FlatmapQueries = function () {
54
87
  this.lookUp = []
55
88
  }
56
89
 
57
- this.createTooltipData = async function (eventData) {
90
+ this.createTooltipData = async function (mapImp, eventData) {
58
91
  let hyperlinks = []
59
92
  if (
60
93
  eventData.feature.hyperlinks &&
@@ -67,13 +100,12 @@ let FlatmapQueries = function () {
67
100
  let taxonomyLabel = undefined
68
101
  if (eventData.provenanceTaxonomy) {
69
102
  taxonomyLabel = []
70
- for (let i = 0; eventData.provenanceTaxonomy.length > i; i++) {
71
- taxonomyLabel.push(
72
- await findTaxonomyLabel(
73
- this.flatmapAPI,
74
- eventData.provenanceTaxonomy[i]
75
- )
76
- )
103
+ const entityLabels = await findTaxonomyLabels(mapImp, eventData.provenanceTaxonomy);
104
+ if (entityLabels.length) {
105
+ entityLabels.forEach((entityLabel) => {
106
+ const { label } = entityLabel;
107
+ taxonomyLabel.push(label);
108
+ });
77
109
  }
78
110
  }
79
111
 
@@ -104,33 +136,22 @@ let FlatmapQueries = function () {
104
136
  return labelList
105
137
  }
106
138
 
107
- this.createLabelLookup = function (uberons) {
108
- return new Promise((resolve) => {
139
+ this.createLabelLookup = function (mapImp, uberons) {
140
+ return new Promise(async (resolve) => {
109
141
  let uberonMap = {}
110
142
  this.uberons = []
111
- const data = { sql: this.buildLabelSqlStatement(uberons) }
112
- fetch(`${this.flatmapApi}knowledge/query/`, {
113
- method: 'POST',
114
- headers: {
115
- 'Content-Type': 'application/json',
116
- },
117
- body: JSON.stringify(data),
118
- })
119
- .then((response) => response.json())
120
- .then((payload) => {
121
- const entity = payload.keys.indexOf('entity')
122
- const label = payload.keys.indexOf('label')
123
- if (entity > -1 && label > -1) {
124
- payload.values.forEach((pair) => {
125
- uberonMap[pair[entity]] = pair[label]
126
- this.uberons.push({
127
- id: pair[entity],
128
- name: pair[label],
129
- })
130
- })
131
- }
132
- resolve(uberonMap)
133
- })
143
+ const entityLabels = await findTaxonomyLabels(mapImp, uberons);
144
+ if (entityLabels.length) {
145
+ entityLabels.forEach((entityLabel) => {
146
+ const { taxon: entity, label } = entityLabel;
147
+ uberonMap[entity] = label;
148
+ this.uberons.push({
149
+ id: entity,
150
+ name: label,
151
+ })
152
+ });
153
+ resolve(uberonMap)
154
+ }
134
155
  })
135
156
  }
136
157
 
@@ -198,6 +219,9 @@ let FlatmapQueries = function () {
198
219
  if (inArray(connectivity.axons, node)) {
199
220
  terminal = true
200
221
  }
222
+ if (connectivity.somas && inArray(connectivity.somas, node)) {
223
+ terminal = true
224
+ }
201
225
  if (inArray(connectivity.dendrites, node)) {
202
226
  terminal = true
203
227
  }
@@ -209,7 +233,7 @@ let FlatmapQueries = function () {
209
233
  return found
210
234
  }
211
235
 
212
- this.retrieveFlatmapKnowledgeForEvent = async function (eventData) {
236
+ this.retrieveFlatmapKnowledgeForEvent = async function (mapImp, eventData) {
213
237
  // check if there is an existing query
214
238
  if (this.controller) this.controller.abort()
215
239
 
@@ -221,15 +245,58 @@ let FlatmapQueries = function () {
221
245
  this.destinations = []
222
246
  this.origins = []
223
247
  this.components = []
224
- if (!keastIds || keastIds.length == 0) return
248
+ this.urls = []
249
+ if (!keastIds || keastIds.length == 0 || !keastIds[0]) return
225
250
 
226
- let prom1 = this.queryForConnectivity(keastIds, signal) // This on returns a promise so dont need 'await'
227
- let prom2 = await this.pubmedQueryOnIds(eventData)
228
- let results = await Promise.all([prom1, prom2])
251
+ let prom1 = this.queryForConnectivityNew(mapImp, keastIds, signal) // This on returns a promise so dont need 'await'
252
+ // let prom2 = await this.pubmedQueryOnIds(eventData)
253
+ let results = await Promise.all([prom1])
229
254
  return results
230
255
  }
231
256
 
232
- this.queryForConnectivity = function (keastIds, signal, processConnectivity=true) {
257
+ this.queryForConnectivityNew = function (mapImp, keastIds, signal, processConnectivity=true) {
258
+ return new Promise((resolve) => {
259
+ mapImp.queryKnowledge(keastIds[0])
260
+ .then((response) => {
261
+ if (this.checkConnectivityExists(response)) {
262
+ let connectivity = response;
263
+ if (processConnectivity) {
264
+ this.processConnectivity(mapImp, connectivity).then((processedConnectivity) => {
265
+ // response.references is publication urls
266
+ if (response.references) {
267
+ // with publications
268
+ this.getURLsForPubMed(response.references).then((urls) => {
269
+ // TODO: if empty urls array is returned,
270
+ // the urls are not on PubMed.
271
+ // Those urls, response.references, will be shown in another way.
272
+ this.urls = urls;
273
+ resolve(processedConnectivity)
274
+ })
275
+ } else {
276
+ // without publications
277
+ resolve(processedConnectivity)
278
+ }
279
+ })
280
+ }
281
+ else resolve(connectivity)
282
+ } else {
283
+ resolve(false)
284
+ }
285
+ })
286
+ .catch((error) => {
287
+ if (error.name === 'AbortError') {
288
+ // This error is from AbortController's abort method.
289
+ } else {
290
+ // console.error('Error:', error)
291
+ // TODO: to update after queryKnowledge method update
292
+ console.warn(`Unable to get the knowledge for the entity ${keastIds[0]}.`)
293
+ }
294
+ resolve(false)
295
+ })
296
+ })
297
+ }
298
+
299
+ this.queryForConnectivity = function (mapImp, keastIds, signal, processConnectivity=true) {
233
300
  const data = { sql: this.buildConnectivitySqlStatement(keastIds) }
234
301
  const headers = {
235
302
  method: 'POST',
@@ -246,7 +313,7 @@ let FlatmapQueries = function () {
246
313
  if (this.connectivityExists(data)) {
247
314
  let connectivity = JSON.parse(data.values[0][0])
248
315
  if (processConnectivity) {
249
- this.processConnectivity(connectivity).then((processedConnectivity) => {
316
+ this.processConnectivity(mapImp, connectivity).then((processedConnectivity) => {
250
317
  resolve(processedConnectivity)
251
318
  })
252
319
  }
@@ -266,6 +333,10 @@ let FlatmapQueries = function () {
266
333
  })
267
334
  }
268
335
 
336
+ this.checkConnectivityExists = function (data) {
337
+ return data && data.connectivity?.length;
338
+ };
339
+
269
340
  this.connectivityExists = function (data) {
270
341
  if (
271
342
  data.values &&
@@ -336,20 +407,28 @@ let FlatmapQueries = function () {
336
407
  )
337
408
  }
338
409
 
339
- this.processConnectivity = function (connectivity) {
410
+ this.processConnectivity = function (mapImp, connectivity) {
340
411
  return new Promise((resolve) => {
341
412
  // Filter the origin and destinations from components
342
413
  let components = this.findComponents(connectivity)
343
414
 
344
415
  // Remove duplicates
345
416
  let axons = removeDuplicates(connectivity.axons)
346
- let dendrites = removeDuplicates(connectivity.dendrites)
417
+ //Somas will become part of origins, support this for future proof
418
+ let dendrites = []
419
+ if (connectivity.somas && connectivity.somas.length > 0) {
420
+ dendrites.push(...connectivity.somas)
421
+ }
422
+ if (connectivity.dendrites && connectivity.dendrites.length > 0) {
423
+ dendrites.push(...connectivity.dendrites)
424
+ }
425
+ dendrites = removeDuplicates(dendrites)
347
426
 
348
427
  // Create list of ids to get labels for
349
428
  let conIds = this.findAllIdsFromConnectivity(connectivity)
350
429
 
351
430
  // Create readable labels from the nodes. Setting this to 'this.origins' updates the display
352
- this.createLabelLookup(conIds).then((lookUp) => {
431
+ this.createLabelLookup(mapImp, conIds).then((lookUp) => {
353
432
  this.destinations = axons.map((a) =>
354
433
  this.createLabelFromNeuralNode(a, lookUp)
355
434
  )
@@ -500,7 +579,11 @@ let FlatmapQueries = function () {
500
579
 
501
580
  this.getURLsForPubMed = function (data) {
502
581
  return new Promise((resolve) => {
503
- const ids = data.values.map((id) => this.extractPublicationIdFromURLString(id[0]))
582
+ const ids = data.map((id) =>
583
+ (typeof id === 'object') ?
584
+ this.extractPublicationIdFromURLString(id[0]) :
585
+ this.extractPublicationIdFromURLString(id)
586
+ )
504
587
  this.convertPublicationIds(ids).then((pmids) => {
505
588
  if (pmids.length > 0) {
506
589
  const transformedIDs = pmids.join()
@@ -552,7 +635,7 @@ let FlatmapQueries = function () {
552
635
  this.flatmapQuery(sql).then((data) => {
553
636
  // Create pubmed url on paths if we have them
554
637
  if (data.values.length > 0) {
555
- this.getURLsForPubMed(data).then((urls) => {
638
+ this.getURLsForPubMed(data.values).then((urls) => {
556
639
  this.urls = urls
557
640
  if (urls.length) {
558
641
  resolve(true)
@@ -579,7 +662,7 @@ let FlatmapQueries = function () {
579
662
  this.buildPubmedSqlStatementForModels(source)
580
663
  ).then((data) => {
581
664
  if (Array.isArray(data.values) && data.values.length > 0) {
582
- this.getURLsForPubMed(data).then((urls) => {
665
+ this.getURLsForPubMed(data.values).then((urls) => {
583
666
  this.urls = urls
584
667
  return true
585
668
  })
@@ -602,4 +685,4 @@ let FlatmapQueries = function () {
602
685
  }
603
686
  }
604
687
 
605
- export { FlatmapQueries, findTaxonomyLabel }
688
+ export { FlatmapQueries, findTaxonomyLabel, findTaxonomyLabels }