@abi-software/map-utilities 1.1.3-beta.1 → 1.1.3-beta.11

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.
@@ -25,9 +25,9 @@ import cytoscape from 'cytoscape'
25
25
 
26
26
  //==============================================================================
27
27
 
28
- export class ConnectivityGraph
28
+ export class ConnectivityGraph extends EventTarget
29
29
  {
30
- cy = null
30
+ cyg = null
31
31
  nodes = []
32
32
  edges = []
33
33
  axons = []
@@ -37,8 +37,9 @@ export class ConnectivityGraph
37
37
 
38
38
  constructor(labelCache, graphCanvas)
39
39
  {
40
- this.labelCache = labelCache;
41
- this.graphCanvas = graphCanvas;
40
+ super()
41
+ this.labelCache = labelCache;
42
+ this.graphCanvas = graphCanvas;
42
43
  }
43
44
 
44
45
  async addConnectivity(knowledge)
@@ -69,15 +70,56 @@ export class ConnectivityGraph
69
70
  showConnectivity(graphCanvas)
70
71
  //================
71
72
  {
72
- this.cy = new CytoscapeGraph(this, graphCanvas)
73
+ this.cyg = new CytoscapeGraph(this, graphCanvas)
74
+
75
+ this.cyg.on('tap-node', (event) => {
76
+ const tapEvent = new CustomEvent('tap-node', {
77
+ detail: event.detail
78
+ })
79
+ this.dispatchEvent(tapEvent);
80
+ });
73
81
  }
74
82
 
75
83
  clearConnectivity()
76
84
  //=================
77
85
  {
78
- if (this.cy) {
79
- this.cy.remove()
80
- this.cy = null
86
+ if (this.cyg?.cy) {
87
+ this.cyg.cy.remove()
88
+ this.cyg.cy = null
89
+ }
90
+ }
91
+
92
+ reset()
93
+ //=====
94
+ {
95
+ if (this.cyg?.cy) {
96
+ this.cyg.cy.reset()
97
+ }
98
+ }
99
+
100
+ zoom(val)
101
+ //=======
102
+ {
103
+ if (this.cyg?.cy) {
104
+ const currentZoom = this.cyg.cy.zoom()
105
+ const width = this.cyg.cy.width()
106
+ const height = this.cyg.cy.height()
107
+ const positionToRender = {
108
+ x: width/2,
109
+ y: height/2,
110
+ }
111
+ this.cyg.cy.zoom({
112
+ level: currentZoom + val,
113
+ renderedPosition: positionToRender,
114
+ })
115
+ }
116
+ }
117
+
118
+ enableZoom(option)
119
+ //================
120
+ {
121
+ if (this.cyg?.cy) {
122
+ this.cyg.cy.userZoomingEnabled(option)
81
123
  }
82
124
  }
83
125
 
@@ -124,6 +166,12 @@ export class ConnectivityGraph
124
166
  }
125
167
  return result
126
168
  }
169
+
170
+ on(eventName, callback)
171
+ //=====================
172
+ {
173
+ this.addEventListener(eventName, callback)
174
+ }
127
175
  }
128
176
 
129
177
  //==============================================================================
@@ -132,54 +180,83 @@ const GRAPH_STYLE = [
132
180
  {
133
181
  'selector': 'node',
134
182
  'style': {
135
- 'label': 'data(label)',
136
- 'background-color': '#80F0F0',
183
+ 'label': function(ele) { return trimLabel(ele.data('label')) },
184
+ // 'background-color': '#80F0F0',
185
+ 'background-color': 'transparent',
186
+ 'background-opacity': '0',
137
187
  'text-valign': 'center',
138
188
  'text-wrap': 'wrap',
189
+ 'width': '80px',
190
+ 'height': '80px',
139
191
  'text-max-width': '80px',
140
- 'font-size': '6px'
192
+ 'font-size': '6px',
193
+ 'shape': 'round-rectangle',
194
+ 'border-width': 1,
195
+ 'border-style': 'solid',
196
+ 'border-color': 'gray',
141
197
  }
142
198
  },
143
199
  {
144
200
  'selector': 'node[axon]',
145
201
  'style': {
146
- 'background-color': 'green'
202
+ // 'background-color': 'green',
203
+ 'shape': 'round-diamond',
204
+ 'width': '100px',
205
+ 'height': '100px',
147
206
  }
148
207
  },
149
208
  {
150
209
  'selector': 'node[dendrite]',
151
210
  'style': {
152
- 'background-color': 'red'
211
+ // 'background-color': 'red',
212
+ 'shape': 'ellipse',
153
213
  }
154
214
  },
155
215
  {
156
216
  'selector': 'node[both-a-d]',
157
217
  'style': {
158
- 'background-color': 'gray'
218
+ // 'background-color': 'gray',
219
+ 'shape': 'round-rectangle',
159
220
  }
160
221
  },
161
222
  {
162
223
  'selector': 'edge',
163
224
  'style': {
164
- 'width': 2,
165
- 'line-color': '#9dbaea',
166
- 'target-arrow-color': '#9dbaea',
225
+ 'width': 1,
226
+ 'line-color': 'dimgray',
227
+ 'target-arrow-color': 'dimgray',
167
228
  'target-arrow-shape': 'triangle',
168
229
  'curve-style': 'bezier'
169
230
  }
170
231
  }
171
232
  ]
