@abi-software/mapintegratedvuer 1.19.1 → 1.20.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,7 +1,10 @@
1
1
  {
2
2
  "name": "@abi-software/mapintegratedvuer",
3
- "version": "1.19.1",
3
+ "version": "1.20.1",
4
4
  "license": "Apache-2.0",
5
+ "engines": {
6
+ "node": ">=20"
7
+ },
5
8
  "scripts": {
6
9
  "serve": "vite --host --force",
7
10
  "heroku-postbuild": "vite build",
@@ -52,14 +55,14 @@
52
55
  "*.js"
53
56
  ],
54
57
  "dependencies": {
55
- "@abi-software/flatmapvuer": "1.13.4",
56
- "@abi-software/map-side-bar": "^2.15.1",
57
- "@abi-software/map-utilities": "1.8.3",
58
- "@abi-software/plotvuer": "1.0.7",
59
- "@abi-software/scaffoldvuer": "1.17.0",
60
- "@abi-software/simulationvuer": "3.2.6",
58
+ "@abi-software/flatmapvuer": "^1.14.1",
59
+ "@abi-software/map-side-bar": "2.16.0",
60
+ "@abi-software/map-utilities": "1.9.0",
61
+ "@abi-software/plotvuer": "1.1.0",
62
+ "@abi-software/scaffoldvuer": "1.18.0",
63
+ "@abi-software/simulationvuer": "3.3.0",
61
64
  "@abi-software/sparc-annotation": "0.3.2",
62
- "@abi-software/svg-sprite": "1.0.4",
65
+ "@abi-software/svg-sprite": "1.1.0",
63
66
  "@element-plus/icons-vue": "^2.3.1",
64
67
  "@vitejs/plugin-vue": "^4.6.2",
65
68
  "css-element-queries": "^1.2.3",
@@ -106,7 +109,10 @@
106
109
  "vue-router": "^4.2.5"
107
110
  },
108
111
  "optionalDependencies": {
109
- "@esbuild/darwin-arm64": "^0.25.3"
112
+ "@esbuild/darwin-arm64": "^0.25.3",
113
+ "@rollup/rollup-darwin-arm64": "4.62.3",
114
+ "@rollup/rollup-linux-x64-gnu": "4.62.3",
115
+ "@rollup/rollup-win32-x64-msvc": "4.62.3"
110
116
  },
111
117
  "eslintConfig": {
112
118
  "root": true,
package/src/App.vue CHANGED
@@ -4,34 +4,46 @@
4
4
  href="https://fonts.googleapis.com/css?family=Asap:400,400i,500,600,700&display=swap">
5
5
  <div class="button-container">
6
6
  <el-popover
7
+ ref="optionsPopover"
7
8
  placement="bottom"
8
9
  trigger="click"
9
10
  width=500
10
11
  class="popover"
11
12
  :teleported=false
12
- >
13
- <div class="options-container">
14
- <div class="row">
15
- <el-button @click="saveSettings()" size="small">Save Settings</el-button>
16
- <el-button @click="restoreSettings()" size="small">Restore Settings</el-button>
17
- <el-button @click="getShareableURL()" size="small">Get Link</el-button>
18
- </div>
19
- <div class="row">
20
- <el-button @click="setRatFlatmap()" size="small">Set Rat Flatmap</el-button>
21
- <el-button @click="setMultiFlatmap()" size="small">Set MultiFlatmap</el-button>
22
- <el-button @click="setLegacyMultiFlatmap()" size="small">Set Legacy MultiFlatmap</el-button>
23
- <el-button @click="setScaffold()" size="small">Set To Scaffold</el-button>
24
- <el-button @click="setWholebody()" size="small">Set to Wholebody</el-button>
25
- <el-button @click="setFlatmap()" size="small">Set Flatmap</el-button>
26
- <el-button @click="setSearch()" size="small">Set Search</el-button>
27
- <el-button @click="toggleLongLabel()" size="small">Toggle Long Label</el-button>
28
- </div>
13
+ >
14
+ <div class="options-container">
15
+ <div class="row">
16
+ <el-button @click="saveSettings()" size="small">Save Settings</el-button>
17
+ <el-button @click="restoreSettings()" size="small">Restore Settings</el-button>
18
+ <el-button @click="getShareableURL()" size="small">Get Link</el-button>
29
19
  </div>
30
- <template #reference>
31
-
32
- <el-button class="options-button" :icon="ElIconSetting">Options</el-button>
33
-
34
- </template>
20
+ <div class="row">
21
+ <el-button @click="setRatFlatmap()" size="small">Set Rat Flatmap</el-button>
22
+ <el-button @click="setMultiFlatmap()" size="small">Set MultiFlatmap</el-button>
23
+ <el-button @click="setLegacyMultiFlatmap()" size="small">Set Legacy MultiFlatmap</el-button>
24
+ <el-button @click="setScaffold()" size="small">Set To Scaffold</el-button>
25
+ <el-button @click="setWholebody()" size="small">Set to Wholebody</el-button>
26
+ <el-button @click="setFlatmap()" size="small">Set Flatmap</el-button>
27
+ <el-button @click="setSearch()" size="small">Set Search</el-button>
28
+ </div>
29
+ <div class="row">
30
+ <div style="font-weight: 600">Connectivity tooltip labels:</div>
31
+ </div>
32
+ <div class="row">
33
+ <el-checkbox @change="onShowLongLabelChange" v-model="showLongLabel" size="small">
34
+ Show long label
35
+ </el-checkbox>
36
+ <el-checkbox @change="onTruncateLongLabelChange" :disabled="!showLongLabel" v-model="truncateLongLabel" size="small">
37
+ Truncate long label
38
+ </el-checkbox>
39
+ <el-checkbox @change="onShowIdInTooltipChange" :disabled="!showLongLabel" v-model="showIdInTooltip" size="small">
40
+ Show ID in tooltip
41
+ </el-checkbox>
42
+ </div>
43
+ </div>
44
+ <template #reference>
45
+ <el-button class="options-button" :icon="ElIconSetting">Options</el-button>
46
+ </template>
35
47
  </el-popover>
36
48
  </div>
37
49
  <div class="map-app">
@@ -42,6 +54,8 @@
42
54
  :options="options"
43
55
  :state="state"
44
56
  :showLongLabel="showLongLabel"
57
+ :truncateLongLabel="truncateLongLabel"
58
+ :showIdInTooltip="showIdInTooltip"
45
59
  :shareLink="shareLink"
46
60
  :useHelpModeDialog="true"
47
61
  :connectivityInfoSidebar="true"
@@ -161,6 +175,8 @@ export default {
161
175
  ElIconSetting: shallowRef(ElIconSetting),
162
176
  routerIsReady: false,
163
177
  showLongLabel: true,
178
+ truncateLongLabel: true,
179
+ showIdInTooltip: true,
164
180
  }
165
181
  },
166
182
  computed: {
@@ -182,6 +198,11 @@ export default {
182
198
  }
183
199
  },
184
200
  methods: {
201
+ closePopover: function() {
202
+ if (this.$refs.optionsPopover) {
203
+ this.$refs.optionsPopover.hide();
204
+ }
205
+ },
185
206
  changeViewingMode: function(modeName) {
186
207
  this.$refs.map.changeViewingMode(modeName);
187
208
  },
@@ -261,6 +282,7 @@ export default {
261
282
  label: "Functional"
262
283
  }
263
284
  );
285
+ this.closePopover();
264
286
  },
