@abi-software/mapintegratedvuer 1.9.0-beta.0 → 1.9.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.
@@ -9,6 +9,9 @@ import { useSettingsStore } from '../stores/settings';
9
9
  import { useSplitFlowStore } from '../stores/splitFlow';
10
10
  import Tagging from '../services/tagging.js';
11
11
 
12
+ import { FlatmapQueries } from "@abi-software/flatmapvuer/src/services/flatmapQueries.js";
13
+ import { getKnowledgeSource, loadAndStoreKnowledge } from "@abi-software/flatmapvuer/src/services/flatmapKnowledge.js";
14
+
12
15
  function capitalise(text) {
13
16
  return text[0].toUpperCase() + text.substring(1)
14
17
  }
@@ -73,8 +76,6 @@ export default {
73
76
  EventBus.emit("OpenNewMap", type);
74
77
  this.trackOpenMap(`open_new_${type}_map`);
75
78
  }
76
-
77
- this.onConnectivityInfoClose();
78
79
  },
79
80
  onMapmanagerLoaded: function (mapManager) {
80
81
  this.settingsStore.updateMapManager(mapManager);
@@ -107,7 +108,8 @@ export default {
107
108
  /**
108
109
  * Callback when the vuers emit a selected event.
109
110
  */
110
- resourceSelected: function (type, resource) {
111
+ resourceSelected: function (type, resources) {
112
+ const resource = resources[0]
111
113
  // Skip processing if resources already has actions
112
114
  if (this.resourceHasAction(resource)) {
113
115
  EventBus.emit("PopoverActionClick", resource);
@@ -120,29 +122,23 @@ export default {
120
122
  const result = {
121
123
  paneIndex: this.entry.id,
122
124
  type: type,
123
- resource: resource,
125
+ resource: resources,
124
126
  internalName: undefined,
125
127
  eventType: undefined,
126
128
  };
127
129
 
128
-
129
130
  if (type == "MultiFlatmap" || type == "Flatmap") {
130
- result.internalName = resource?.feature?.label ? resource.feature.label : this.idNamePair[resource.feature.models];
131
+ result.internalName = resource?.feature?.label ?
132
+ resource.feature.label : this.idNamePair[resource.feature.models];
131
133
  if (resource.eventType == "click") {
132
134
  result.eventType = "selected";
133
135
  if (resource.feature.type == "marker") {
134
136
  let label = result.internalName;
135
- if (
136
- this.settingsStore.isFeaturedMarkerIdentifier(
137
- resource.feature.id
138
- )
139
- ) {
137
+ if (this.settingsStore.isFeaturedMarkerIdentifier(resource.feature.id)) {
140
138
  // It is a featured dataset search for DOI.
141
139
  returnedAction = {
142
140
  type: "Search",
143
- term: this.settingsStore.featuredMarkerDoi(
144
- resource.feature.id
145
- ),
141
+ term: this.settingsStore.featuredMarkerDoi(resource.feature.id),
146
142
  featuredDataset: true,
147
143
  };
148
144
  } else {
@@ -151,14 +147,25 @@ export default {
151
147
  type: "Facet",
152
148
  facet: label,
153
149
  facetPropPath: "anatomy.organ.category.name",
150
+ facetSubPropPath: "anatomy.organ.name",
154
151
  term: "Anatomical structure",
155
152
  };
153
+ let labels = new Set();
154
+ resource.feature['marker-terms'].forEach((term) => {
155
+ labels.add(term.label)
156
+ });
157
+ labels.add(label)
158
+ if (labels.size > 0) {
159
+ returnedAction = {
160
+ type: "Facets",
161
+ labels: [...labels],
162
+ };
163
+ }
156
164
  }
157
165
 
158
166
  fireResourceSelected = true;
159
167
  if (type == "MultiFlatmap") {
160
- const flatmap =
161
- this.$refs.multiflatmap.getCurrentFlatmap().mapImp;
168
+ const flatmap = this.$refs.multiflatmap.getCurrentFlatmap().mapImp;
162
169
  flatmap.clearSearchResults();
163
170
  }
164
171
  } else if (resource.feature.type == "feature") {
@@ -174,16 +181,16 @@ export default {
174
181
  fireResourceSelected = true;
175
182
  }
176
183
  } else if (type == "Scaffold") {
177
- if (resource && resource[0]) {
178
- if (resource[0].data?.id === undefined || resource[0].data?.id === "") {
179
- resource[0].data.id = resource[0].data?.group;
184
+ if (resource) {
185
+ if (resource.data?.id === undefined || resource.data?.id === "") {
186
+ resource.data.id = resource.data?.group;
180
187
  }
181
- result.internalName = resource[0].data.id;
188
+ result.internalName = resource.data.id;
182
189
  // Facet search if marker is clicked
183
- if (resource[0].data.lastActionOnMarker === true) {
190
+ if (resource.data.lastActionOnMarker === true) {
184
191
  returnedAction = {
185
192
  type: "Facet",
186
- facet: capitalise(resource[0].data.id),
193
+ facet: capitalise(resource.data.id),
187
194
  facetPropPath: "anatomy.organ.category.name",
188
195
  term: "Anatomical structure",
189
196
  };
@@ -458,76 +465,69 @@ export default {
458
465
  this.endHelp();
459
466
  }
460
467
  },
461
- getConnectivitiesByDOI: async function (hoverDOI) {
462
- const currentFlatmap = this.$refs.multiflatmap.getCurrentFlatmap();
463
- const response = await currentFlatmap.searchConnectivitiesByReference(hoverDOI);
464
- return response;
465
- },
466
- highlightAnatomies: async function (mapImp, hoverAnatomies, hoverDOI) {
467
- const itemsToHighlight = [...hoverAnatomies];
468
- const hoverHighlightOptions = this.settingsStore.hoverHighlightOptions;
468
+ flatmapHighlight: async function (flatmap, hoverAnatomies, hoverDOI, hoverConnectivity) {
469
+ let toHighlight = [...hoverAnatomies, ...hoverConnectivity];
470
+ const globalSettings = this.settingsStore.globalSettings;
469
471
 
470
472
  // to highlight connected paths
471
- if (hoverHighlightOptions.highlightConnectedPaths) {
472
- const connectionsFromFeatures = await mapImp.queryPathsForFeatures(hoverAnatomies);
473
- if (connectionsFromFeatures) {
474
- itemsToHighlight.push(...connectionsFromFeatures);
473
+ if (globalSettings.highlightConnectedPaths) {
474
+ const hoverEntry = hoverAnatomies.length ? hoverAnatomies :
475
+ hoverConnectivity.length ? hoverConnectivity :
476
+ []
477
+ const connectedPaths = await flatmap.retrieveConnectedPaths(hoverEntry);
478
+ if (connectedPaths) {
479
+ toHighlight.push(...connectedPaths);
475
480
  }
476
481
  }
477
482
 
478
483
  // to highlight related paths from reference DOI
479
- if (hoverHighlightOptions.highlightDOIPaths) {
480
- const connectionsFromDOI = await this.getConnectivitiesByDOI(hoverDOI);
484
+ if (globalSettings.highlightDOIPaths) {
485
+ const connectionsFromDOI = await flatmap.searchConnectivitiesByReference(hoverDOI);
481
486
  if (connectionsFromDOI) {
482
- itemsToHighlight.push(...connectionsFromDOI);
487
+ toHighlight.push(...connectionsFromDOI);
483
488
  }
484
489
  }
485
-
486
- return itemsToHighlight;
490
+ toHighlight = [...new Set(toHighlight)];
491
+ return toHighlight;
487
492
  },
488
- mapHoverHighlight: function () {
493
+ cardHoverHighlight: function () {
489
494
  if (this.visible) {
490
495
  const hoverAnatomies = this.settingsStore.hoverAnatomies;
491
496
  const hoverOrgans = this.settingsStore.hoverOrgans;
492
497
  const hoverDOI = this.settingsStore.hoverDOI;
493
- let mapImp = null;
494
- let scaffold = null;
498
+ const hoverConnectivity = this.settingsStore.hoverConnectivity;
495
499
 
496
- if (this.flatmapRef) {
497
- mapImp = this.$refs.flatmap.mapImp;
498
- }
499
-
500
- if (this.multiflatmapRef) {
501
- mapImp = this.$refs.multiflatmap.getCurrentFlatmap().mapImp;
502
- }
503
-
504
- if (this.scaffoldRef) {
505
- scaffold = this.$refs.scaffold;
506
- }
500
+ let flatmap = null;
501
+ let scaffold = null;
502
+ if (this.flatmapRef) flatmap = this.flatmapRef;
503
+ if (this.multiflatmapRef) flatmap = this.multiflatmapRef.getCurrentFlatmap();
504
+ if (this.scaffoldRef) scaffold = this.scaffoldRef;
507
505
 
508
506
  // reset
509
- if (mapImp) {
510
- mapImp.clearSearchResults();
507
+ clearTimeout(this.highlightDelay);
508
+ if (!hoverAnatomies.length && !hoverOrgans.length && !hoverDOI && !hoverConnectivity.length) {
509
+ if ((this.multiflatmapRef || this.flatmapRef) && flatmap) {
510
+ flatmap.mapImp?.clearSearchResults();
511
+ } else if (this.scaffoldRef && scaffold) {
512
+ scaffold.changeHighlightedByName(hoverOrgans, "", false);
513
+ }
511
514
  }
512
515
 
513
- if (hoverAnatomies.length || hoverOrgans.length) {
514
- clearTimeout(this.hoverDelay);
515
- if (this.multiflatmapRef || this.flatmapRef) {
516
- this.highlightAnatomies(mapImp, hoverAnatomies, hoverDOI).then((itemsToHighlight) => {
517
- mapImp.selectFeatures(itemsToHighlight);
518
- });
519
- } else if (this.scaffoldRef) {
520
- scaffold?.changeHighlightedByName(hoverOrgans, "", false);
521
- }
522
- } else {
523
- this.hoverDelay = setTimeout(() => {
524
- if (this.multiflatmapRef || this.flatmapRef) {
525
- mapImp?.clearSearchResults();
526
- } else if (this.scaffoldRef) {
527
- scaffold?.changeHighlightedByName(hoverOrgans, "", false);
516
+ this.highlightDelay = setTimeout(() => {
517
+ if (hoverAnatomies.length || hoverOrgans.length || hoverDOI || hoverConnectivity.length) {
518
+ if ((this.multiflatmapRef || this.flatmapRef) && flatmap) {
519
+ this.flatmapHighlight(flatmap, hoverAnatomies, hoverDOI, hoverConnectivity).then((paths) => {
520
+ try {
521
+ flatmap.zoomToFeatures(paths);
522
+ } catch (error) {
523
+ console.log(error)
524
+ }
525
+ });
526
+ } else if (this.scaffoldRef && scaffold) {
527
+ scaffold.changeHighlightedByName(hoverOrgans, "", false);
528
528
  }
529
- }, 500);
530
- }
529
+ }
530
+ }, 100);
531
531
  }
532
532
  },
533
533
  onAnnotationOpen: function (payload) {
@@ -539,12 +539,72 @@ export default {
539
539
  onConnectivityInfoOpen: function (connectivityInfoData) {
540
540
  EventBus.emit('connectivity-info-open', connectivityInfoData);
541
541
  },
542
- onConnectivityInfoClose: function () {
543
- EventBus.emit('connectivity-info-close');
544
- },
545
542
  onConnectivityGraphError: function (errorInfo) {
546
543
  EventBus.emit('connectivity-graph-error', errorInfo);
547
544
  },
545
+ loadConnectivityKnowledge: async function (flatmap) {
546
+ const sckanVersion = getKnowledgeSource(flatmap);
547
+ const flatmapQueries = markRaw(new FlatmapQueries());
548
+ flatmapQueries.initialise(this.flatmapAPI);
549
+ const knowledge = await loadAndStoreKnowledge(flatmap, flatmapQueries);
550
+ const uuid = flatmap.uuid;
551
+ const mapPathsData = await flatmapQueries.queryMapPaths(uuid);
552
+ const pathsFromMap = mapPathsData ? mapPathsData.paths : {};
553
+
554
+ this.connectivityKnowledge[uuid] = knowledge.filter((item) => {
555
+ if (item.source === sckanVersion && item.connectivity?.length && item.id in pathsFromMap) {
556
+ return true;
557
+ }
558
+ return false;
559
+ });
560
+ EventBus.emit("connectivity-knowledge", { type: "default", data: this.connectivityKnowledge[uuid] });
561
+ },
562
+ getSearchedId: function (flatmap, term) {
563
+ let ids = [];
564
+ const searchResult = flatmap.mapImp.search(term);
565
+ const featureIds = searchResult.__featureIds || searchResult.featureIds;
566
+ featureIds.forEach((id) => {
567
+ const annotation = flatmap.mapImp.annotation(id);
568
+ if (
569
+ annotation.label?.toLowerCase().includes(term.toLowerCase()) &&
570
+ annotation.models && !ids.includes(annotation.models)
571
+ ) {
572
+ ids.push(annotation.models);
573
+ }
574
+ });
575
+ return ids;
576
+ },
577
+ connectivityQueryFilter: async function (flatmap, data) {
578
+ const uuid = flatmap.mapImp.uuid
579
+ let payload = {
580
+ state: "default",
581
+ data: [...this.connectivityKnowledge[uuid]],
582
+ };
583
+ if (data) {
584
+ if (data.type === "query-update") {
585
+ if (this.query !== data.value) this.target = [];
586
+ this.query = data.value;
587
+ } else if (data.type === "filter-update") {
588
+ this.filter = data.value;
589
+ }
590
+ }
591
+ if (this.query) {
592
+ payload.state = "processed";
593
+ let prom1 = [], options = {};
594
+ const searchTerms = this.query.split(",").map((term) => term.trim());
595
+ for (let index = 0; index < searchTerms.length; index++) {
596
+ prom1.push(this.getSearchedId(flatmap, searchTerms[index]));
597
+ }
598
+ const nestedIds = await Promise.all(prom1);
599
+ const ids = [...new Set(nestedIds.flat())];
600
+ let paths = await flatmap.retrieveConnectedPaths(ids, options);
601
+ paths = [...ids, ...paths.filter((path) => !ids.includes(path))];
602
+ let results = this.connectivityKnowledge[uuid].filter((item) => paths.includes(item.id));
603
+ results.sort((a, b) => paths.indexOf(a.id) - paths.indexOf(b.id));
604
+ payload.data = results;
605
+ }
606
+ EventBus.emit("connectivity-knowledge", payload);
607
+ }
548
608
  },
549
609
  data: function () {
550
610
  return {
@@ -564,8 +624,11 @@ export default {
564
624
  scaffoldRef: null,
565
625
  scaffoldLoaded: false,
566
626
  isInHelp: false,
567
- hoverDelay: undefined,
568
627
  mapManager: undefined,
628
+ connectivityKnowledge: {},
629
+ query: "",
630
+ filter: [],
631
+ highlightDelay: undefined
569
632
  };
570
633
  },
571
634
  created: function () {
@@ -40,7 +40,7 @@ export default {
40
40
 
41
41
  if (flatmapImp) {
42
42
  // Set the dataset markers
43
- let markers = this.settingsStore.globalSettings.displayMarker ? this.settingsStore.markers : [];
43
+ let markers = this.settingsStore.globalSettings.displayMarkers ? this.settingsStore.markers : [];
44
44
  markers = removeDuplicates(markers);
45
45
  let fmMarkers = this.removeMarkersNotOnFlatmap(flatmapImp, markers);
46
46
  flatmapImp.clearMarkers();
@@ -21,6 +21,7 @@ export const useSettingsStore = defineStore('settings', {
21
21
  hoverAnatomies: [],
22
22
  hoverOrgans: [],
23
23
  hoverDOI: '',
24
+ hoverConnectivity: [],
24
25
  featuredMarkers: [],
25
26
  featuredMarkerIdentifiers: [],
26
27
  featuredMarkerDois: [],
@@ -30,12 +31,12 @@ export const useSettingsStore = defineStore('settings', {
30
31
  useHelpModeDialog: false,
31
32
  connectivityInfoSidebar: true,
32
33
  annotationSidebar: true,
33
- hoverHighlightOptions: {
34
- highlightConnectedPaths: false,
35
- highlightDOIPaths: false,
36
- },
34
+ allClosable: true,
37
35
  globalSettings: {
38
- displayMarker: true,
36
+ displayMarkers: true,
37
+ highlightConnectedPaths: false,
38
+ highlightDOIPaths: false, // comment out to hide in settings
39
+ interactiveMode: 'dataset', // dataset, connectivity, multiscale
39
40
  },
40
41
  }
41
42
  },
@@ -53,7 +54,7 @@ export const useSettingsStore = defineStore('settings', {
53
54
  let updatedSettings = [];
54
55
  for (const [key, value] of Object.entries(settings)) {
55
56
  const attribute = state.globalSettings[key];
56
- if (!attribute || (attribute !== value)) {
57
+ if (attribute === undefined || (attribute !== value)) {
57
58
  updatedSettings.push(key);
58
59
  }
59
60
  }
@@ -94,10 +95,11 @@ export const useSettingsStore = defineStore('settings', {
94
95
  updateMarkers(markers) {
95
96
  this.markers = markers;
96
97
  },
97
- updateHoverFeatures(anatomies, organs, doi) {
98
+ updateHoverFeatures(anatomies, organs, doi, connectivity) {
98
99
  this.hoverAnatomies = anatomies;
99
100
  this.hoverOrgans = organs;
100
101
  this.hoverDOI = doi;
102
+ this.hoverConnectivity = connectivity;
101
103
  },
102
104
  updateFeatured(datasetIdentifiers) {
103
105
  this.featuredMarkerIdentifiers = new Array(datasetIdentifiers.length);
@@ -181,8 +183,8 @@ export const useSettingsStore = defineStore('settings', {
181
183
  updateAnnotationSidebar(annotationSidebar) {
182
184
  this.annotationSidebar = annotationSidebar;
183
185
  },
184
- updateHoverHighlightOptions(hoverHighlightOptions) {
185
- this.hoverHighlightOptions = hoverHighlightOptions;
186
+ updateAllClosable(allClosable) {
187
+ this.allClosable = allClosable;
186
188
  },
187
189
  updateGlobalSettings(globalSettings) {
188
190
  for (const [key, value] of Object.entries(globalSettings)) {
@@ -105,6 +105,7 @@ const autoAssignEntryIdsToPane = (entries, layout) => {
105
105
  }
106
106
  }
107
107
  });
108
+
108
109
  }
109
110
 
110
111
  const extractPaneInfo = (layout) => {
@@ -208,7 +209,6 @@ export const useSplitFlowStore = defineStore('splitFlow', {
208
209
  if (this._controller) this._controller.abort();
209
210
  this._controller = new AbortController();
210
211
  let signal = this._controller.signal;
211
- // console.log("getAvailableTerms")
212
212
  fetch(`${apiLocation}get-organ-curies`, {
213
213
  signal,
214
214
  })
@@ -325,12 +325,12 @@ export const useSplitFlowStore = defineStore('splitFlow', {
325
325
  //Extract pane info form original state and copy to the new layout
326
326
  const customLayout = newLayoutWithOrigInfo(
327
327
  this.customLayout, this.activeView);
328
- const originalKey = findKeyWithId(customLayout, 1);
328
+ const originalKey = findKeyWithId(customLayout, payload.id);
329
329
  const firstPaneId = customLayout["pane-1"].id;
330
330
  if (originalKey !== "pane-1") {
331
331
  customLayout["pane-1"].id = firstPaneId;
332
332
  }
333
- customLayout["pane-1"].id = 1;
333
+ customLayout["pane-1"].id = payload.id;
334
334
  customLayout["pane-2"].id = payload.newId;
335
335
  for (const [key, value] of Object.entries(customLayout)) {
336
336
  this.customLayout[key] = value;
@@ -362,14 +362,12 @@ export const useSplitFlowStore = defineStore('splitFlow', {
362
362
  this.syncMode = false;
363
363
  this.globalCallback = false;
364
364
  let availableId = 0;
365
- //Primary id cannot be changed
366
- if (payload.id === 1) {
367
- availableId = 1;
368
- } else if (payload.entries) {
365
+ if (payload.entries) {
369
366
  for (let i = 0; i < payload.entries.length &&
370
367
  availableId == 0; i++) {
371
368
  //Find the first entry not currently in use
372
- if (findKeyWithId(payload.entries[i].id) === undefined) {
369
+ if ((payload.entries[i].id !== payload.id) &&
370
+ findKeyWithId(payload.entries[i].id) === undefined) {
373
371
  availableId = payload.entries[i].id;
374
372
  }
375
373
  }
@@ -402,7 +400,6 @@ export const useSplitFlowStore = defineStore('splitFlow', {
402
400
  const customLayout = newLayoutWithOrigInfo(
403
401
  this.customLayout, this.activeView);
404
402
  const key = findKeyWithId(customLayout, payload.id);
405
-
406
403
  // The following move the entry id to the appropriate slot
407
404
  // and remove the target id
408
405
  switch (key) {