@abi-software/map-utilities 1.1.3-beta.4 → 1.2.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/map-utilities",
3
- "version": "1.1.3-beta.4",
3
+ "version": "1.2.0-beta.1",
4
4
  "files": [
5
5
  "dist/*",
6
6
  "src/*",
@@ -31,7 +31,6 @@
31
31
  "dependencies": {
32
32
  "@abi-software/svg-sprite": "^1.0.1",
33
33
  "@element-plus/icons-vue": "^2.3.1",
34
- "cytoscape": "^3.30.2",
35
34
  "element-plus": "2.8.4",
36
35
  "mitt": "^3.0.1",
37
36
  "vue": "^3.4.21"
package/src/App.vue CHANGED
@@ -38,7 +38,6 @@ const drawnTypes = [
38
38
  { value: "Polygon", label: "Polygon" },
39
39
  { value: "None", label: "None" },
40
40
  ];
41
- const showConnectivityGraph = ref(false);
42
41
 
43
42
  onMounted(() => {
44
43
  console.log("🚀 ~ onMounted ~ appRef:", appRef.value);
@@ -423,25 +422,6 @@ function changeHover(value) {
423
422
  </el-button>
424
423
  </el-col>
425
424
  </el-row>
426
- <el-row>
427
- <el-col>
428
- <h3>Connectivity Graph</h3>
429
- </el-col>
430
- <el-col>
431
- <el-button
432
- @click="showConnectivityGraph = true"
433
- size="small"
434
- >
435
- Show connectivity graph
436
- </el-button>
437
- <el-button
438
- @click="showConnectivityGraph = false"
439
- size="small"
440
- >
441
- Hide connectivity graph
442
- </el-button>
443
- </el-col>
444
- </el-row>
445
425
 
446
426
  <DrawToolbar
447
427
  v-show="isFlatmap"
@@ -511,11 +491,6 @@ function changeHover(value) {
511
491
  @setColour="setColour"
512
492
  @checkChanged="checkChanged"
513
493
  />
514
- <ConnectivityGraph
515
- v-if="showConnectivityGraph"
516
- entry="ilxtr:neuron-type-aacar-13"
517
- map-server="https://mapcore-demo.org/curation/flatmap/"
518
- />
519
494
  </div>
520
495
  </template>
521
496
 
@@ -533,13 +508,4 @@ function changeHover(value) {
533
508
  top: calc(50% - 100px);
534
509
  left: calc(50% - 200px);
535
510
  }
536
- .toolbar-container {
537
- height: 80px;
538
- position: relative;
539
- }
540
- .connectivity-graph {
541
- width: 600px;
542
- height: 600px;
543
- margin-top: 1rem;
544
- }
545
511
  </style>
@@ -6,12 +6,21 @@
6
6
  {{ title }}
7
7
  </div>
8
8
  </el-col>
9
+ <el-col v-if="enableFilter" :span="12">
10
+ <div>
11
+ <el-input
12
+ class="tree-filter-input"
13
+ v-model="filterText"
14
+ placeholder="Filter keyword"
15
+ />
16
+ </div>
17
+ </el-col>
9
18
  </el-row>
10
19
  <div class="tree-container" ref="treeContainer">
11
20
  <div :class="['tree-tooltip', tooltipAtBottom ? 'bottom' : '']" >
12
21
  <el-popover
13
22
  ref="tooltip"
14
- :visible="tooltipVisible"
23
+ :visible="tooltipVisible && tooltipLabel !== ''"
15
24
  placement="top"
16
25
  :show-arrow="false"
17
26
  :teleported="false"
@@ -38,6 +47,7 @@
38
47
  :default-expanded-keys="expandedKeys"
39
48
  @check="checkChanged"
40
49
  :indent="8"
50
+ :filter-node-method="filterNode"
41
51
  :class="[mapType === 'flatmap' ? 'hide_grandchildren_checkbox': '']"
42
52
  >
43
53
  <template #default="{ node, data }">
@@ -138,10 +148,15 @@ export default {
138
148
  type: [String, Array],
139
149
  required: true,
140
150
  },
151
+ enableFilter: {
152
+ type: Boolean,
153
+ default: true,
154
+ }
141
155
  },
142
156
  data: function () {
143
157
  return {
144
158
  defaultExpandedKeys: ["All"],
159
+ filterText: "",
145
160
  myPopperClass: "hide-scaffold-colour-popup",
146
161
  tooltipVisible: false,
147
162
  tooltipLabel: "",
@@ -178,8 +193,17 @@ export default {
178
193
  else this.myPopperClass = "hide-scaffold-colour-popup";
179
194
  },
180
195
  },
196
+ filterText: {
197
+ handler: function (value) {
198
+ if (this.$refs.regionTree) this.$refs.regionTree.filter(value);
199
+ },
200
+ },
181
201
  },
182
202
  methods: {
203
+ filterNode: function(value, data) {
204
+ if (!value) return true;
205
+ return data.label ? data.label.toLowerCase().includes(value) : false;
206
+ },
183
207
  setColour: function (nodeData, value) {
184
208
  this.$emit("setColour", nodeData, value);
185
209
  },
@@ -250,6 +274,9 @@ export default {
250
274
  unmounted: function () {
251
275
  this.sortedPrimitiveGroups = undefined;
252
276
  },
277
+ mounted: function() {
278
+ if (this.$refs.regionTree) this.$refs.regionTree.filter(this.filterText);
279
+ }
253
280
  };
254
281
  </script>
255
282
 
@@ -265,6 +292,7 @@ export default {
265
292
  }
266
293
 
267
294
  .selections-container {
295
+ width: 260px;
268
296
  padding-top: 5px;
269
297
  }
270
298
 
@@ -278,6 +306,15 @@ export default {
278
306
  margin-left: 8px;
279
307
  }
280
308
 
309
+ :deep(.tree-filter-input) {
310
+ .el-input__inner {
311
+ height: 20px;
312
+ }
313
+ .el-input__wrapper.is-focus{
314
+ box-shadow: 0 0 0 1px $app-primary-color;
315
+ }
316
+ }
317
+
281
318
  .tree-container {
282
319
  width: 260px;
283
320
  border: 1px solid rgb(144, 147, 153);
@@ -3,13 +3,5 @@ import HelpModeDialog from "./HelpModeDialog/HelpModeDialog.vue";
3
3
  import Tooltip from "./Tooltip/Tooltip.vue";
4
4
  import TreeControls from "./TreeControls/TreeControls.vue";
5
5
  import CopyToClipboard from "./CopyToClipboard/CopyToClipboard.vue";
6
- import ConnectivityGraph from "./ConnectivityGraph/ConnectivityGraph.vue";
7
6
 
8
- export {
9
- DrawToolbar,
10
- HelpModeDialog,
11
- Tooltip,
12
- TreeControls,
13
- CopyToClipboard,
14
- ConnectivityGraph,
15
- };
7
+ export { DrawToolbar, HelpModeDialog, Tooltip, TreeControls, CopyToClipboard };
@@ -9,7 +9,6 @@ declare module 'vue' {
9
9
  export interface GlobalComponents {
10
10
  AnnotationPopup: typeof import('./components/Tooltip/AnnotationPopup.vue')['default']
11
11
  ConnectionDialog: typeof import('./components/DrawToolbar/ConnectionDialog.vue')['default']
12
- ConnectivityGraph: typeof import('./components/ConnectivityGraph/ConnectivityGraph.vue')['default']
13
12
  CopyToClipboard: typeof import('./components/CopyToClipboard/CopyToClipboard.vue')['default']
14
13
  DrawToolbar: typeof import('./components/DrawToolbar/DrawToolbar.vue')['default']
15
14
  ElButton: typeof import('element-plus/es')['ElButton']
@@ -18,7 +17,6 @@ declare module 'vue' {
18
17
  ElCol: typeof import('element-plus/es')['ElCol']
19
18
  ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
20
19
  ElIcon: typeof import('element-plus/es')['ElIcon']
21
- ElIconAim: typeof import('@element-plus/icons-vue')['Aim']
22
20
  ElIconArrowDown: typeof import('@element-plus/icons-vue')['ArrowDown']
23
21
  ElIconArrowUp: typeof import('@element-plus/icons-vue')['ArrowUp']
24
22
  ElIconClose: typeof import('@element-plus/icons-vue')['Close']
@@ -26,8 +24,6 @@ declare module 'vue' {
26
24
  ElIconDelete: typeof import('@element-plus/icons-vue')['Delete']
27
25
  ElIconEdit: typeof import('@element-plus/icons-vue')['Edit']
28
26
  ElIconFinished: typeof import('@element-plus/icons-vue')['Finished']
29
- ElIconLock: typeof import('@element-plus/icons-vue')['Lock']
30
- ElIconUnlock: typeof import('@element-plus/icons-vue')['Unlock']
31
27
  ElIconWarning: typeof import('@element-plus/icons-vue')['Warning']
32
28
  ElInput: typeof import('element-plus/es')['ElInput']
33
29
  ElMain: typeof import('element-plus/es')['ElMain']
@@ -1,451 +0,0 @@
1
- <template>
2
- <div class="connectivity-graph" v-loading="loading">
3
- <div ref="graphCanvas" class="graph-canvas"></div>
4
- <div class="control-panel">
5
- <div class="node-key">
6
- <div class="key-head">Node type:</div>
7
- <div>
8
- <div><span>Node:</span><span class="key-box" style="background: #80F0F0"/></div>
9
- <div><span>Axon:</span><span class="key-box" style="background: green"/></div>
10
- <div><span>Dendrite:</span><span class="key-box" style="background: red"/></div>
11
- <div><span>Both:</span><span class="key-box" style="background: gray"/></div>
12
- </div>
13
- </div>
14
- <div class="tools">
15
- <el-tooltip
16
- :content="resetLabel"
17
- placement="bottom"
18
- effect="control-tooltip"
19
- >
20
- <el-button
21
- class="control-button"
22
- :class="theme"
23
- size="small"
24
- @click="reset"
25
- >
26
- <el-icon color="white">
27
- <el-icon-aim />
28
- </el-icon>
29
- <span class="visually-hidden">{{ resetLabel }}</span>
30
- </el-button>
31
- </el-tooltip>
32
- <el-tooltip
33
- :content="zoomLockLabel"
34
- placement="bottom"
35
- effect="control-tooltip"
36
- >
37
- <el-button
38
- class="control-button"
39
- :class="theme"
40
- size="small"
41
- @click="toggleZoom"
42
- >
43
- <el-icon color="white">
44
- <template v-if="zoomEnabled">
45
- <el-icon-lock />
46
- </template>
47
- <template v-else>
48
- <el-icon-unlock />
49
- </template>
50
- </el-icon>
51
- <span class="visually-hidden">{{ zoomLockLabel }}</span>
52
- </el-button>
53
- </el-tooltip>
54
- </div>
55
- </div>
56
- </div>
57
- </template>
58
-
59
- <script>
60
- import { ConnectivityGraph } from './graph';
61
-
62
- const MIN_SCHEMA_VERSION = 1.3;
63
- const CACHE_LIFETIME = 24 * 60 * 60 * 1000; // One day
64
- const RESET_LABEL = 'Reset position';
65
- const ZOOM_LOCK_LABEL = 'Lock zoom (to scroll)';
66
- const ZOOM_UNLOCK_LABEL = 'Unlock zoom';
67
- const APP_PRIMARY_COLOR = '#8300bf';
68
-
69
- export default {
70
- name: 'ConnectivityGraph',
71
- props: {
72
- /**
73
- * Entity to load its connectivity graph.
74
- */
75
- entry: {
76
- type: String,
77
- default: '',
78
- },
79
- mapServer: {
80
- type: String,
81
- default: '',
82
- },
83
- },
84
- data: function () {
85
- return {
86
- loading: true,
87
- connectivityGraph: null,
88
- selectedSource: '',
89
- pathList: [],
90
- schemaVersion: '',
91
- knowledgeByPath: new Map(),
92
- labelledTerms: new Set(),
93
- labelCache: new Map(),
94
- resetLabel: RESET_LABEL,
95
- zoomLockLabel: ZOOM_LOCK_LABEL,
96
- iconColor: APP_PRIMARY_COLOR,
97
- zoomEnabled: false,
98
- };
99
- },
100
- mounted() {
101
- this.refreshCache();
102
- this.loadCacheData();
103
- this.run().then((res) => {
104
- this.showGraph(this.entry);
105
- });
106
- },
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
- },
154
- run: async function () {
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) {
161
- console.warn('No Server!');
162
- return;
163
- }
164
- this.showSpinner();
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);
171
- this.hideSpinner();
172
- },
173
- showGraph: async function (neuronPath) {
174
- const graphCanvas = this.$refs.graphCanvas;
175
-
176
- this.showSpinner();
177
-
178
- this.connectivityGraph = new ConnectivityGraph(this.labelCache, graphCanvas);
179
- await this.connectivityGraph.addConnectivity(this.knowledgeByPath.get(neuronPath));
180
-
181
- this.hideSpinner();
182
-
183
- this.connectivityGraph.showConnectivity(graphCanvas);
184
- },
185
- query: async function (sql, params) {
186
- const url = `${this.mapServer}knowledge/query/`;
187
- const query = { sql, params };
188
-
189
- try {
190
- const response = await fetch(url, {
191
- method: 'POST',
192
- headers: {
193
- "Accept": "application/json; charset=utf-8",
194
- "Cache-Control": "no-store",
195
- "Content-Type": "application/json"
196
- },
197
- body: JSON.stringify(query)
198
- });
199
-
200
- if (!response.ok) {
201
- throw new Error(`Cannot access ${url}`);
202
- }
203
-
204
- return await response.json();
205
- } catch {
206
- return {
207
- values: []
208
- };
209
- }
210
- },
211
- setSourceList: async function () {
212
- const data = await this.getJsonData(`${this.mapServer}knowledge/sources`);
213
- const sources = data ? (data.sources || []) : [];
214
-
215
- // Order with most recent first...
216
- let firstSource = '';
217
- const sourceList = [];
218
-
219
- for (const source of sources) {
220
- if (source) {
221
- sourceList.push(source);
222
-
223
- if (firstSource === '') {
224
- firstSource = source;
225
- }
226
- }
227
- }
228
-
229
- return firstSource;
230
- },
231
- loadPathData: async function (source) {
232
- const data = await this.query(
233
- `select entity, knowledge from knowledge
234
- where entity like 'ilxtr:%' and source=?
235
- order by entity`,
236
- [source]);
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
-
247
- this.knowledgeByPath.clear();
248
- this.labelledTerms = new Set();
249
-
250
- for (const [key, jsonKnowledge] of this.pathList) {
251
- const knowledge = JSON.parse(jsonKnowledge);
252
- if ('connectivity' in knowledge) {
253
- this.knowledgeByPath.set(key, knowledge);
254
- this.cacheLabels(knowledge);
255
- }
256
- }
257
-
258
- if (!this.labelCache.size) {
259
- await this.getCachedTermLabels();
260
- }
261
-
262
- return '';
263
- },
264
- getSchemaVersion: async function () {
265
- const data = await this.getJsonData(`${this.mapServer}knowledge/schema-version`);
266
- return data ? (+data.version || 0) : 0;
267
- },
268
- getJsonData: async function (url) {
269
- try {
270
- const response = await fetch(url, {
271
- method: 'GET',
272
- headers: {
273
- "Accept": "application/json; charset=utf-8",
274
- "Cache-Control": "no-store",
275
- "Content-Type": "application/json"
276
- }
277
- });
278
-
279
- if (!response.ok) {
280
- console.error(`Cannot access ${url}`);
281
- }
282
-
283
- return await response.json();
284
- } catch {
285
- return null;
286
- }
287
- },
288
- getCachedTermLabels: async function () {
289
- if (this.labelledTerms.size) {
290
- const data = await this.query(`
291
- select entity, label from labels
292
- where entity in (?${', ?'.repeat(this.labelledTerms.size-1)})`,
293
- [...this.labelledTerms.values()]
294
- );
295
-
296
- for (const termLabel of data.values) {
297
- this.labelCache.set(termLabel[0], termLabel[1]);
298
- }
299
-
300
- const labelCacheObj = Object.fromEntries(this.labelCache);
301
- sessionStorage.setItem('connectivity-graph-labels', JSON.stringify(labelCacheObj));
302
- this.updateCacheExpiry();
303
- }
304
- },
305
- cacheNodeLabels: function (node) {
306
- for (const term of [node[0], ...node[1]]) {
307
- this.labelledTerms.add(term);
308
- }
309
- },
310
- cacheLabels: async function (knowledge) {
311
- for (const edge of knowledge.connectivity) {
312
- this.cacheNodeLabels(edge[0]);
313
- this.cacheNodeLabels(edge[1]);
314
- }
315
- },
316
- showSpinner: function () {
317
- this.loading = true;
318
- },
319
- hideSpinner: function () {
320
- this.loading = false;
321
- },
322
- reset: function () {
323
- this.connectivityGraph.reset();
324
- },
325
- /**
326
- * Enable/disable user zoom for scrolling
327
- */
328
- toggleZoom: function () {
329
- this.zoomEnabled = !this.zoomEnabled;
330
- this.zoomLockLabel = this.zoomEnabled ? ZOOM_UNLOCK_LABEL : ZOOM_LOCK_LABEL;
331
- this.connectivityGraph.enableZoom(!this.zoomEnabled);
332
- },
333
- },
334
- };
335
- </script>
336
-
337
- <style lang="scss" scoped>
338
- .connectivity-graph,
339
- .graph-canvas {
340
- width: 100%;
341
- height: 600px;
342
- background-color: white;
343
- position: relative;
344
- }
345
-
346
- .connectivity-graph {
347
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
348
- border: solid 1px #e4e7ed;
349
- }
350
-
351
- .control-panel {
352
- position: absolute;
353
- top: 1rem;
354
- right: 1rem;
355
- }
356
-
357
- .node-key {
358
- border: 1px solid $app-primary-color;
359
- padding: 4px;
360
- background-color: rgba(#f7faff, 0.85);
361
-
362
- div div {
363
- width: 90px;
364
- }
365
- }
366
-
367
- .key-head {
368
- text-align: center;
369
- font-weight: bold;
370
- border-bottom: 1px solid gray;
371
- padding-bottom: 4px;
372
- margin-bottom: 4px;
373
- }
374
-
375
- .key-box {
376
- float: right;
377
- width: 12px;
378
- height: 12px;
379
- }
380
-
381
- .tools {
382
- margin-top: 0.5rem;
383
- display: flex;
384
- flex-direction: row;
385
- gap: 0.5rem;
386
- align-items: flex-end;
387
- justify-content: flex-end;
388
- }
389
-
390
- .control-button {
391
- margin: 0 !important;
392
- padding: 0.25rem !important;
393
- font-size: 14px !important;
394
- border-color: $app-primary-color !important;
395
- background: $app-primary-color !important;
396
- transition: all 0.25s ease;
397
-
398
- svg {
399
- margin: 0;
400
- }
401
-
402
- &,
403
- &:focus,
404
- &:active {
405
- box-shadow: none !important;
406
- }
407
-
408
- &:hover {
409
- background: $lightPurple !important;
410
- }
411
- }
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
-
427
- .visually-hidden {
428
- clip: rect(0 0 0 0);
429
- clip-path: inset(50%);
430
- height: 1px;
431
- overflow: hidden;
432
- position: absolute;
433
- white-space: nowrap;
434
- width: 1px;
435
- }
436
- </style>
437
-
438
- <style lang="scss">
439
- .el-popper.is-control-tooltip {
440
- padding: 4px 10px;
441
- font-family: Asap;
442
- background: #f3ecf6 !important;
443
- border: 1px solid $app-primary-color;
444
-
445
- & .el-popper__arrow::before {
446
- border: 1px solid;
447
- border-color: $app-primary-color;
448
- background: #f3ecf6;
449
- }
450
- }
451
- </style>