@abi-software/flatmapvuer 1.10.2 → 1.10.3-beta.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/flatmapvuer",
3
- "version": "1.10.2",
3
+ "version": "1.10.3-beta.0",
4
4
  "license": "Apache-2.0",
5
5
  "files": [
6
6
  "dist/*",
@@ -44,7 +44,7 @@
44
44
  "./src/*": "./src/*"
45
45
  },
46
46
  "dependencies": {
47
- "@abi-software/map-utilities": "^1.6.0",
47
+ "@abi-software/map-utilities": "^1.6.1-beta.1",
48
48
  "@abi-software/sparc-annotation": "0.3.2",
49
49
  "@abi-software/svg-sprite": "^1.0.1",
50
50
  "@element-plus/icons-vue": "^2.3.1",
@@ -633,6 +633,9 @@ import {
633
633
  refreshFlatmapKnowledgeCache,
634
634
  getKnowledgeSource,
635
635
  getReferenceConnectivitiesByAPI,
636
+ filterPathsByOriginFromKnowledge,
637
+ filterPathsByDestinationFromKnowledge,
638
+ filterPathsByViaFromKnowledge,
636
639
  } from '../services/flatmapKnowledge.js'
637
640
  import { capitalise } from './utilities.js'
638
641
  import yellowstar from '../icons/yellowstar'
@@ -641,7 +644,19 @@ import * as flatmap from 'https://cdn.jsdelivr.net/npm/@abi-software/flatmap-vie
641
644
  import { AnnotationService } from '@abi-software/sparc-annotation'
642
645
  import { mapState } from 'pinia'
643
646
  import { useMainStore } from '@/store/index'
644
- import { DrawToolbar, Tooltip, TreeControls } from '@abi-software/map-utilities'
647
+ import {
648
+ queryPathsByOrigin,
649
+ queryPathsByViaLocation,
650
+ queryPathsByDestination,
651
+ extractOriginItems,
652
+ extractDestinationItems,
653
+ extractViaItems,
654
+ fetchLabels,
655
+ queryAllConnectedPaths,
656
+ DrawToolbar,
657
+ Tooltip,
658
+ TreeControls
659
+ } from '@abi-software/map-utilities'
645
660
  import '@abi-software/map-utilities/dist/style.css'
646
661
  import EventBus from './EventBus.js'
647
662
 
@@ -740,8 +755,13 @@ export default {
740
755
  return { annotator }
741
756
  },
742
757
  methods: {
758
+ enableFeatureResetOnClick: function (enable) {
759
+ if (this.mapImp) {
760
+ this.mapImp.enableFeatureResetOnClick(enable)
761
+ }
762
+ },
743
763
  /**
744
- *
764
+ *
745
765
  * @param filter format should follow #makeStyleFilter (flatmap-viewer)
746
766
  */
747
767
  setVisibilityFilter: function (filter) {
@@ -1401,8 +1421,8 @@ export default {
1401
1421
  const notPathways = { NOT: isPathways };
1402
1422
 
1403
1423
  if (payload.key === "alert" || payload.key === "withoutAlert") {
1404
- const hasAlert = payload.key === "alert" ?
1405
- { HAS: 'alert' } :
1424
+ const hasAlert = payload.key === "alert" ?
1425
+ { HAS: 'alert' } :
1406
1426
  { NOT: { HAS: 'alert' } };
1407
1427
 
1408
1428
  filter = { OR: [notPathways, { AND: [isPathways, hasAlert] }] };
@@ -1732,9 +1752,8 @@ export default {
1732
1752
  const clickedItem = singleSelection ? data : data[0]
1733
1753
  this.setConnectivityDataSource(this.viewingMode, clickedItem);
1734
1754
  if (this.viewingMode === 'Neuron Connection') {
1735
- this.retrieveConnectedPaths([clickedItem.models]).then((paths) => {
1736
- this.zoomToFeatures(paths)
1737
- })
1755
+ // do nothing here
1756
+ // the method to highlight paths is moved to checkAndCreatePopups function
1738
1757
  } else {
1739
1758
  this.currentActive = clickedItem.models ? clickedItem.models : '' // This is for FC map
1740
1759
  // This is for annotation mode - draw connectivity between features/paths
@@ -1767,7 +1786,6 @@ export default {
1767
1786
  data &&
1768
1787
  data.type !== 'marker' &&
1769
1788
  eventType === 'click' &&
1770
- !(this.viewingMode === 'Neuron Connection') &&
1771
1789
  // Disable popup when drawing
1772
1790
  !this.activeDrawTool
1773
1791
  ) {
@@ -1938,6 +1956,14 @@ export default {
1938
1956
  }
1939
1957
  return featureIds;
1940
1958
  },
1959
+ getFlatmapKnowledge: function () {
1960
+ let flatmapKnowledge = [];
1961
+ const flatmapKnowledgeRaw = sessionStorage.getItem('flatmap-knowledge');
1962
+ if (flatmapKnowledgeRaw) {
1963
+ flatmapKnowledge = JSON.parse(flatmapKnowledgeRaw);
1964
+ }
1965
+ return flatmapKnowledge;
1966
+ },
1941
1967
  emitConnectivityError: function (errorData) {
1942
1968
  this.$emit('connectivity-error', {
1943
1969
  data: {
@@ -1973,7 +1999,7 @@ export default {
1973
1999
  * _checkNeuronClicked shows a neuron path pop up if a path was recently clicked._
1974
2000
  * @arg {Object} `data`
1975
2001
  */
1976
- checkAndCreatePopups: async function (data) {
2002
+ checkAndCreatePopups: async function (data, connectivityExplorerClicked) {
1977
2003
  // Call flatmap database to get the connection data
1978
2004
  if (this.viewingMode === 'Annotation') {
1979
2005
  const features = data.filter(d => d.feature).map(d => d.feature)
@@ -2020,6 +2046,134 @@ export default {
2020
2046
  } else {
2021
2047
  this.annotation = {}
2022
2048
  }
2049
+ }
2050
+ // clicking on a connectivity explorer card will be the same as exploration mode
2051
+ // the card should be opened without doing other functions
2052
+ else if (this.viewingMode === 'Neuron Connection' && !connectivityExplorerClicked) {
2053
+ const resources = data.map(tooltip => tooltip.resource[0]);
2054
+ // TODO: to remove pathsQueryAPI
2055
+ // the new query, queryPathsByRoute, is used in mapviewer for CQ
2056
+ // let pathsQueryAPI = this.retrieveConnectedPaths(resources); // TODO: to replace with queryAllConnectedPaths
2057
+
2058
+ // filter out paths
2059
+ const featureId = resources.find(resource => !resource.startsWith('ilxtr:'));
2060
+ if (featureId) {
2061
+ // fallback if it cannot find in anatomical nodes
2062
+ const transformResources = Array.isArray(resources) ? [...resources] : [resources];
2063
+ if (transformResources.length === 1) {
2064
+ transformResources.push([]);
2065
+ }
2066
+
2067
+ const featureId = data[0].feature?.featureId;
2068
+ const annotation = this.mapImp.annotations.get(featureId);
2069
+ const anatomicalNodes = annotation?.['anatomical-nodes'];
2070
+ const uniqueResource = anatomicalNodes ? JSON.parse(anatomicalNodes[0]) : transformResources;
2071
+
2072
+ // if (this.connectionType === 'Origin') {
2073
+ // Competency Query API
2074
+ // pathsQueryAPI = queryPathsByOrigin(this.flatmapAPI, this.mapImp.knowledgeSource, resources);
2075
+
2076
+ // search by unique placement before competency API is ready for this
2077
+ // pathsQueryAPI = filterPathsByOriginFromKnowledge(uniqueResource);
2078
+ // } else if (this.connectionType === 'Via') {
2079
+ // Competency Query API
2080
+ // pathsQueryAPI = queryPathsByViaLocation(this.flatmapAPI, this.mapImp.knowledgeSource, resources);
2081
+
2082
+ // search by unique placement before competency API is ready for this
2083
+ // pathsQueryAPI = filterPathsByViaFromKnowledge(uniqueResource);
2084
+ // } else if (this.connectionType === 'Destination') {
2085
+ // Competency Query API
2086
+ // pathsQueryAPI = queryPathsByDestination(this.flatmapAPI, this.mapImp.knowledgeSource, resources);
2087
+
2088
+ // search by unique placement before competency API is ready for this
2089
+ // pathsQueryAPI = filterPathsByDestinationFromKnowledge(uniqueResource);
2090
+ // } else {
2091
+ // pathsQueryAPI = queryAllConnectedPaths(this.flatmapAPI, this.mapImp.knowledgeSource, resources);
2092
+ // }
2093
+ const terms = uniqueResource.flat(Infinity);
2094
+ const uniqueTerms = [...new Set(terms)];
2095
+ const fetchResults = await fetchLabels(this.flatmapAPI, uniqueTerms);
2096
+ const objectResults = fetchResults.reduce((arr, item) => {
2097
+ const id = item[0];
2098
+ const valObj = JSON.parse(item[1]);
2099
+ if (valObj.source === this.mapImp.knowledgeSource) {
2100
+ arr.push({ id, label: valObj.label });
2101
+ }
2102
+ return arr;
2103
+ }, []);
2104
+ const labels = [];
2105
+ for (let i = 0; i < uniqueTerms.length; i++) {
2106
+ const foundObj = objectResults.find((obj) => obj.id === uniqueTerms[i])
2107
+ if (foundObj) {
2108
+ labels.push(foundObj.label);
2109
+ }
2110
+ }
2111
+ const filterItemLabel = capitalise(labels.join(', '));
2112
+ const newConnectivityfilter = {
2113
+ facet: JSON.stringify(uniqueResource),
2114
+ facetPropPath: `flatmap.connectivity.source.${this.connectionType.toLowerCase()}`,
2115
+ tagLabel: filterItemLabel, // used tagLabel here instead of label since the label and value are different
2116
+ term: this.connectionType
2117
+ };
2118
+ // check for existing item
2119
+ const isNewFilterItemExist = this.connectivityfilters.some((connectivityfilter) => (
2120
+ connectivityfilter.facet === newConnectivityfilter.facet &&
2121
+ connectivityfilter.facetPropPath === newConnectivityfilter.facetPropPath
2122
+ ));
2123
+
2124
+ if (!isNewFilterItemExist) {
2125
+ this.connectivityfilters.push(newConnectivityfilter);
2126
+ }
2127
+ // TODO: to remove "neuron-connection-click"
2128
+ this.$emit('neuron-connection-feature-click', this.connectivityfilters);
2129
+ }
2130
+
2131
+ // TODO: to clean up after verification
2132
+ // pathsQueryAPI.then(async (paths) => {
2133
+ // if (paths.length) {
2134
+ // const filteredPaths = paths.filter(path => (path in this.mapImp.pathways.paths))
2135
+ // const filteredPathsWithData = [];
2136
+ // let prom1 = [];
2137
+ // let prom2 = [];
2138
+
2139
+ // for (let i = 0; i < filteredPaths.length; i++) {
2140
+ // const path = filteredPaths[i];
2141
+ // const modelFeatureIds = this.mapImp.modelFeatureIds(path);
2142
+ // const feature = this.mapImp.featureProperties(modelFeatureIds[0]);
2143
+ // if (feature) {
2144
+ // const pathData = {
2145
+ // resource: [feature.models],
2146
+ // feature: feature,
2147
+ // label: feature.label,
2148
+ // provenanceTaxonomy: feature.taxons,
2149
+ // alert: feature.alert,
2150
+ // };
2151
+ // filteredPathsWithData.push(pathData);
2152
+ // prom1.push({
2153
+ // title: pathData.label,
2154
+ // featureId: [path]
2155
+ // })
2156
+ // }
2157
+ // }
2158
+ // this.tooltipEntry = await Promise.all(prom1)
2159
+ // // Emit placeholders first.
2160
+ // this.$emit('connectivity-info-open', this.tooltipEntry);
2161
+
2162
+ // /**
2163
+ // * This event is emitted to highlight the same paths on other display maps.
2164
+ // */
2165
+ // this.$emit('neuron-connection-click', paths);
2166
+
2167
+ // // loading data
2168
+ // for (let i = 0; i < filteredPathsWithData.length; i++) {
2169
+ // const pathData = filteredPathsWithData[i];
2170
+ // const tooltipEntryData = await this.getKnowledgeTooltip(pathData);
2171
+ // prom2.push(tooltipEntryData)
2172
+ // }
2173
+ // this.tooltipEntry = await Promise.all(prom2)
2174
+ // this.displayTooltip(filteredPaths)
2175
+ // }
2176
+ // })
2023
2177
  } else {
2024
2178
  // load and store knowledge
2025
2179
  loadAndStoreKnowledge(this.mapImp, this.flatmapQueries);
@@ -2034,6 +2188,7 @@ export default {
2034
2188
  // this should only for flatmap paths not all features
2035
2189
  if (this.tooltipEntry.length) {
2036
2190
  this.$emit('connectivity-info-open', this.tooltipEntry);
2191
+
2037
2192
  // While having placeholders displayed, get details for all paths and then replace.
2038
2193
  for (let index = 0; index < data.length; index++) {
2039
2194
  prom1.push(await this.getKnowledgeTooltip(data[index]))
@@ -2046,6 +2201,31 @@ export default {
2046
2201
  }
2047
2202
  }
2048
2203
  },
2204
+ /**
2205
+ * Updates the connectivity filters in flatmap when there are changes in the sidebar.
2206
+ * @public
2207
+ * @param {Array} payload - The array of filter items to update.
2208
+ */
2209
+ updateConnectivityFilters: function (payload) {
2210
+ if (!payload.length) return;
2211
+ this.connectivityfilters = payload.filter((filterItem) => (
2212
+ filterItem.facet.toLowerCase() !== 'show all'
2213
+ ));
2214
+ },
2215
+ resetConnectivityfilters: function (payload) {
2216
+ if (payload.length) {
2217
+ // remove not found items
2218
+ this.connectivityfilters = this.connectivityfilters.filter((connectivityfilter) =>
2219
+ payload.some((notFoundItem) => (
2220
+ notFoundItem.facetPropPath === connectivityfilter.facetPropPath &&
2221
+ notFoundItem.facet !== connectivityfilter.facet
2222
+ ))
2223
+ )
2224
+ } else {
2225
+ // full reset
2226
+ this.connectivityfilters = [];
2227
+ }
2228
+ },
2049
2229
  getKnowledgeTooltip: async function (data) {
2050
2230
  //require data.resource && data.feature.source
2051
2231
  const results = await this.flatmapQueries.retrieveFlatmapKnowledgeForEvent(this.mapImp, data)
@@ -2749,9 +2929,9 @@ export default {
2749
2929
  }
2750
2930
  return filterSources
2751
2931
  },
2752
- getFilterOptions: async function () {
2932
+ getFilterOptions: async function (_flatmapKnowledge) {
2933
+ let filterOptions = [];
2753
2934
  if (this.mapImp) {
2754
- let filterOptions = []
2755
2935
  const filterRanges = this.mapImp.featureFilterRanges()
2756
2936
  for (const [key, value] of Object.entries(filterRanges)) {
2757
2937
  let main = {
@@ -2804,8 +2984,40 @@ export default {
2804
2984
  filterOptions.push(main)
2805
2985
  }
2806
2986
  }
2807
- return filterOptions
2987
+ const connectionFilters = [];
2988
+ const flatmapKnowledge = _flatmapKnowledge || this.getFlatmapKnowledge();
2989
+ const originItems = await extractOriginItems(this.flatmapAPI, flatmapKnowledge);
2990
+ const viaItems = await extractViaItems(this.flatmapAPI, flatmapKnowledge);
2991
+ const destinationItems = await extractDestinationItems(this.flatmapAPI, flatmapKnowledge);
2992
+
2993
+ const transformItem = (facet, item) => {
2994
+ const key = JSON.stringify(item.key);
2995
+ return {
2996
+ key: `flatmap.connectivity.source.${facet}.${key}`,
2997
+ label: item.label
2998
+ };
2999
+ }
3000
+
3001
+ for (const facet of ["origin", "via", "destination"]) {
3002
+ let childrenList = []
3003
+ if (facet === 'origin') {
3004
+ childrenList = originItems.map((item) => transformItem(facet, item));
3005
+ } else if (facet === 'via') {
3006
+ childrenList = viaItems.map((item) => transformItem(facet, item));
3007
+ } else if (facet === 'destination') {
3008
+ childrenList = destinationItems.map((item) => transformItem(facet, item));
3009
+ }
3010
+
3011
+ connectionFilters.push({
3012
+ key: `flatmap.connectivity.source.${facet}`,
3013
+ label: facet,
3014
+ children: childrenList,
3015
+ })
3016
+ }
3017
+
3018
+ filterOptions.push(...connectionFilters)
2808
3019
  }
3020
+ return filterOptions;
2809
3021
  },
2810
3022
  /**
2811
3023
  * @public
@@ -2882,7 +3094,7 @@ export default {
2882
3094
  * @arg {String} `term`,
2883
3095
  * @arg {String} `displayInfo`
2884
3096
  */
2885
- searchAndShowResult: function (term, displayInfo) {
3097
+ searchAndShowResult: function (term, displayInfo, connectivityExplorerClicked) {
2886
3098
  if (this.mapImp) {
2887
3099
  if (term === undefined || term === '') {
2888
3100
  this.mapImp.clearSearchResults()
@@ -2913,13 +3125,8 @@ export default {
2913
3125
  provenanceTaxonomy: feature.taxons,
2914
3126
  alert: feature.alert,
2915
3127
  }
2916
- if (this.viewingMode === "Exploration" || this.viewingMode === "Annotation") {
2917
- this.checkAndCreatePopups([data])
2918
- } else if (this.viewingMode === 'Neuron Connection') {
2919
- this.retrieveConnectedPaths(data.resource).then((paths) => {
2920
- this.zoomToFeatures(paths)
2921
- })
2922
- }
3128
+ // Show popup for all modes
3129
+ this.checkAndCreatePopups([data], connectivityExplorerClicked)
2923
3130
  this.mapImp.showPopup(featureId, capitalise(feature.label), {
2924
3131
  className: 'custom-popup',
2925
3132
  positionAtLastClick: false,
@@ -2934,6 +3141,21 @@ export default {
2934
3141
  }
2935
3142
  return false
2936
3143
  },
3144
+ /**
3145
+ * @public
3146
+ * Public method to highlight connected paths for neuron connection mode,
3147
+ * to highlight paths for other display maps on spit screen.
3148
+ * @arg {Array} `paths`
3149
+ */
3150
+ highlightConnectedPaths: function (paths) {
3151
+ if (paths.length) {
3152
+ // filter paths for this map
3153
+ const filteredPaths = paths.filter(path => (path in this.mapImp.pathways.paths))
3154
+ // this.zoomToFeatures is replaced with selectGeoJSONFeatures to highlight paths
3155
+ const featureIdsToHighlight = this.mapImp.modelFeatureIdList(filteredPaths);
3156
+ this.mapImp.selectGeoJSONFeatures(featureIdsToHighlight);
3157
+ }
3158
+ },
2937
3159
  /**
2938
3160
  * @public
2939
3161
  * Function to show search suggestions
@@ -2947,6 +3169,9 @@ export default {
2947
3169
  onActionClick: function (data) {
2948
3170
  EventBus.emit('onActionClick', data)
2949
3171
  },
3172
+ setConnectionType: function (type) {
3173
+ this.connectionType = type;
3174
+ },
2950
3175
  },
2951
3176
  props: {
2952
3177
  /**
@@ -3246,6 +3471,7 @@ export default {
3246
3471
  'Neuron Connection': 'Discover Neuron connections by selecting a neuron and viewing its associated network connections',
3247
3472
  'Annotation': ['View feature annotations', 'Add, comment on and view feature annotations']
3248
3473
  },
3474
+ connectionType: 'All',
3249
3475
  offlineAnnotationEnabled: false,
3250
3476
  offlineAnnotations: [],
3251
3477
  annotationFrom: 'Anyone',
@@ -3292,6 +3518,7 @@ export default {
3292
3518
  }),
3293
3519
  searchTerm: "",
3294
3520
  taxonLeaveDelay: undefined,
3521
+ connectivityfilters: [],
3295
3522
  }
3296
3523
  },
3297
3524
  computed: {
@@ -70,6 +70,8 @@
70
70
  @connectivity-info-open="onConnectivityInfoOpen"
71
71
  @connectivity-info-close="onConnectivityInfoClose"
72
72
  @connectivity-error="onConnectivityError"
73
+ @neuron-connection-click="onNeuronConnectionClick"
74
+ @neuron-connection-feature-click="onNeuronConnectionFeatureClick"
73
75
  @open-map="$emit('open-map', $event)"
74
76
  @pathway-selection-changed="onSelectionsDataChanged"
75
77
  :minZoom="minZoom"
@@ -305,6 +307,12 @@ export default {
305
307
  onConnectivityError: function (errorInfo) {
306
308
  this.$emit('connectivity-error', errorInfo);
307
309
  },
310
+ onNeuronConnectionClick: function (payload) {
311
+ this.$emit('neuron-connection-click', payload);
312
+ },
313
+ onNeuronConnectionFeatureClick: function (payload) {
314
+ this.$emit('neuron-connection-feature-click', payload);
315
+ },
308
316
  onSelectionsDataChanged: function (data) {
309
317
  this.$emit('pathway-selection-changed', data);
310
318
  },
@@ -557,6 +565,10 @@ export default {
557
565
  let map = this.getCurrentFlatmap()
558
566
  map.changeViewingMode(modeName)
559
567
  },
568
+ setConnectionType: function (type) {
569
+ let map = this.getCurrentFlatmap();
570
+ map.setConnectionType(type);
571
+ },
560
572
  },
561
573
  props: {
562
574
  /**
@@ -1,3 +1,9 @@
1
+ import {
2
+ findPathsByOriginItem,
3
+ findPathsByDestinationItem,
4
+ findPathsByViaItem,
5
+ } from '@abi-software/map-utilities';
6
+
1
7
  async function getReferenceConnectivitiesFromStorage(resource) {
2
8
  const flatmapKnowledgeRaw = sessionStorage.getItem('flatmap-knowledge');
3
9
 
@@ -26,6 +32,43 @@ async function getReferenceConnectivitiesByAPI(mapImp, resource, flatmapQueries)
26
32
  return featureIds;
27
33
  }
28
34
 
35
+ function getFlatmapKnowledge() {
36
+ const flatmapKnowledgeRaw = sessionStorage.getItem('flatmap-knowledge');
37
+
38
+ if (flatmapKnowledgeRaw) {
39
+ const flatmapKnowledge = JSON.parse(flatmapKnowledgeRaw);
40
+ return flatmapKnowledge;
41
+ }
42
+ return [];
43
+ }
44
+
45
+ async function filterPathsByOriginFromKnowledge(resource) {
46
+ const flatmapKnowledge = getFlatmapKnowledge();
47
+ const results = findPathsByOriginItem(flatmapKnowledge, resource);
48
+ if (Array.isArray(results)) {
49
+ return results.map(x => x.id);
50
+ }
51
+ return [];
52
+ }
53
+
54
+ async function filterPathsByDestinationFromKnowledge(resource) {
55
+ const flatmapKnowledge = getFlatmapKnowledge();
56
+ const results = findPathsByDestinationItem(flatmapKnowledge, resource);
57
+ if (Array.isArray(results)) {
58
+ return results.map(x => x.id);
59
+ }
60
+ return [];
61
+ }
62
+
63
+ async function filterPathsByViaFromKnowledge(resource) {
64
+ const flatmapKnowledge = getFlatmapKnowledge();
65
+ const results = findPathsByViaItem(flatmapKnowledge, resource);
66
+ if (Array.isArray(results)) {
67
+ return results.map(x => x.id);
68
+ }
69
+ return [];
70
+ }
71
+
29
72
  function getKnowledgeSource(mapImp) {
30
73
  return getKnowledgeSourceFromProvenance(mapImp.provenance);
31
74
  }
@@ -103,4 +146,7 @@ export {
103
146
  getKnowledgeSource,
104
147
  getKnowledgeSourceFromProvenance,
105
148
  refreshFlatmapKnowledgeCache,
149
+ filterPathsByOriginFromKnowledge,
150
+ filterPathsByDestinationFromKnowledge,
151
+ filterPathsByViaFromKnowledge,
106
152
  }