@abi-software/flatmapvuer 1.10.3-beta.9 → 1.11.0-beta.1

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.3-beta.9",
3
+ "version": "1.11.0-beta.1",
4
4
  "license": "Apache-2.0",
5
5
  "files": [
6
6
  "dist/*",
@@ -643,9 +643,6 @@ import {
643
643
  refreshFlatmapKnowledgeCache,
644
644
  getKnowledgeSource,
645
645
  getReferenceConnectivitiesByAPI,
646
- filterPathsByOriginFromKnowledge,
647
- filterPathsByDestinationFromKnowledge,
648
- filterPathsByViaFromKnowledge,
649
646
  } from '../services/flatmapKnowledge.js'
650
647
  import { capitalise } from './utilities.js'
651
648
  import yellowstar from '../icons/yellowstar'
@@ -655,14 +652,10 @@ import { AnnotationService } from '@abi-software/sparc-annotation'
655
652
  import { mapState } from 'pinia'
656
653
  import { useMainStore } from '@/store/index'
657
654
  import {
658
- queryPathsByOrigin,
659
- queryPathsByViaLocation,
660
- queryPathsByDestination,
661
655
  extractOriginItems,
662
656
  extractDestinationItems,
663
657
  extractViaItems,
664
658
  fetchLabels,
665
- queryAllConnectedPaths,
666
659
  DrawToolbar,
667
660
  Tooltip,
668
661
  TreeControls
@@ -765,6 +758,11 @@ export default {
765
758
  return { annotator }
766
759
  },
767
760
  methods: {
761
+ enableFeatureResetOnClick: function (enable) {
762
+ if (this.mapImp) {
763
+ this.mapImp.enableFeatureResetOnClick(enable)
764
+ }
765
+ },
768
766
  /**
769
767
  *
770
768
  * @param filter format should follow #makeStyleFilter (flatmap-viewer)
@@ -828,7 +826,7 @@ export default {
828
826
  ? this.mapImp.featureProperties(numericId)
829
827
  : { feature: this.existDrawnFeatures.find(feature => feature.id === value.trim()) };
830
828
  let payload = { feature: featureObject }
831
- this.checkAndCreatePopups([payload])
829
+ this.checkAndCreatePopups([payload], false)
832
830
  } else {
833
831
  this.closeTooltip()
834
832
  }
@@ -840,7 +838,7 @@ export default {
840
838
  */
841
839
  confirmDrawnFeature: function () {
842
840
  if (this.isValidDrawnCreated) {
843
- this.checkAndCreatePopups([this.drawnCreatedEvent])
841
+ this.checkAndCreatePopups([this.drawnCreatedEvent], false)
844
842
  // Add connection if exist to annotationEntry
845
843
  // Connection will only be added in creating new drawn feature annotation
846
844
  // And will not be updated if move drawn features
@@ -1338,12 +1336,6 @@ export default {
1338
1336
  * @arg {string} `pathId` or `anatomicalId`
1339
1337
  */
1340
1338
  retrieveConnectedPaths: async function (payload, options = {}) {
1341
- // query all connected paths CQ
1342
- if (this.viewingMode === 'Neuron Connection' && this.connectionType.toLowerCase() === 'all') {
1343
- const sourceId = this.mapImp.uuid;
1344
- const connectedPaths = await queryAllConnectedPaths(this.flatmapAPI, sourceId, payload);
1345
- return connectedPaths;
1346
- }
1347
1339
  // query all connected paths from flatmap
1348
1340
  if (this.mapImp) {
1349
1341
  let connectedPaths = [];
@@ -1517,7 +1509,7 @@ export default {
1517
1509
  * @arg {String} `models`
1518
1510
  */
1519
1511
  ftuSelected: function (models) {
1520
- this.searchAndShowResult(models, true)
1512
+ this.searchAndShowResult(models, true, true)
1521
1513
  },
1522
1514
  /**
1523
1515
  * @public
@@ -2022,7 +2014,7 @@ export default {
2022
2014
  * _checkNeuronClicked shows a neuron path pop up if a path was recently clicked._
2023
2015
  * @arg {Object} `data`
2024
2016
  */
2025
- checkAndCreatePopups: async function (data, connectivityExplorerClicked) {
2017
+ checkAndCreatePopups: async function (data, mapclick = true) {
2026
2018
  // Call flatmap database to get the connection data
2027
2019
  if (this.viewingMode === 'Annotation') {
2028
2020
  const features = data.filter(d => d.feature).map(d => d.feature)
@@ -2072,7 +2064,7 @@ export default {
2072
2064
  }
2073
2065
  // clicking on a connectivity explorer card will be the same as exploration mode
2074
2066
  // the card should be opened without doing other functions
2075
- else if (this.viewingMode === 'Neuron Connection' && !connectivityExplorerClicked) {
2067
+ else if (this.viewingMode === 'Neuron Connection' && mapclick) {
2076
2068
  const resources = data.map(tooltip => tooltip.resource[0]);
2077
2069
 
2078
2070
  // filter out paths
@@ -2087,11 +2079,16 @@ export default {
2087
2079
  const featureId = data[0].feature?.featureId;
2088
2080
  const annotation = this.mapImp.annotations.get(featureId);
2089
2081
  const anatomicalNodes = annotation?.['anatomical-nodes'];
2082
+ const annotationModels = annotation?.['models'];
2090
2083
  let anatomicalNode;
2091
2084
  let uniqueResource = transformResources;
2092
2085
  const models = annotation?.['models'];
2093
2086
  if (anatomicalNodes?.length) {
2094
- anatomicalNode = anatomicalNodes[anatomicalNodes.length - 1];
2087
+ // get the node which match the feature in a location
2088
+ // [feature, location]
2089
+ anatomicalNode = anatomicalNodes.find((node) =>
2090
+ JSON.parse(node)[0] === annotationModels
2091
+ );
2095
2092
  }
2096
2093
  if (anatomicalNode) {
2097
2094
  uniqueResource = JSON.parse(anatomicalNode);
@@ -2134,18 +2131,10 @@ export default {
2134
2131
  this.connectivityFilters.push(newConnectivityfilter);
2135
2132
  }
2136
2133
 
2137
- if (this.connectionType.toLowerCase() === 'all') {
2138
- const searchTerms = uniqueTerms.join();
2139
- this.$emit('neuron-connection-feature-click', {
2140
- filters: [],
2141
- search: searchTerms,
2142
- });
2143
- } else {
2144
- this.$emit('neuron-connection-feature-click', {
2145
- filters: this.connectivityFilters,
2146
- search: '',
2147
- });
2148
- }
2134
+ this.$emit('neuron-connection-feature-click', {
2135
+ filters: this.connectivityFilters,
2136
+ search: '',
2137
+ });
2149
2138
  } else {
2150
2139
  // clicking on paths
2151
2140
  // do nothing for origin, destination, via
@@ -2728,7 +2717,7 @@ export default {
2728
2717
  if (state.background) this.backgroundChangeCallback(state.background)
2729
2718
  if (state.searchTerm) {
2730
2719
  const searchTerm = state.searchTerm
2731
- this.searchAndShowResult(searchTerm, true)
2720
+ this.searchAndShowResult(searchTerm, true, true)
2732
2721
  }
2733
2722
  this.setVisibilityState(state)
2734
2723
  }
@@ -2975,7 +2964,7 @@ export default {
2975
2964
  const id = knowledge.id;
2976
2965
  if (id) {
2977
2966
  const mapKnowledgeObj = mapKnowledge[id];
2978
- if (mapKnowledgeObj) {
2967
+ if (mapKnowledgeObj && mapKnowledgeObj.connectivity && mapKnowledgeObj['node-phenotypes']) {
2979
2968
  const mapConnectivity = mapKnowledgeObj.connectivity;
2980
2969
  const mapNodePhenotypes = mapKnowledgeObj['node-phenotypes'];
2981
2970
  // take only map connectivity
@@ -3005,7 +2994,7 @@ export default {
3005
2994
  };
3006
2995
  }
3007
2996
 
3008
- for (const facet of ["origin", "via", "destination"]) {
2997
+ for (const facet of ["origin", "via", "destination", "all"]) {
3009
2998
  let childrenList = []
3010
2999
  if (facet === 'origin') {
3011
3000
  childrenList = originItems.map((item) => transformItem(facet, item));
@@ -3013,6 +3002,20 @@ export default {
3013
3002
  childrenList = viaItems.map((item) => transformItem(facet, item));
3014
3003
  } else if (facet === 'destination') {
3015
3004
  childrenList = destinationItems.map((item) => transformItem(facet, item));
3005
+ } else {
3006
+ // All is the combination of origin, via, destination
3007
+ const allList = [
3008
+ ...originItems.map((item) => transformItem(facet, item)),
3009
+ ...viaItems.map((item) => transformItem(facet, item)),
3010
+ ...destinationItems.map((item) => transformItem(facet, item))
3011
+ ];
3012
+ // Generate unique list since the same feature can be in origin, via, and destination
3013
+ const seenKeys = new Set();
3014
+ childrenList = allList.filter(item => {
3015
+ if (seenKeys.has(item.key)) return false;
3016
+ seenKeys.add(item.key);
3017
+ return true;
3018
+ });
3016
3019
  }
3017
3020
 
3018
3021
  // Those without label but key should be below
@@ -3027,14 +3030,18 @@ export default {
3027
3030
  return a.label.localeCompare(b.label);
3028
3031
  });
3029
3032
 
3030
- connectionFilters.push({
3031
- key: `flatmap.connectivity.source.${facet}`,
3032
- label: facet,
3033
- children: childrenList,
3034
- })
3033
+ if (childrenList.length) {
3034
+ connectionFilters.push({
3035
+ key: `flatmap.connectivity.source.${facet}`,
3036
+ label: facet,
3037
+ children: childrenList,
3038
+ })
3039
+ }
3035
3040
  }
3036
3041
 
3037
- filterOptions.push(...connectionFilters)
3042
+ if (connectionFilters.length) {
3043
+ filterOptions.push(...connectionFilters)
3044
+ }
3038
3045
  }
3039
3046
  return filterOptions;
3040
3047
  },
@@ -3113,8 +3120,9 @@ export default {
3113
3120
  * with the option to display the label/connectivity information using displayInfo flag.
3114
3121
  * @arg {String} `term`,
3115
3122
  * @arg {String} `displayInfo`
3123
+ * @arg {String} `mapclick` Similate the event as it is triggered by an user click
3116
3124
  */
3117
- searchAndShowResult: function (term, displayInfo, connectivityExplorerClicked) {
3125
+ searchAndShowResult: function (term, displayInfo, mapclick = true) {
3118
3126
  if (this.mapImp) {
3119
3127
  if (term === undefined || term === '') {
3120
3128
  this.mapImp.clearSearchResults()
@@ -3146,7 +3154,7 @@ export default {
3146
3154
  alert: feature.alert,
3147
3155
  }
3148
3156
  // Show popup for all modes
3149
- this.checkAndCreatePopups([data], connectivityExplorerClicked)
3157
+ this.checkAndCreatePopups([data], mapclick)
3150
3158
  this.mapImp.showPopup(featureId, capitalise(feature.label), {
3151
3159
  className: 'custom-popup',
3152
3160
  positionAtLastClick: false,
@@ -6,12 +6,7 @@
6
6
  :key="item[identifierKey]"
7
7
  :label="item[identifierKey]"
8
8
  >
9
- <div
10
- v-if="legendStyle(item) === 'yellow-star'"
11
- :class="legendStyle(item)"
12
- v-html="showStarInLegend ? yellowstar : ''"
13
- ></div>
14
- <div v-else class="legend-item">
9
+ <div class="legend-item" v-if="legendStyle(item)">
15
10
  <div
16
11
  :class="legendStyle(item)"
17
12
  :style="{ 'background-color': item[colourKey] }"
@@ -23,7 +18,6 @@
23
18
  </template>
24
19
 
25
20
  <script>
26
- import yellowstar from "../../icons/yellowstar";
27
21
  /* eslint-disable no-alert, no-console */
28
22
  export default {
29
23
  name: "DynamicLegends",
@@ -55,11 +49,6 @@ export default {
55
49
  default: false,
56
50
  },
57
51
  },
58
- data: function () {
59
- return {
60
- yellowstar: yellowstar,
61
- };
62
- },
63
52
  methods: {
64
53
  capitalise: function (label) {
65
54
  return label.charAt(0).toUpperCase() + label.slice(1).toLowerCase();
@@ -67,6 +56,9 @@ export default {
67
56
  legendStyle: function (item) {
68
57
  if (item[this.styleKey] === "star") {
69
58
  if (item[this.identifierKey] === "Featured dataset marker") {
59
+ if (!this.showStarInLegend) {
60
+ return;
61
+ }
70
62
  return "yellow-star";
71
63
  } else if (item[this.identifierKey] === "Gaglionated nerve plexus") {
72
64
  return "hexagon-star";
@@ -101,20 +93,31 @@ export default {
101
93
  display: inline-block;
102
94
  }
103
95
 
104
- // hexagon
105
96
  .hexagon-star {
106
- width: 21px;
97
+ width: 20px;
107
98
  height: 25px;
108
99
  background-color: #ffffff;
109
100
  opacity: 0.64;
110
101
  clip-path: path(
111
- "M10.48 0.76 c-2.12 3.72 -6.12 6.04 -10.44 6.04 l-0.16 0.24 c2.04 3.6 2.04 8 0 11.6 l0.16 0.24 c4.28 0 8.32 2.32 10.44 6.04 c2.12 -3.72 6.12 -6.04 10.44 -6.04 c-2.12 -3.72 -2.12 -8.36 0 -12.16 C16.64 6.84 12.68 4.52 10.48 0.76z"
102
+ "M9.96 0.72 c-2.01 3.53 -5.81 5.74 -9.92 5.74 l-0.15 0.23 c1.94 3.42 1.94 7.6 0 11.02 l0.15 0.23 c4.07 0 7.9 2.2 9.92 5.74 c2.01 -3.53 5.81 -5.74 9.92 -5.74 c-2.01 -3.53 -2.01 -7.94 0 -11.55 C15.81 6.5 12.04 4.29 9.96 0.72z"
112
103
  );
113
104
  -webkit-clip-path: path(
114
- "M10.48 0.76 c-2.12 3.72 -6.12 6.04 -10.44 6.04 l-0.16 0.24 c2.04 3.6 2.04 8 0 11.6 l0.16 0.24 c4.28 0 8.32 2.32 10.44 6.04 c2.12 -3.72 6.12 -6.04 10.44 -6.04 c-2.12 -3.72 -2.12 -8.36 0 -12.16 C16.64 6.84 12.68 4.52 10.48 0.76z"
105
+ "M9.96 0.72 c-2.01 3.53 -5.81 5.74 -9.92 5.74 l-0.15 0.23 c1.94 3.42 1.94 7.6 0 11.02 l0.15 0.23 c4.07 0 7.9 2.2 9.92 5.74 c2.01 -3.53 5.81 -5.74 9.92 -5.74 c-2.01 -3.53 -2.01 -7.94 0 -11.55 C15.81 6.5 12.04 4.29 9.96 0.72z"
115
106
  );
116
107
  }
117
108
 
109
+ .yellow-star {
110
+ width: 25px;
111
+ height: 25px;
112
+ background-color: #ffffff !important;
113
+ background-image: url("data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cpath%20fill%3D%22yellow%22%20stroke%3D%22%23000%22%20stroke-width%3D%222%22%20d%3D%22M11.0748%203.25583C11.4141%202.42845%2012.5859%202.42845%2012.9252%203.25583L14.6493%207.45955C14.793%207.80979%2015.1221%208.04889%2015.4995%208.07727L20.0303%208.41798C20.922%208.48504%2021.2841%209.59942%2020.6021%2010.1778L17.1369%2013.1166C16.8482%2013.3614%2016.7225%2013.7483%2016.8122%2014.1161L17.8882%2018.5304C18.1%2019.3992%2017.152%2020.0879%2016.3912%2019.618L12.5255%2017.2305C12.2034%2017.0316%2011.7966%2017.0316%2011.4745%2017.2305L7.60881%2019.618C6.84796%2020.0879%205.90001%2019.3992%206.1118%2018.5304L7.18785%2014.1161C7.2775%2013.7483%207.1518%2013.3614%206.86309%2013.1166L3.3979%2010.1778C2.71588%209.59942%203.07796%208.48504%203.96971%208.41798L8.50046%208.07727C8.87794%208.04889%209.20704%207.80979%209.35068%207.45955L11.0748%203.25583Z%22/%3E%3C/svg%3E");
114
+ background-repeat: no-repeat;
115
+ background-size: contain;
116
+ display: inline-block;
117
+ margin: -3px;
118
+ padding-right: 2px;
119
+ }
120
+
118
121
  .label {
119
122
  margin-left: 14px;
120
123
  font-size: 12px;
@@ -25,9 +25,8 @@ async function getReferenceConnectivitiesByAPI(mapImp, resource, flatmapQueries)
25
25
  const sql = `select knowledge from knowledge
26
26
  where source="${knowledgeSource}" and
27
27
  knowledge like "%${resource}%" order by source desc`;
28
- const response = await flatmapQueries.flatmapQuery(sql);
29
- const mappedData = response.values.map((x) => x[0]);
30
- const parsedData = mappedData.map((x) => JSON.parse(x));
28
+ const response = await flatmapQueries.queryKnowledge(sql);
29
+ const parsedData = response.map((x) => JSON.parse(x));
31
30
  const featureIds = parsedData.map((x) => x.id);
32
31
  return featureIds;
33
32
  }
@@ -97,9 +96,8 @@ async function loadAndStoreKnowledge(mapImp, flatmapQueries) {
97
96
  const flatmapKnowledgeSource = sessionStorage.getItem('flatmap-knowledge-source');
98
97
 
99
98
  if (!flatmapKnowledge || flatmapKnowledgeSource !== knowledgeSource) {
100
- const response = await flatmapQueries.flatmapQuery(sql);
101
- const mappedData = response.values.map(x => x[0]);
102
- const parsedData = mappedData.map(x => JSON.parse(x));
99
+ const response = await flatmapQueries.queryKnowledge(sql);
100
+ const parsedData = response.map(x => JSON.parse(x));
103
101
 
104
102
  sessionStorage.setItem('flatmap-knowledge', JSON.stringify(parsedData));
105
103
  sessionStorage.setItem('flatmap-knowledge-source', knowledgeSource);
@@ -104,6 +104,7 @@ let FlatmapQueries = function () {
104
104
  this.uberons = []
105
105
  this.lookUp = []
106
106
  this.connectivitySource = 'map' // 'sckan'
107
+ this.noMapConnectivity = false
107
108
  }
108
109
 
109
110
  this.createTooltipData = async function (mapImp, eventData) {
@@ -144,7 +145,8 @@ let FlatmapQueries = function () {
144
145
  hyperlinks: hyperlinks,
145
146
  provenanceTaxonomy: eventData.provenanceTaxonomy,
146
147
  provenanceTaxonomyLabel: taxonomyLabel,
147
- connectivitySource: this.connectivitySource
148
+ connectivitySource: this.connectivitySource,
149
+ noMapConnectivity: this.noMapConnectivity,
148
150
  }
149
151
  return tooltipData
150
152
  }
@@ -158,7 +160,8 @@ let FlatmapQueries = function () {
158
160
  componentsWithDatasets: this.componentsWithDatasets,
159
161
  destinations: this.destinations,
160
162
  destinationsWithDatasets: this.destinationsWithDatasets,
161
- connectivitySource: this.connectivitySource
163
+ connectivitySource: this.connectivitySource,
164
+ noMapConnectivity: this.noMapConnectivity,
162
165
  };
163
166
  }
164
167
 
@@ -300,6 +303,9 @@ let FlatmapQueries = function () {
300
303
  queryAPI
301
304
  .then((response) => {
302
305
  if (this.checkConnectivityExists(response)) {
306
+ if (connectivitySource === 'map') {
307
+ this.noMapConnectivity = false;
308
+ }
303
309
  let connectivity = response;
304
310
  if (processConnectivity) {
305
311
  this.processConnectivity(mapImp, connectivity).then((processedConnectivity) => {
@@ -312,6 +318,32 @@ let FlatmapQueries = function () {
312
318
  })
313
319
  }
314
320
  else resolve(connectivity)
321
+ } else if (connectivitySource === 'map') {
322
+ // switch to SCKAN
323
+ // when there has no connectivity data from Map
324
+ // and add the noMapConnectivity flag to disable the option
325
+ this.connectivitySource = 'sckan';
326
+ this.noMapConnectivity = true;
327
+ mapImp.queryKnowledge(keastId)
328
+ .then((fallbackResponse) => {
329
+ if (this.checkConnectivityExists(fallbackResponse)) {
330
+ let connectivity = fallbackResponse;
331
+ if (processConnectivity) {
332
+ this.processConnectivity(mapImp, connectivity).then((processedConnectivity) => {
333
+ // response.references is publication urls
334
+ if (fallbackResponse.references) {
335
+ // with publications from both PubMed and Others
336
+ this.rawURLs = [...fallbackResponse.references];
337
+ }
338
+ resolve(processedConnectivity)
339
+ })
340
+ }
341
+ else resolve(connectivity)
342
+ } else {
343
+ resolve(false)
344
+ }
345
+ })
346
+ .catch(() => resolve(false));
315
347
  } else {
316
348
  resolve(false)
317
349
  }
@@ -536,19 +568,24 @@ let FlatmapQueries = function () {
536
568
  return `select distinct publication from publications where entity = '${model}'`
537
569
  }
538
570
 
539
- this.flatmapQuery = function (sql) {
540
- const data = { sql: sql }
541
- return fetch(`${this.flatmapAPI}knowledge/query/`, {
542
- method: 'POST',
543
- headers: {
544
- 'Content-Type': 'application/json',
545
- },
546
- body: JSON.stringify(data),
571
+ this.queryKnowledge = async (sql, params) => {
572
+ const url = `${this.flatmapAPI}/knowledge/query/`;
573
+ const query = { sql, params };
574
+ const response = await fetch(url, {
575
+ method: 'POST',
576
+ headers: {
577
+ "Accept": "application/json"
578
+ },
579
+ body: JSON.stringify(query),
547
580
  })
548
- .then((response) => response.json())
549
- .catch((error) => {
550
- console.error('Error:', error)
551
- })
581
+ if (!response.ok) {
582
+ throw new Error(`Cannot access ${url}`);
583
+ }
584
+ const data = await response.json();
585
+ if ('error' in data) {
586
+ throw new TypeError(data.error);
587
+ }
588
+ return data.values
552
589
  }
553
590
  }
554
591