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

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,81 @@ 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',
147
204
  }
148
205
  },
149
206
  {
150
207
  'selector': 'node[dendrite]',
151
208
  'style': {
152
- 'background-color': 'red'
209
+ // 'background-color': 'red',
210
+ 'shape': 'ellipse',
153
211
  }
154
212
  },
155
213
  {
156
214
  'selector': 'node[both-a-d]',
157
215
  'style': {
158
- 'background-color': 'gray'
216
+ // 'background-color': 'gray',
217
+ 'shape': 'round-rectangle',
159
218
  }
160
219
  },
161
220
  {
162
221
  'selector': 'edge',
163
222
  'style': {
164
- 'width': 2,
165
- 'line-color': '#9dbaea',
166
- 'target-arrow-color': '#9dbaea',
223
+ 'width': 1,
224
+ 'line-color': 'dimgray',
225
+ 'target-arrow-color': 'dimgray',
167
226
  'target-arrow-shape': 'triangle',
168
227
  'curve-style': 'bezier'
169
228
  }
170
229
  }
171
230
  ]
172
231
 
232
+ function trimLabel(label) {
233
+ const labels = label.split('\n')
234
+ const half = labels.length/2
235
+ const trimLabels = labels.slice(half)
236
+ return trimLabels.join('\n')
237
+ }
238
+
239
+ function capitalizeLabels(input) {
240
+ return input.split('\n').map(label => {
241
+ if (label && label[0] >= 'a' && label[0] <= 'z') {
242
+ return label.charAt(0).toUpperCase() + label.slice(1)
243
+ }
244
+ return label
245
+ }).join('\n')
246
+ }
247
+
173
248
  //==============================================================================
174
249
 
175
- class CytoscapeGraph
250
+ class CytoscapeGraph extends EventTarget
176
251
  {
177
252
  cy
178
253
  tooltip
179
254
 
180
255
  constructor(connectivityGraph, graphCanvas)
181
256
  {
182
- // const graphCanvas = document.getElementById('graph-canvas')
257
+ super()
183
258
  this.cy = cytoscape({
184
259
  container: graphCanvas,
185
260
  elements: connectivityGraph.elements,
@@ -196,11 +271,12 @@ class CytoscapeGraph
196
271
  }).on('mouseover', 'node', this.overNode.bind(this))
197
272
  .on('mouseout', 'node', this.exitNode.bind(this))
198
273
  .on('position', 'node', this.moveNode.bind(this))
274
+ .on('tap', this.tapNode.bind(this))
199
275
 
200
276
  this.tooltip = document.createElement('div')
201
- this.tooltip.id = 'tooltip'
277
+ this.tooltip.className = 'cy-graph-tooltip'
202
278
  this.tooltip.hidden = true
203
- this.graphCanvas?.lastChild?.appendChild(this.tooltip)
279
+ graphCanvas?.lastChild?.appendChild(this.tooltip)
204
280
  }
205
281
 
206
282
  remove()
@@ -223,10 +299,14 @@ class CytoscapeGraph
223
299
  //==============
224
300
  {
225
301
  const node = event.target
226
- this.tooltip.innerText = node.data().label
302
+ const label = capitalizeLabels(node.data().label)
303
+
304
+ this.tooltip.innerText = label
227
305
  this.tooltip.style.left = `${event.renderedPosition.x}px`
228
306
  this.tooltip.style.top = `${event.renderedPosition.y}px`
307
+ this.tooltip.style.maxWidth = '240px'
229
308
  this.tooltip.hidden = false
309
+
230
310
  this.checkRightBoundary(event.renderedPosition.x)
231
311
  }
232
312
 
@@ -244,6 +324,23 @@ class CytoscapeGraph
244
324
  {
245
325
  this.tooltip.hidden = true
246
326
  }
327
+
328
+ tapNode(event)
329
+ //============
330
+ {
331
+ const node = event.target
332
+ const data = node.data()
333
+ const tapEvent = new CustomEvent('tap-node', {
334
+ detail: data
335
+ })
336
+ this.dispatchEvent(tapEvent);
337
+ }
338
+
339
+ on(eventName, callback)
340
+ //=====================
341
+ {
342
+ this.addEventListener(eventName, callback)
343
+ }
247
344
  }
248
345
 
249
346
  //==============================================================================
@@ -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']