172
233
 
234
+ function trimLabel(label) {
235
+ const labels = label.split('\n')
236
+ const half = labels.length/2
237
+ const trimLabels = labels.slice(half)
238
+ return trimLabels.join('\n')
239
+ }
240
+
241
+ function capitalizeLabels(input) {
242
+ return input.split('\n').map(label => {
243
+ if (label && label[0] >= 'a' && label[0] <= 'z') {
244
+ return label.charAt(0).toUpperCase() + label.slice(1)
245
+ }
246
+ return label
247
+ }).join('\n')
248
+ }
249
+
173
250
  //==============================================================================
174
251
 
175
- class CytoscapeGraph
252
+ class CytoscapeGraph extends EventTarget
176
253
  {
177
254
  cy
178
255
  tooltip
179
256
 
180
257
  constructor(connectivityGraph, graphCanvas)
181
258
  {
182
- // const graphCanvas = document.getElementById('graph-canvas')
259
+ super()
183
260
  this.cy = cytoscape({
184
261
  container: graphCanvas,
185
262
  elements: connectivityGraph.elements,
@@ -196,11 +273,12 @@ class CytoscapeGraph
196
273
  }).on('mouseover', 'node', this.overNode.bind(this))
197
274
  .on('mouseout', 'node', this.exitNode.bind(this))
198
275
  .on('position', 'node', this.moveNode.bind(this))
276
+ .on('tap', this.tapNode.bind(this))
199
277
 
200
278
  this.tooltip = document.createElement('div')
201
- this.tooltip.id = 'tooltip'
279
+ this.tooltip.className = 'cy-graph-tooltip'
202
280
  this.tooltip.hidden = true
203
- this.graphCanvas?.lastChild?.appendChild(this.tooltip)
281
+ graphCanvas?.lastChild?.appendChild(this.tooltip)
204
282
  }
205
283
 
206
284
  remove()
@@ -223,10 +301,14 @@ class CytoscapeGraph
223
301
  //==============
224
302
  {
225
303
  const node = event.target
226
- this.tooltip.innerText = node.data().label
304
+ const label = capitalizeLabels(node.data().label)
305
+
306
+ this.tooltip.innerText = label
227
307
  this.tooltip.style.left = `${event.renderedPosition.x}px`
228
308
  this.tooltip.style.top = `${event.renderedPosition.y}px`
309
+ this.tooltip.style.maxWidth = '240px'
229
310
  this.tooltip.hidden = false
311
+
230
312
  this.checkRightBoundary(event.renderedPosition.x)
231
313
  }
232
314
 
@@ -244,6 +326,23 @@ class CytoscapeGraph
244
326
  {
245
327
  this.tooltip.hidden = true
246
328
  }
329
+
330
+ tapNode(event)
331
+ //============
332
+ {
333
+ const node = event.target
334
+ const data = node.data()
335
+ const tapEvent = new CustomEvent('tap-node', {
336
+ detail: data
337
+ })
338
+ this.dispatchEvent(tapEvent);
339
+ }
340
+
341
+ on(eventName, callback)
342
+ //=====================
343
+ {
344
+ this.addEventListener(eventName, callback)
345
+ }
247
346
  }
248
347
 
249
348
  //==============================================================================
@@ -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.toLowerCase()) : 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);
@@ -18,6 +18,7 @@ declare module 'vue' {
18
18
  ElCol: typeof import('element-plus/es')['ElCol']
19
19
  ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
20
20
  ElIcon: typeof import('element-plus/es')['ElIcon']
21
+ ElIconAim: typeof import('@element-plus/icons-vue')['Aim']
21
22
  ElIconArrowDown: typeof import('@element-plus/icons-vue')['ArrowDown']
22
23
  ElIconArrowUp: typeof import('@element-plus/icons-vue')['ArrowUp']
23
24
  ElIconClose: typeof import('@element-plus/icons-vue')['Close']
@@ -25,7 +26,11 @@ declare module 'vue' {
25
26
  ElIconDelete: typeof import('@element-plus/icons-vue')['Delete']
26
27
  ElIconEdit: typeof import('@element-plus/icons-vue')['Edit']
27
28
  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']
28
31
  ElIconWarning: typeof import('@element-plus/icons-vue')['Warning']
32
+ ElIconZoomIn: typeof import('@element-plus/icons-vue')['ZoomIn']
33
+ ElIconZoomOut: typeof import('@element-plus/icons-vue')['ZoomOut']
29
34
  ElInput: typeof import('element-plus/es')['ElInput']
30
35
  ElMain: typeof import('element-plus/es')['ElMain']
31
36
  ElOption: typeof import('element-plus/es')['ElOption']