@abi-software/map-utilities 1.1.3-beta.2 → 1.1.3-beta.4

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/map-utilities",
3
- "version": "1.1.3-beta.2",
3
+ "version": "1.1.3-beta.4",
4
4
  "files": [
5
5
  "dist/*",
6
6
  "src/*",
package/src/App.vue CHANGED
@@ -533,6 +533,10 @@ function changeHover(value) {
533
533
  top: calc(50% - 100px);
534
534
  left: calc(50% - 200px);
535
535
  }
536
+ .toolbar-container {
537
+ height: 80px;
538
+ position: relative;
539
+ }
536
540
  .connectivity-graph {
537
541
  width: 600px;
538
542
  height: 600px;
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="connectivity-graph">
2
+ <div class="connectivity-graph" v-loading="loading">
3
3
  <div ref="graphCanvas" class="graph-canvas"></div>
4
4
  <div class="control-panel">
5
5
  <div class="node-key">
@@ -60,6 +60,7 @@
60
60
  import { ConnectivityGraph } from './graph';
61
61
 
62
62
  const MIN_SCHEMA_VERSION = 1.3;
63
+ const CACHE_LIFETIME = 24 * 60 * 60 * 1000; // One day
63
64
  const RESET_LABEL = 'Reset position';
64
65
  const ZOOM_LOCK_LABEL = 'Lock zoom (to scroll)';
65
66
  const ZOOM_UNLOCK_LABEL = 'Unlock zoom';
@@ -82,8 +83,11 @@ export default {
82
83
  },
83
84
  data: function () {
84
85
  return {
85
- cy: null,
86
+ loading: true,
86
87
  connectivityGraph: null,
88
+ selectedSource: '',
89
+ pathList: [],
90
+ schemaVersion: '',
87
91
  knowledgeByPath: new Map(),
88
92
  labelledTerms: new Set(),
89
93
  labelCache: new Map(),
@@ -94,34 +98,94 @@ export default {
94
98
  };
95
99
  },
96
100
  mounted() {
101
+ this.refreshCache();
102
+ this.loadCacheData();
97
103
  this.run().then((res) => {
98
104
  this.showGraph(this.entry);
99
105
  });
100
106
  },
101
107
  methods: {
108
+ loadCacheData: function () {
109
+ const selectedSource = sessionStorage.getItem('connectivity-graph-source');
110
+ const labelCache = sessionStorage.getItem('connectivity-graph-labels');
111
+ const pathList = sessionStorage.getItem('connectivity-graph-pathlist');
112
+ const schemaVersion = sessionStorage.getItem('connectivity-graph-schema-version');
113
+
114
+ if (selectedSource) {
115
+ this.selectedSource = selectedSource;
116
+ }
117
+ if (pathList) {
118
+ this.pathList = JSON.parse(pathList);
119
+ }
120
+ if (labelCache) {
121
+ const labelCacheObj = JSON.parse(labelCache);
122
+ this.labelCache = new Map(Object.entries(labelCacheObj));
123
+ }
124
+ if (schemaVersion) {
125
+ this.schemaVersion = schemaVersion;
126
+ }
127
+ },
128
+ removeAllCacheData: function () {
129
+ const keys = [
130
+ 'connectivity-graph-expiry',
131
+ 'connectivity-graph-source',
132
+ 'connectivity-graph-labels',
133
+ 'connectivity-graph-pathlist',
134
+ 'connectivity-graph-schema-version',
135
+ ];
136
+ keys.forEach((key) => {
137
+ sessionStorage.removeItem(key);
138
+ });
139
+ },
140
+ refreshCache: function () {
141
+ const expiry = sessionStorage.getItem('connectivity-graph-expiry');
142
+ const now = new Date();
143
+
144
+ if (now.getTime() > expiry) {
145
+ this.removeAllCacheData();
146
+ }
147
+ },
148
+ updateCacheExpiry: function () {
149
+ const now = new Date();
150
+ const expiry = now.getTime() + CACHE_LIFETIME;
151
+
152
+ sessionStorage.setItem('connectivity-graph-expiry', expiry);
153
+ },
102
154
  run: async function () {
103
- const schemaVersion = await this.getSchemaVersion();
104
- if (schemaVersion < MIN_SCHEMA_VERSION) {
155
+ if (!this.schemaVersion) {
156
+ this.schemaVersion = await this.getSchemaVersion();
157
+ sessionStorage.setItem('connectivity-graph-schema-version', this.schemaVersion);
158
+ this.updateCacheExpiry();
159
+ }
160
+ if (this.schemaVersion < MIN_SCHEMA_VERSION) {
105
161
  console.warn('No Server!');
106
162
  return;
107
163
  }
108
164
  this.showSpinner();
109
- const selectedSource = await this.setSourceList();
110
- await this.setPathList(selectedSource)
165
+ if (!this.selectedSource) {
166
+ this.selectedSource = await this.setSourceList();
167
+ sessionStorage.setItem('connectivity-graph-source', this.selectedSource);
168
+ this.updateCacheExpiry();
169
+ }
170
+ await this.setPathList(this.selectedSource);
111
171
  this.hideSpinner();
112
172
  },
113
173
  showGraph: async function (neuronPath) {
114
174
  const graphCanvas = this.$refs.graphCanvas;
175
+
115
176
  this.showSpinner();
177
+
116
178
  this.connectivityGraph = new ConnectivityGraph(this.labelCache, graphCanvas);
117
179
  await this.connectivityGraph.addConnectivity(this.knowledgeByPath.get(neuronPath));
180
+
118
181
  this.hideSpinner();
182
+
119
183
  this.connectivityGraph.showConnectivity(graphCanvas);
120
- this.currentPath = neuronPath
121
184
  },
122
185
  query: async function (sql, params) {
123
186
  const url = `${this.mapServer}knowledge/query/`;
124
- const query = { sql, params }
187
+ const query = { sql, params };
188
+
125
189
  try {
126
190
  const response = await fetch(url, {
127
191
  method: 'POST',
@@ -132,9 +196,11 @@ export default {
132
196
  },
133
197
  body: JSON.stringify(query)
134
198
  });
199
+
135
200
  if (!response.ok) {
136
201
  throw new Error(`Cannot access ${url}`);
137
202
  }
203
+
138
204
  return await response.json();
139
205
  } catch {
140
206
  return {
@@ -149,38 +215,50 @@ export default {
149
215
  // Order with most recent first...
150
216
  let firstSource = '';
151
217
  const sourceList = [];
218
+
152
219
  for (const source of sources) {
153
220
  if (source) {
154
221
  sourceList.push(source);
222
+
155
223
  if (firstSource === '') {
156
224
  firstSource = source;
157
225
  }
158
226
  }
159
227
  }
228
+
160
229
  return firstSource;
161
230
  },
162
- setPathList: async function (source) {
231
+ loadPathData: async function (source) {
163
232
  const data = await this.query(
164
233
  `select entity, knowledge from knowledge
165
234
  where entity like 'ilxtr:%' and source=?
166
235
  order by entity`,
167
236
  [source]);
168
- const pathList = [];
237
+ const pathList = data ? data.values : [];
238
+ return pathList;
239
+ },
240
+ setPathList: async function (source) {
241
+ if (!this.pathList.length) {
242
+ this.pathList = await this.loadPathData(source);
243
+ sessionStorage.setItem('connectivity-graph-pathlist', JSON.stringify(this.pathList));
244
+ this.updateCacheExpiry();
245
+ }
246
+
169
247
  this.knowledgeByPath.clear();
170
248
  this.labelledTerms = new Set();
171
- for (const [key, jsonKnowledge] of data.values) {
249
+
250
+ for (const [key, jsonKnowledge] of this.pathList) {
172
251
  const knowledge = JSON.parse(jsonKnowledge);
173
252
  if ('connectivity' in knowledge) {
174
- const label = knowledge.label || key;
175
- const shortLabel = (label === key.slice(6).replace('-prime', "'").replaceAll('-', ' '))
176
- ? ''
177
- : (label.length < 50) ? label : `${label.slice(0, 50)}...`;
178
- pathList.push(key);
179
253
  this.knowledgeByPath.set(key, knowledge);
180
254
  this.cacheLabels(knowledge);
181
255
  }
182
256
  }
183
- await this.getCachedTermLabels();
257
+
258
+ if (!this.labelCache.size) {
259
+ await this.getCachedTermLabels();
260
+ }
261
+
184
262
  return '';
185
263
  },
186
264
  getSchemaVersion: async function () {
@@ -197,9 +275,11 @@ export default {
197
275
  "Content-Type": "application/json"
198
276
  }
199
277
  });
278
+
200
279
  if (!response.ok) {
201
280
  console.error(`Cannot access ${url}`);
202
281
  }
282
+
203
283
  return await response.json();
204
284
  } catch {
205
285
  return null;
@@ -207,14 +287,19 @@ export default {
207
287
  },
208
288
  getCachedTermLabels: async function () {
209
289
  if (this.labelledTerms.size) {
210
- const termLabels = await this.query(`
290
+ const data = await this.query(`
211
291
  select entity, label from labels
212
292
  where entity in (?${', ?'.repeat(this.labelledTerms.size-1)})`,
213
293
  [...this.labelledTerms.values()]
214
294
  );
215
- for (const termLabel of termLabels.values) {
295
+
296
+ for (const termLabel of data.values) {
216
297
  this.labelCache.set(termLabel[0], termLabel[1]);
217
298
  }
299
+
300
+ const labelCacheObj = Object.fromEntries(this.labelCache);
301
+ sessionStorage.setItem('connectivity-graph-labels', JSON.stringify(labelCacheObj));
302
+ this.updateCacheExpiry();
218
303
  }
219
304
  },
220
305
  cacheNodeLabels: function (node) {
@@ -229,10 +314,10 @@ export default {
229
314
  }
230
315
  },
231
316
  showSpinner: function () {
232
- // show loading spinner
317
+ this.loading = true;
233
318
  },
234
319
  hideSpinner: function () {
235
- // hide loading spinner
320
+ this.loading = false;
236
321
  },
237
322
  reset: function () {
238
323
  this.connectivityGraph.reset();
@@ -272,7 +357,7 @@ export default {
272
357
  .node-key {
273
358
  border: 1px solid $app-primary-color;
274
359
  padding: 4px;
275
- background-color: rgba(240, 240, 240, 0.8);
360
+ background-color: rgba(#f7faff, 0.85);
276
361
 
277
362
  div div {
278
363
  width: 90px;
@@ -294,7 +379,7 @@ export default {
294
379
  }
295
380
 
296
381
  .tools {
297
- margin-top: 1rem;
382
+ margin-top: 0.5rem;
298
383
  display: flex;
299
384
  flex-direction: row;
300
385
  gap: 0.5rem;
@@ -310,6 +395,10 @@ export default {
310
395
  background: $app-primary-color !important;
311
396
  transition: all 0.25s ease;
312
397
 
398
+ svg {
399
+ margin: 0;
400
+ }
401
+
313
402
  &,
314
403
  &:focus,
315
404
  &:active {
@@ -321,6 +410,20 @@ export default {
321
410
  }
322
411
  }
323
412
 
413
+ :deep(.cy-graph-tooltip) {
414
+ padding: 4px 10px;
415
+ font-family: Asap;
416
+ font-size: 12px;
417
+ background: #f3ecf6 !important;
418
+ border: 1px solid $app-primary-color;
419
+ border-radius: var(--el-border-radius-base);
420
+ position: relative;
421
+ top: 0;
422
+ left: 0;
423
+ width: fit-content;
424
+ z-index: 1;
425
+ }
426
+
324
427
  .visually-hidden {
325
428
  clip: rect(0 0 0 0);
326
429
  clip-path: inset(50%);
@@ -27,7 +27,7 @@ import cytoscape from 'cytoscape'
27
27
 
28
28
  export class ConnectivityGraph
29
29
  {
30
- cy = null
30
+ cyg = null
31
31
  nodes = []
32
32
  edges = []
33
33
  axons = []
@@ -69,31 +69,31 @@ export class ConnectivityGraph
69
69
  showConnectivity(graphCanvas)
70
70
  //================
71
71
  {
72
- this.cy = new CytoscapeGraph(this, graphCanvas)
72
+ this.cyg = new CytoscapeGraph(this, graphCanvas)
73
73
  }
74
74
 
75
75
  clearConnectivity()
76
76
  //=================
77
77
  {
78
- if (this.cy) {
79
- this.cy.remove()
80
- this.cy = null
78
+ if (this.cyg?.cy) {
79
+ this.cyg.cy.remove()
80
+ this.cyg.cy = null
81
81
  }
82
82
  }
83
83
 
84
84
  reset()
85
85
  //=================
86
86
  {
87
- if (this.cy?.cy) {
88
- this.cy.cy.reset()
87
+ if (this.cyg?.cy) {
88
+ this.cyg.cy.reset()
89
89
  }
90
90
  }
91
91
 
92
92
  enableZoom(option)
93
93
  //=================
94
94
  {
95
- if (this.cy?.cy) {
96
- this.cy.cy.userZoomingEnabled(option)
95
+ if (this.cyg?.cy) {
96
+ this.cyg.cy.userZoomingEnabled(option)
97
97
  }
98
98
  }
99
99
 
@@ -195,7 +195,6 @@ class CytoscapeGraph
195
195
 
196
196
  constructor(connectivityGraph, graphCanvas)
197
197
  {
198
- // const graphCanvas = document.getElementById('graph-canvas')
199
198
  this.cy = cytoscape({
200
199
  container: graphCanvas,
201
200
  elements: connectivityGraph.elements,
@@ -214,9 +213,9 @@ class CytoscapeGraph
214
213
  .on('position', 'node', this.moveNode.bind(this))
215
214
 
216
215
  this.tooltip = document.createElement('div')
217
- this.tooltip.id = 'tooltip'
216
+ this.tooltip.className = 'cy-graph-tooltip'
218
217
  this.tooltip.hidden = true
219
- this.graphCanvas?.lastChild?.appendChild(this.tooltip)
218
+ graphCanvas?.lastChild?.appendChild(this.tooltip)
220
219
  }
221
220
 
222
221
  remove()