265
287
  setLegacyMultiFlatmap: function() {
266
288
  this.$refs.map.setCurrentEntry(
@@ -270,6 +292,7 @@ export default {
270
292
  uuid: "01fedbf9-d783-509c-a10c-827941ab13da",
271
293
  }
272
294
  );
295
+ this.closePopover();
273
296
  },
274
297
  setMultiFlatmap: function() {
275
298
  this.$refs.map.setCurrentEntry(
@@ -281,6 +304,7 @@ export default {
281
304
  organ: "UBERON:0018675"
282
305
  }
283
306
  );
307
+ this.closePopover();
284
308
  },
285
309
  setRatFlatmap: function() {
286
310
  this.$refs.map.setCurrentEntry(
@@ -289,6 +313,7 @@ export default {
289
313
  taxo: "NCBITaxon:10114"
290
314
  }
291
315
  );
316
+ this.closePopover();
292
317
  },
293
318
  setScaffold: function() {
294
319
  this.$refs.map.setCurrentEntry(
@@ -299,6 +324,7 @@ export default {
299
324
  viewUrl: "colonMouse_Layout1_view.json"
300
325
  }
301
326
  );
327
+ this.closePopover();
302
328
  },
303
329
  setWholebody: function() {
304
330
  this.$refs.map.setCurrentEntry(
@@ -308,12 +334,20 @@ export default {
308
334
  isBodyScaffold: true
309
335
  }
310
336
  );
337
+ this.closePopover();
311
338
  },
312
339
  setSearch: function() {
313
340
  this.$refs.map.openSearch([], "10.26275/1uno-tynt");
341
+ this.closePopover();
342
+ },
343
+ onShowLongLabelChange: function() {
344
+ this.closePopover();
345
+ },
346
+ onTruncateLongLabelChange: function() {
347
+ this.closePopover();
314
348
  },
315
- toggleLongLabel: function() {
316
- this.showLongLabel = !this.showLongLabel;
349
+ onShowIdInTooltipChange: function() {
350
+ this.closePopover();
317
351
  },
318
352
  mapIsLoaded: function(map) {
319
353
  console.log("map is loaded", map)
@@ -20,6 +20,7 @@
20
20
 
21
21
  <script>
22
22
  /* eslint-disable no-alert, no-console */
23
+ import { computed } from 'vue';
23
24
  import Tagging from '../services/tagging.js';
24
25
  import SplitFlow from './SplitFlow.vue';
25
26
  import EventBus from './EventBus';
@@ -64,6 +65,14 @@ export default {
64
65
  type: Boolean,
65
66
  default: true,
66
67
  },
68
+ truncateLongLabel: {
69
+ type: Boolean,
70
+ default: true,
71
+ },
72
+ showIdInTooltip: {
73
+ type: Boolean,
74
+ default: true,
75
+ },
67
76
  /**
68
77
  * The options include APIs and Keys.
69
78
  */
@@ -133,6 +142,8 @@ export default {
133
142
  return {
134
143
  showGlobalSettings: this.showGlobalSettings,
135
144
  showOpenMapButton: this.showOpenMapButton,
145
+ truncateLongLabel: computed(() => this.truncateLongLabel),
146
+ showIdInTooltip: computed(() => this.showIdInTooltip),
136
147
  };
137
148
  },
138
149
  data: function () {
@@ -30,7 +30,7 @@
30
30
  :connectivityKnowledge="connectivityKnowledge"
31
31
  :filterOptions="filterOptions"
32
32
  :showVisibilityFilter="showVisibilityFilter"
33
- :showLongLabel="showLongLabel"
33
+ :showLongLabel="true"
34
34
  @tabClicked="onSidebarTabClicked"
35
35
  @tabClosed="onSidebarTabClosed"
36
36
  @actionClick="actionClick"
@@ -67,7 +67,7 @@
67
67
 
68
68
  <script>
69
69
  /* eslint-disable no-alert, no-console */
70
- import { provide, markRaw } from 'vue'
70
+ import { provide, markRaw, computed } from 'vue';
71
71
  import Tagging from '../services/tagging.js';
72
72
  import DialogToolbarContent from "./DialogToolbarContent.vue";
73
73
  import EventBus from "./EventBus";
@@ -141,12 +141,13 @@ export default {
141
141
  SplitDialog,
142
142
  SideBar,
143
143
  },
144
- setup() {
144
+ setup(props) {
145
145
  const mainStore = useMainStore();
146
- provide('userApiKey', mainStore.userToken);
147
146
  const settings = useSettingsStore();
148
147
  let annotator = markRaw(new AnnotationService(`${settings.flatmapAPI}annotator`));
149
- provide('$annotator', annotator)
148
+ provide('userApiKey', mainStore.userToken);
149
+ provide('$annotator', annotator);
150
+ provide('showLongLabel', computed(() => props.showLongLabel));
150
151
  return { annotator }
151
152
  },
152
153
  props: {
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <CellDLViewer
3
+ :annotations="annotations"
4
+ :celldlData="celldlData"
5
+ @error="onError"
6
+ @event="onEvent"
7
+ />
8
+ </template>
9
+
10
+ <script>
11
+ /* eslint-disable no-alert, no-console */
12
+ import './cellDLViewer.css';
13
+ import CellDLViewer from '@celldl/viewer';
14
+ import ContentMixin from "../../mixins/ContentMixin";
15
+
16
+ export default {
17
+ name: "CellDLView",
18
+ mixins: [ ContentMixin ],
19
+ components: {
20
+ CellDLViewer,
21
+ },
22
+ data: function() {
23
+ return {
24
+ annotations: {},
25
+ celldlData: '',
26
+ }
27
+ },
28
+ methods: {
29
+ onError: function() {
30
+ console.log(msg);
31
+ },
32
+ onEvent: function() {
33
+ console.log(detail);
34
+ }
35
+ }
36
+ };
37
+ </script>
@@ -41,6 +41,7 @@
41
41
  @pathway-selection-changed="onPathwaySelectionChanged"
42
42
  @mapmanager-loaded="onMapmanagerLoaded"
43
43
  :showPathwayFilter="false"
44
+ :tooltipContentProvider="tooltipPathLabelProvider"
44
45
  @trackEvent="trackEvent"
45
46
  />
46
47
 
@@ -86,7 +87,7 @@ export default {
86
87
  },
87
88
  /**
88
89
  * Perform a local search on this contentvuer
89
- * This is similar to directly clicking onthe map
90
+ * This is similar to directly clicking on the map
90
91
  */
91
92
  search: function (term) {
92
93
  return this.$refs.flatmap.searchAndShowResult(term, true, true);
@@ -42,6 +42,7 @@
42
42
  @open-pubmed-url="onOpenPubmedUrl"
43
43
  @mapmanager-loaded="onMapmanagerLoaded"
44
44
  :showPathwayFilter="false"
45
+ :tooltipContentProvider="tooltipPathLabelProvider"
45
46
  @trackEvent="trackEvent"
46
47
  />
47
48
 
@@ -7,6 +7,7 @@ export {}
7
7
 
8
8
  declare module 'vue' {
9
9
  export interface GlobalComponents {
10
+ CellDLViewer: typeof import('./components/viewers/CellDLViewer.vue')['default']
10
11
  ConnectivityGraph: typeof import('./components/viewers/ConnectivityGraph.vue')['default']
11
12
  ContentBar: typeof import('./components/ContentBar.vue')['default']
12
13
  ContentVuer: typeof import('./components/ContentVuer.vue')['default']
@@ -41,7 +41,23 @@ export default {
41
41
  default: false,
42
42
  },
43
43
  },
44
- inject: ['showGlobalSettings', 'showOpenMapButton'],
44
+ inject: {
45
+ showGlobalSettings: {
46
+ default: true,
47
+ },
48
+ showOpenMapButton: {
49
+ default: true,
50
+ },
51
+ showLongLabel: {
52
+ default: true,
53
+ },
54
+ truncateLongLabel: {
55
+ default: true,
56
+ },
57
+ showIdInTooltip: {
58
+ default: true,
59
+ },
60
+ },
45
61
  computed: {
46
62
  ...mapStores(useEntriesStore, useSettingsStore, useSplitFlowStore, useConnectivitiesStore),
47
63
  idNamePair() {
@@ -65,11 +81,21 @@ export default {
65
81
  this.alive = false;
66
82
  },
67
83
  mounted: function () {
68
- this.multiflatmapRef = markRaw(this.$refs.multiflatmap);
69
- this.flatmapRef = markRaw(this.$refs.flatmap);
70
- this.iframeRef = markRaw(this.$refs.iframe);
71
- this.plotRef = markRaw(this.$refs.plot);
72
- this.simulationRef = markRaw(this.$refs.simulation);
84
+ if (this.$refs.multiflatmap) {
85
+ this.multiflatmapRef = markRaw(this.$refs.multiflatmap);
86
+ }
87
+ if (this.$refs.flatmap) {
88
+ this.flatmapRef = markRaw(this.$refs.flatmap);
89
+ }
90
+ if (this.$refs.iframe) {
91
+ this.iframeRef = markRaw(this.$refs.iframe);
92
+ }
93
+ if (this.$refs.plot) {
94
+ this.plotRef = markRaw(this.$refs.plot);
95
+ }
96
+ if (this.$refs.simulation) {
97
+ this.simulationRef = markRaw(this.$refs.simulation);
98
+ }
73
99
  // load connectivity with mock human male flatmap
74
100
  if (this.iframeRef || this.plotRef || this.simulationRef) {
75
101
  this.loadExplorerConfig();
@@ -766,6 +792,70 @@ export default {
766
792
  trackEvent: function (data) {
767
793
  Tagging.sendEvent(data);
768
794
  },
795
+ /**
796
+ * Provides custom tooltip content for FlatmapVuer path features.
797
+ * Uses connectivity 'long-label' values for IDs starting with 'ilxtr:' or 'ilx:'.
798
+ * Returns null to use the default tooltip when long labels are disabled or unavailable.
799
+ */
800
+ tooltipPathLabelProvider: function (featureData) {
801
+ const showLong = this.showLongLabel?.value ?? this.showLongLabel;
802
+ if (!showLong) {
803
+ return null;
804
+ }
805
+
806
+ // Handle both single feature data object and array of feature data (multi-feature case)
807
+ const features = Array.isArray(featureData) ? featureData : [featureData];
808
+ const longLabels = [];
809
+ const uuid = features[0]?.mapUUID;
810
+ const connectivities = uuid ? this.connectivitiesStore?.globalConnectivities?.[uuid] : null;
811
+
812
+ // Make features unique by it's id.
813
+ const uniqueFeatures = features.filter((feature, index, self) =>
814
+ index === self.findIndex((f) => f.id === feature.id)
815
+ );
816
+
817
+ for (const feature of uniqueFeatures) {
818
+ const featureId = feature?.id;
819
+ // Only applies to path features
820
+ if (!featureId || !(featureId.startsWith('ilxtr:') || featureId.startsWith('ilx:'))) {
821
+ continue;
822
+ }
823
+ // Look up long-label from the connectivity store
824
+ if (connectivities) {
825
+ const match = connectivities.find(c => c.id === featureId);
826
+ const truncate = this.truncateLongLabel?.value ?? this.truncateLongLabel;
827
+ const lineClamp = 3;
828
+ const withIdStyles = [
829
+ `margin-bottom: 4px`,
830
+ ];
831
+ const truncateStyles = [
832
+ `display: -webkit-box`,
833
+ `-webkit-line-clamp: ${lineClamp}`,
834
+ `-webkit-box-orient: vertical`,
835
+ `overflow: hidden`,
836
+ ];
837
+ const styles = [
838
+ ...(this.showIdInTooltip ? withIdStyles : []),
839
+ ...(truncate ? truncateStyles : [])
840
+ ].join(';');
841
+
842
+ if (match && match['long-label']) {
843
+ let labelTag = []
844
+ labelTag.push(`<div style="${styles}">${capitalise(match['long-label'])}</div>`);
845
+ if (this.showIdInTooltip) {
846
+ labelTag.push(`<span class="id-tag">${featureId}</span>`);
847
+ }
848
+ longLabels.push(labelTag.join(''));
849
+ }
850
+ }
851
+ }
852
+
853
+ if (longLabels.length > 0) {
854
+ return `<div class='flatmap-feature-label flatmap-connectivity-label'>${longLabels.join('<hr/>')}</div>`;
855
+ }
856
+
857
+ return null; // Use default tooltip
858
+ },
769
859
  },
770
860
  data: function () {
771
861
  return {
@@ -0,0 +1,77 @@
1
+ const knowledgeMap = {
2
+ "classes": {
3
+ "cardio_28": {
4
+ "models": "UBERON:0002165",
5
+ "name": "Endocardium"
6
+ },
7
+ "cardio_29": {
8
+ "models": "UBERON:0002349",
9
+ "name": "Myocardium"
10
+ }
11
+ },
12
+ "features": {
13
+ "v_GLUT2_basal": {
14
+ "name": "Flow through GLUT2 transporter",
15
+ "variable": "main/v_GLUT2base"
16
+ },
17
+ "v_SGLT1_apical": {
18
+ "name": "SGLT1 transporter",
19
+ "variable": "main/v_SGLT1"
20
+ },
21
+ "v_Kir_basal": {
22
+ "name": "Kir channel",
23
+ "models": "UBERON:0001536",
24
+ "variable": "main/v_Kir"
25
+ },
26
+ "v_NKA_basal": {
27
+ "name": "Na/K ATPase",
28
+ "variable": "main/v_NKA"
29
+ },
30
+ "v_GLUT2_apical": {
31
+ "name": "GLUT2 transporter",
32
+ "variable": "main/v_GLUT2apex"
33
+ },
34
+ "q_Na_lumen": {
35
+ "name": "[Na+] in lumen",
36
+ "variable": "main/c_Na_gut"
37
+ },
38
+ "q_Na_i": {
39
+ "name": "[Na+] in intracellular space",
40
+ "variable": "main/c_Na_int"
41
+ },
42
+ "q_Na_blood": {
43
+ "name": "[Na+] in blood",
44
+ "variable": "main/c_Na_cap"
45
+ },
46
+ "q_K_blood": {
47
+ "name": "[K+] in blood",
48
+ "variable": "main/c_K_cap"
49
+ },
50
+ "q_K_i": {
51
+ "name": "[K+] in intracellular space",
52
+ "variable": "main/c_K_int"
53
+ },
54
+ "q_Glc_lumen": {
55
+ "name": "[Glucose] in lumen",
56
+ "variable": "main/c_Glc_gut"
57
+ },
58
+ "q_Glc_i": {
59
+ "name": "[Glucose] in intracellular space",
60
+ "variable": "main/c_Glc_int"
61
+ },
62
+ "q_Glc_blood": {
63
+ "name": "[Glucose] in blood",
64
+ "variable": "main/c_Glc_cap"
65
+ }
66
+ }
67
+ };
68
+
69
+ const getVariableName = (name) => {
70
+ if (Object.hasOwn(knowledgeMap.features, name)) {
71
+ console.log("pass")
72
+ const data = knowledgeMap.features[name];
73
+ return data;
74
+ }
75
+ };
76
+
77
+ export { getVariableName }