topo-engine 0.1.6 → 0.1.7
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/README.md +19 -6
- package/dist/index.d.ts +9 -2
- package/dist/style.css +71 -42
- package/dist/topo-engine.cjs +10509 -9940
- package/dist/topo-engine.cjs.map +1 -1
- package/dist/topo-engine.js +10510 -9941
- package/dist/topo-engine.js.map +1 -1
- package/dist/topo-engine.umd.cjs +10509 -9940
- package/dist/topo-engine.umd.cjs.map +1 -1
- package/docs/API.md +1246 -0
- package/package.json +3 -2
package/docs/API.md
ADDED
|
@@ -0,0 +1,1246 @@
|
|
|
1
|
+
# 拓扑引擎 API 参考手册
|
|
2
|
+
|
|
3
|
+
> `topo-engine` v1.0 · 基于 Vue3 + G6 v5 + 自研正交布局引擎
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 目录
|
|
8
|
+
|
|
9
|
+
- [快速开始](#快速开始)
|
|
10
|
+
- [类型定义](#类型定义)
|
|
11
|
+
- [一、查询 API](#一查询-api)
|
|
12
|
+
- [二、视图控制](#二视图控制)
|
|
13
|
+
- [三、节点样式](#三节点样式)
|
|
14
|
+
- [四、边样式](#四边样式)
|
|
15
|
+
- [五、高亮与标注](#五高亮与标注)
|
|
16
|
+
- [六、动画](#六动画)
|
|
17
|
+
- [七、文字标注](#七文字标注)
|
|
18
|
+
- [八、卡片盒](#八卡片盒)
|
|
19
|
+
- [九、连接线与拓扑线](#九连接线与拓扑线)
|
|
20
|
+
- [十、事件系统](#十事件系统)
|
|
21
|
+
- [十一、导出](#十一导出)
|
|
22
|
+
- [十二、生命周期](#十二生命周期)
|
|
23
|
+
- [十三、TopoGraph 组件 Props / Events 与计量箱客户交互](#十三topograph-组件-props--events-与计量箱客户交互)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 快速开始
|
|
28
|
+
|
|
29
|
+
```vue
|
|
30
|
+
<template>
|
|
31
|
+
<TopoGraph ref="topo" data-url="/data/sample.json" />
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script setup>
|
|
35
|
+
import { ref, onMounted } from 'vue';
|
|
36
|
+
import TopoGraph from './components/TopoGraph.vue';
|
|
37
|
+
|
|
38
|
+
const topo = ref(null);
|
|
39
|
+
|
|
40
|
+
onMounted(async () => {
|
|
41
|
+
// 等待图渲染完成
|
|
42
|
+
await new Promise(r => setTimeout(r, 500));
|
|
43
|
+
|
|
44
|
+
// 查询节点
|
|
45
|
+
const nodes = topo.value.findNodes({ cat: 'transformer' });
|
|
46
|
+
|
|
47
|
+
// 定位到第一个变压器
|
|
48
|
+
if (nodes.length) {
|
|
49
|
+
topo.value.locateNode(nodes[0].id, 1.5);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 高亮 + 标注
|
|
53
|
+
topo.value.highlightNode(nodes[0].id, {
|
|
54
|
+
color: '#FF0000',
|
|
55
|
+
label: '异常',
|
|
56
|
+
labelColor: '#FF0000',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 监听事件
|
|
60
|
+
topo.value.on('node:click', ({ nodeId, node }) => {
|
|
61
|
+
console.log('点击:', node.name);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
</script>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 类型定义
|
|
70
|
+
|
|
71
|
+
### NodeData
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
interface NodeData {
|
|
75
|
+
id: string; // 唯一标识(String)
|
|
76
|
+
psrId: string; // PMS PSR 编号
|
|
77
|
+
psrType: string; // PMS 类型码(如 '0302', '3301')
|
|
78
|
+
symbolId: string; // PMS 设备编码
|
|
79
|
+
name: string; // 完整名称
|
|
80
|
+
shortName: string; // 简称
|
|
81
|
+
cat: string; // 设备类别(见下表)
|
|
82
|
+
catLabel: string; // 类别中文名
|
|
83
|
+
status: string; // 状态码('0'=正常)
|
|
84
|
+
insideStation: boolean;// 是否在站房内部
|
|
85
|
+
isLine: boolean; // 是否为导线
|
|
86
|
+
isFuse: boolean; // 是否为熔丝
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 设备类别(cat)
|
|
91
|
+
|
|
92
|
+
| cat | 中文 | 尺寸 (w×h) |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `transformer` | 配电变压器 | 56×26 |
|
|
95
|
+
| `fuse` | 熔丝 | 56×20 |
|
|
96
|
+
| `switch` | 开关 | 60×24 |
|
|
97
|
+
| `bus` | 低压母线 | 40×12 |
|
|
98
|
+
| `cableTerminal` | 电缆终端头 | 18×22 |
|
|
99
|
+
| `stationTerminal` | 站内终端头 | 24×14 |
|
|
100
|
+
| `meterBox` | 计量箱 | 21×21 |
|
|
101
|
+
| `consumer` | 用户接入点 | 30×30 |
|
|
102
|
+
| `line` | 导线/连接点 | 12×12 |
|
|
103
|
+
| `junction` | 密母分接点 | 12×12 |
|
|
104
|
+
| `station` | 低压配电箱(站房框) | 动态 |
|
|
105
|
+
| `other` | 其他 | 20×20 |
|
|
106
|
+
|
|
107
|
+
### EdgeData
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
interface EdgeData {
|
|
111
|
+
source: string; // 起点节点 ID
|
|
112
|
+
target: string; // 终点节点 ID
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### HighlightOptions
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
interface HighlightOptions {
|
|
120
|
+
color?: string; // 高亮色,默认 '#FFD700'(金色)
|
|
121
|
+
label?: string; // 可选标注文字
|
|
122
|
+
labelColor?: string; // 标注颜色,默认 '#FFFFFF'
|
|
123
|
+
labelSize?: number; // 标注字号,默认 12
|
|
124
|
+
borderColor?: string; // 边框色(覆盖 color)
|
|
125
|
+
borderStyle?: 'solid' | 'dashed'; // 边框样式,默认 'dashed'
|
|
126
|
+
borderWidth?: number; // 边框粗细,默认 2
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### NodeStyle
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
interface NodeStyle {
|
|
134
|
+
stroke?: string; // 描边颜色
|
|
135
|
+
strokeWidth?: number; // 描边粗细
|
|
136
|
+
fill?: string; // 背景填充
|
|
137
|
+
opacity?: number; // 透明度 (0-1)
|
|
138
|
+
visible?: boolean; // 是否可见
|
|
139
|
+
cursor?: string; // 鼠标样式
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### EdgeStyle
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
interface EdgeStyle {
|
|
147
|
+
stroke?: string; // 颜色
|
|
148
|
+
lineWidth?: number; // 线宽
|
|
149
|
+
opacity?: number; // 透明度
|
|
150
|
+
lineDash?: number[]; // 虚线样式
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### PulseOptions
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
interface PulseOptions {
|
|
158
|
+
color?: string; // 脉动颜色,默认 '#00C8FF'
|
|
159
|
+
duration?: number; // 周期 (ms),默认 1500
|
|
160
|
+
maxScale?: number; // 最大缩放,默认 1.3
|
|
161
|
+
minScale?: number; // 最小缩放,默认 1.0
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### FlowOptions
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
interface FlowOptions {
|
|
169
|
+
color?: string; // 流动颜色,默认 '#00C8FF'
|
|
170
|
+
duration?: number; // 周期 (ms),默认 2000
|
|
171
|
+
width?: number; // 线宽,默认 3
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### CardContent
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
interface CardContent {
|
|
179
|
+
title?: string;
|
|
180
|
+
fields?: Array<{ label: string; value: string }>;
|
|
181
|
+
buttons?: Array<{ text: string; onClick: () => void; type?: 'primary' | 'default' }>;
|
|
182
|
+
closable?: boolean; // 是否可关闭,默认 true
|
|
183
|
+
width?: number; // 卡片宽度,默认 240
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### ConnectionOptions
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
interface ConnectionOptions {
|
|
191
|
+
color?: string; // 颜色,默认 '#00C8FF'
|
|
192
|
+
width?: number; // 线宽,默认 2
|
|
193
|
+
style?: 'solid' | 'dashed'; // 样式,默认 'solid'
|
|
194
|
+
midArrow?: boolean; // 沿线简洁方向标记(开口 ›),默认 true
|
|
195
|
+
arrowSize?: number; // 方向标记尺寸,默认 7
|
|
196
|
+
arrowGap?: number; // 标记间距,默认 60(更小=更多标记)
|
|
197
|
+
startArrow?: boolean; // 起点贴边箭头(需显式 true)
|
|
198
|
+
endArrow?: boolean; // 终点贴边箭头(需显式 true)
|
|
199
|
+
label?: string; // 可选标签
|
|
200
|
+
animated?: boolean; // 是否流动动画(场景覆盖线暂未实现)
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 一、查询 API
|
|
207
|
+
|
|
208
|
+
### `getNode(nodeId)`
|
|
209
|
+
|
|
210
|
+
获取单个节点完整数据。
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
getNode(nodeId: string): NodeData | null
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**参数:**
|
|
217
|
+
- `nodeId` — 节点 ID
|
|
218
|
+
|
|
219
|
+
**返回:** 节点数据对象,未找到返回 `null`
|
|
220
|
+
|
|
221
|
+
**示例:**
|
|
222
|
+
```js
|
|
223
|
+
const node = topo.getNode('123');
|
|
224
|
+
console.log(node.name, node.catLabel); // "上屋胡2#台区柱上变" "配电变压器"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### `getAllNodes()`
|
|
230
|
+
|
|
231
|
+
获取所有节点。
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
getAllNodes(): NodeData[]
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**返回:** 节点数组(只读副本)
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
### `findNodes(filter)`
|
|
242
|
+
|
|
243
|
+
按条件查找节点,多条件 AND 组合。
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
findNodes(filter: NodeFilter): NodeData[]
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**filter 支持的字段:**
|
|
250
|
+
|
|
251
|
+
| 字段 | 类型 | 匹配方式 |
|
|
252
|
+
|---|---|---|
|
|
253
|
+
| `psrId` | `string` | 精确匹配 |
|
|
254
|
+
| `symbolId` | `string` | 精确匹配 |
|
|
255
|
+
| `cat` | `string` | 精确匹配 |
|
|
256
|
+
| `psrType` | `string` | 精确匹配 |
|
|
257
|
+
| `name` | `string \| RegExp` | 包含 / 正则匹配 |
|
|
258
|
+
| `shortName` | `string \| RegExp` | 包含 / 正则匹配 |
|
|
259
|
+
| `status` | `string` | 精确匹配 |
|
|
260
|
+
| `insideStation` | `boolean` | 精确匹配 |
|
|
261
|
+
|
|
262
|
+
**示例:**
|
|
263
|
+
```js
|
|
264
|
+
// 查找所有变压器
|
|
265
|
+
const transformers = topo.findNodes({ cat: 'transformer' });
|
|
266
|
+
|
|
267
|
+
// 查找名称含"开关"的设备
|
|
268
|
+
const switches = topo.findNodes({ name: /开关/ });
|
|
269
|
+
|
|
270
|
+
// 组合条件:站房内的正常设备
|
|
271
|
+
const inner = topo.findNodes({ insideStation: true, status: '0' });
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
### `getSelectedId()`
|
|
277
|
+
|
|
278
|
+
获取当前选中节点 ID。
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
getSelectedId(): string | null
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
### `getNeighbors(nodeId)`
|
|
287
|
+
|
|
288
|
+
获取指定节点的上下游邻居。
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
getNeighbors(nodeId: string): { upstream: NodeData[]; downstream: NodeData[] }
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**示例:**
|
|
295
|
+
```js
|
|
296
|
+
const { upstream, downstream } = topo.getNeighbors('123');
|
|
297
|
+
console.log(`上游 ${upstream.length} 个,下游 ${downstream.length} 个`);
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
### `getStreamNodes(nodeId, direction)`
|
|
303
|
+
|
|
304
|
+
沿拓扑流向获取节点链(BFS 遍历)。
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
getStreamNodes(nodeId: string, direction: 'upstream' | 'downstream'): NodeData[]
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**参数:**
|
|
311
|
+
- `nodeId` — 起始节点 ID
|
|
312
|
+
- `direction` — `'upstream'`(向上游/电源侧)或 `'downstream'`(向下游/负荷侧)
|
|
313
|
+
|
|
314
|
+
**示例:**
|
|
315
|
+
```js
|
|
316
|
+
// 获取某节点的所有下游节点
|
|
317
|
+
const downstream = topo.getStreamNodes('123', 'downstream');
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
### `getTrunkNodes()`
|
|
323
|
+
|
|
324
|
+
获取主干链节点(从根节点沿叶子数最多路径一直走的链)。
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
getTrunkNodes(): NodeData[]
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
### `getSubtreeNodes(nodeId)`
|
|
333
|
+
|
|
334
|
+
获取以指定节点为根的子树中所有节点。
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
getSubtreeNodes(nodeId: string): NodeData[]
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
### `getPath(fromId, toId)`
|
|
343
|
+
|
|
344
|
+
获取两个节点之间的拓扑路径。
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
getPath(fromId: string, toId: string): NodeData[] | null
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
**返回:** 路径节点数组(含首尾),不可达返回 `null`
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### `getEdge(srcId, tgtId)`
|
|
355
|
+
|
|
356
|
+
获取指定边。
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
getEdge(srcId: string, tgtId: string): EdgeData | null
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
### `getEdges()`
|
|
365
|
+
|
|
366
|
+
获取所有边。
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
getEdges(): EdgeData[]
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
### `getStreamEdges(nodeId, direction)`
|
|
375
|
+
|
|
376
|
+
沿流向获取边集合(分路导线着色用)。
|
|
377
|
+
|
|
378
|
+
```ts
|
|
379
|
+
getStreamEdges(nodeId: string, direction: 'upstream' | 'downstream'): EdgeData[]
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
### `getMainEdge()`
|
|
385
|
+
|
|
386
|
+
获取主干边(非鱼骨肋骨、非站房内部、非末端分支)。
|
|
387
|
+
|
|
388
|
+
```ts
|
|
389
|
+
getMainEdge(): EdgeData[]
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
### `getNodePosition(nodeId)`
|
|
395
|
+
|
|
396
|
+
获取节点在画布中的坐标。
|
|
397
|
+
|
|
398
|
+
```ts
|
|
399
|
+
getNodePosition(nodeId: string): { x: number; y: number } | null
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
### `getEdgePath(srcId, tgtId)`
|
|
405
|
+
|
|
406
|
+
获取边的折线控制点序列(含端点)。
|
|
407
|
+
|
|
408
|
+
```ts
|
|
409
|
+
getEdgePath(srcId: string, tgtId: string): [number, number][] | null
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
### `getGraphBounds()`
|
|
415
|
+
|
|
416
|
+
获取图整体边界。
|
|
417
|
+
|
|
418
|
+
```ts
|
|
419
|
+
getGraphBounds(): { minX: number; minY: number; maxX: number; maxY: number }
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
### `getStats()`
|
|
425
|
+
|
|
426
|
+
获取拓扑统计信息。
|
|
427
|
+
|
|
428
|
+
```ts
|
|
429
|
+
getStats(): {
|
|
430
|
+
total: number; // 节点总数
|
|
431
|
+
depth: number; // 最大深度
|
|
432
|
+
leaves: number; // 叶子节点数
|
|
433
|
+
byCat: Record<string, number>; // 按类别统计
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## 二、视图控制
|
|
440
|
+
|
|
441
|
+
### `fitView(padding?)`
|
|
442
|
+
|
|
443
|
+
适配画布到视口。
|
|
444
|
+
|
|
445
|
+
```ts
|
|
446
|
+
fitView(padding?: number): void
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**参数:**
|
|
450
|
+
- `padding` — 内边距(px),默认 `30`
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
### `zoomTo(ratio, center?)`
|
|
455
|
+
|
|
456
|
+
缩放到指定比例。
|
|
457
|
+
|
|
458
|
+
```ts
|
|
459
|
+
zoomTo(ratio: number, center?: { x: number; y: number }): void
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
**参数:**
|
|
463
|
+
- `ratio` — 缩放比例(`1` = 100%,`2` = 200%)
|
|
464
|
+
- `center` — 缩放中心(画布坐标),默认视口中心
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
### `zoomIn(step?)`
|
|
469
|
+
|
|
470
|
+
放大一级。
|
|
471
|
+
|
|
472
|
+
```ts
|
|
473
|
+
zoomIn(step?: number): void
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
**参数:**
|
|
477
|
+
- `step` — 放大倍率增量,默认 `0.2`(即放大 20%)
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
### `zoomOut(step?)`
|
|
482
|
+
|
|
483
|
+
缩小一级。
|
|
484
|
+
|
|
485
|
+
```ts
|
|
486
|
+
zoomOut(step?: number): void
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
**参数:**
|
|
490
|
+
- `step` — 缩小倍率减量,默认 `0.2`
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
### `locateNode(nodeId, zoom?)`
|
|
495
|
+
|
|
496
|
+
定位节点到视口中央,可选缩放。
|
|
497
|
+
|
|
498
|
+
```ts
|
|
499
|
+
locateNode(nodeId: string, zoom?: number): void
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
**参数:**
|
|
503
|
+
- `nodeId` — 要定位的节点 ID
|
|
504
|
+
- `zoom` — 可选的目标缩放比例
|
|
505
|
+
|
|
506
|
+
**示例:**
|
|
507
|
+
```js
|
|
508
|
+
// 定位到节点,保持当前缩放
|
|
509
|
+
topo.locateNode('123');
|
|
510
|
+
|
|
511
|
+
// 定位到节点,放大到 2 倍
|
|
512
|
+
topo.locateNode('123', 2);
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
### `getViewport()`
|
|
518
|
+
|
|
519
|
+
获取当前视口状态。
|
|
520
|
+
|
|
521
|
+
```ts
|
|
522
|
+
getViewport(): { zoom: number; center: { x: number; y: number } }
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## 三、节点样式
|
|
528
|
+
|
|
529
|
+
### `setNodeStyle(nodeId, style)`
|
|
530
|
+
|
|
531
|
+
设置单个节点的视觉样式。
|
|
532
|
+
|
|
533
|
+
```ts
|
|
534
|
+
setNodeStyle(nodeId: string, style: NodeStyle): void
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
**示例:**
|
|
538
|
+
```js
|
|
539
|
+
// 给节点加红色描边
|
|
540
|
+
topo.setNodeStyle('123', { stroke: '#FF0000', strokeWidth: 2 });
|
|
541
|
+
|
|
542
|
+
// 降低透明度
|
|
543
|
+
topo.setNodeStyle('123', { opacity: 0.3 });
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
### `batchSetNodeStyle(nodeIds, style)`
|
|
549
|
+
|
|
550
|
+
批量设置节点样式。
|
|
551
|
+
|
|
552
|
+
```ts
|
|
553
|
+
batchSetNodeStyle(nodeIds: string[], style: NodeStyle): void
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
### `resetNodeStyle(nodeId)`
|
|
559
|
+
|
|
560
|
+
重置单个节点为默认样式。
|
|
561
|
+
|
|
562
|
+
```ts
|
|
563
|
+
resetNodeStyle(nodeId: string): void
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
### `resetAllNodeStyles()`
|
|
569
|
+
|
|
570
|
+
重置所有节点为默认样式。
|
|
571
|
+
|
|
572
|
+
```ts
|
|
573
|
+
resetAllNodeStyles(): void
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## 四、边样式
|
|
579
|
+
|
|
580
|
+
### `setEdgeStyle(srcId, tgtId, style)`
|
|
581
|
+
|
|
582
|
+
设置边的视觉样式。
|
|
583
|
+
|
|
584
|
+
```ts
|
|
585
|
+
setEdgeStyle(srcId: string, tgtId: string, style: EdgeStyle): void
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
**示例:**
|
|
589
|
+
```js
|
|
590
|
+
// 导线变红加粗
|
|
591
|
+
topo.setEdgeStyle('A', 'B', { stroke: '#FF0000', lineWidth: 3 });
|
|
592
|
+
|
|
593
|
+
// 虚线
|
|
594
|
+
topo.setEdgeStyle('A', 'B', { lineDash: [5, 3] });
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
### `batchSetEdgeStyle(edgeIds, style)`
|
|
600
|
+
|
|
601
|
+
批量设置边样式。
|
|
602
|
+
|
|
603
|
+
```ts
|
|
604
|
+
batchSetEdgeStyle(edgeIds: Array<[string, string]>, style: EdgeStyle): void
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
### `resetEdgeStyle(srcId, tgtId)`
|
|
610
|
+
|
|
611
|
+
重置边为默认样式。
|
|
612
|
+
|
|
613
|
+
```ts
|
|
614
|
+
resetEdgeStyle(srcId: string, tgtId: string): void
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
## 五、高亮与标注
|
|
620
|
+
|
|
621
|
+
### `highlightNode(nodeId, options?)`
|
|
622
|
+
|
|
623
|
+
高亮节点(选中效果 + 可选文字标注)。
|
|
624
|
+
|
|
625
|
+
```ts
|
|
626
|
+
highlightNode(nodeId: string, options?: HighlightOptions): void
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
**示例:**
|
|
630
|
+
```js
|
|
631
|
+
// 金色高亮
|
|
632
|
+
topo.highlightNode('123');
|
|
633
|
+
|
|
634
|
+
// 红色高亮 + "停电" 标注
|
|
635
|
+
topo.highlightNode('123', {
|
|
636
|
+
color: '#FF0000',
|
|
637
|
+
label: '停电',
|
|
638
|
+
labelColor: '#FF0000',
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
// 绿色虚线高亮 + "正常" 标注
|
|
642
|
+
topo.highlightNode('123', {
|
|
643
|
+
color: '#00FF00',
|
|
644
|
+
label: '正常',
|
|
645
|
+
borderStyle: 'dashed',
|
|
646
|
+
});
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
---
|
|
650
|
+
|
|
651
|
+
### `unhighlightNode(nodeId)`
|
|
652
|
+
|
|
653
|
+
取消节点高亮并移除标注。
|
|
654
|
+
|
|
655
|
+
```ts
|
|
656
|
+
unhighlightNode(nodeId: string): void
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
### `highlightPath(nodeIds, options?)`
|
|
662
|
+
|
|
663
|
+
高亮一组节点和它们之间的边(路径高亮)。
|
|
664
|
+
|
|
665
|
+
```ts
|
|
666
|
+
highlightPath(nodeIds: string[], options?: HighlightOptions & { edgeColor?: string }): void
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
**示例:**
|
|
670
|
+
```js
|
|
671
|
+
// 高亮从电源到某用户的路径
|
|
672
|
+
const path = topo.getPath('root', 'user123');
|
|
673
|
+
if (path) {
|
|
674
|
+
topo.highlightPath(path.map(n => n.id), { color: '#00FF00', label: '供电路径' });
|
|
675
|
+
}
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
### `unhighlightAll()`
|
|
681
|
+
|
|
682
|
+
取消所有高亮和标注。
|
|
683
|
+
|
|
684
|
+
```ts
|
|
685
|
+
unhighlightAll(): void
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
---
|
|
689
|
+
|
|
690
|
+
### `dimOthers(keepIds, opacity?)`
|
|
691
|
+
|
|
692
|
+
将非指定节点变暗(聚焦效果)。
|
|
693
|
+
|
|
694
|
+
```ts
|
|
695
|
+
dimOthers(keepIds: string[], opacity?: number): void
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
**参数:**
|
|
699
|
+
- `keepIds` — 保持正常的节点 ID 列表
|
|
700
|
+
- `opacity` — 变暗透明度,默认 `0.15`
|
|
701
|
+
|
|
702
|
+
**示例:**
|
|
703
|
+
```js
|
|
704
|
+
// 聚焦某节点及其上下游
|
|
705
|
+
const { upstream, downstream } = topo.getNeighbors('123');
|
|
706
|
+
const keep = ['123', ...upstream.map(n => n.id), ...downstream.map(n => n.id)];
|
|
707
|
+
topo.dimOthers(keep, 0.15);
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
712
|
+
## 六、动画
|
|
713
|
+
|
|
714
|
+
### `setNodePulse(nodeId, options?)`
|
|
715
|
+
|
|
716
|
+
节点脉动/光晕动画。
|
|
717
|
+
|
|
718
|
+
```ts
|
|
719
|
+
setNodePulse(nodeId: string, options?: PulseOptions): void
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
**示例:**
|
|
723
|
+
```js
|
|
724
|
+
topo.setNodePulse('123', { color: '#FF0000', duration: 1500 });
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
---
|
|
728
|
+
|
|
729
|
+
### `setNodeGlow(nodeId, options?)`
|
|
730
|
+
|
|
731
|
+
节点发光效果。
|
|
732
|
+
|
|
733
|
+
```ts
|
|
734
|
+
setNodeGlow(nodeId: string, options?: { color?: string; radius?: number }): void
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
---
|
|
738
|
+
|
|
739
|
+
### `setEdgeFlow(srcId, tgtId, options?)`
|
|
740
|
+
|
|
741
|
+
边流动动画(视觉流动效果)。
|
|
742
|
+
|
|
743
|
+
```ts
|
|
744
|
+
setEdgeFlow(srcId: string, tgtId: string, options?: FlowOptions): void
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
**示例:**
|
|
748
|
+
```js
|
|
749
|
+
topo.setEdgeFlow('A', 'B', { color: '#00C8FF', duration: 2000 });
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
---
|
|
753
|
+
|
|
754
|
+
### `setEdgePulse(srcId, tgtId, options?)`
|
|
755
|
+
|
|
756
|
+
边脉动动画(线宽周期变化)。
|
|
757
|
+
|
|
758
|
+
```ts
|
|
759
|
+
setEdgePulse(srcId: string, tgtId: string, options?: { color?: string; duration?: number }): void
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
---
|
|
763
|
+
|
|
764
|
+
### `removeAnimation(targetId)`
|
|
765
|
+
|
|
766
|
+
移除指定元素的动画。
|
|
767
|
+
|
|
768
|
+
```ts
|
|
769
|
+
removeAnimation(targetId: string): void
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
---
|
|
773
|
+
|
|
774
|
+
### `removeAllAnimations()`
|
|
775
|
+
|
|
776
|
+
移除所有动画。
|
|
777
|
+
|
|
778
|
+
```ts
|
|
779
|
+
removeAllAnimations(): void
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
---
|
|
783
|
+
|
|
784
|
+
## 七、文字标注
|
|
785
|
+
|
|
786
|
+
### `setText(nodeId, text, options?)`
|
|
787
|
+
|
|
788
|
+
在节点旁设置附加文字。
|
|
789
|
+
|
|
790
|
+
```ts
|
|
791
|
+
setText(nodeId: string, text: string, options?: {
|
|
792
|
+
fontSize?: number; // 默认 12
|
|
793
|
+
color?: string; // 默认 '#FFFFFF'
|
|
794
|
+
position?: 'top' | 'bottom' | 'left' | 'right'; // 默认 'top'
|
|
795
|
+
offset?: number; // 偏移量 (px),默认 4
|
|
796
|
+
}): void
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
**示例:**
|
|
800
|
+
```js
|
|
801
|
+
topo.setText('123', '突变(3次)', { color: '#FF4444', position: 'top' });
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
---
|
|
805
|
+
|
|
806
|
+
### `removeText(nodeId)`
|
|
807
|
+
|
|
808
|
+
移除指定节点的附加文字。
|
|
809
|
+
|
|
810
|
+
```ts
|
|
811
|
+
removeText(nodeId: string): void
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
---
|
|
815
|
+
|
|
816
|
+
### `removeAllTexts()`
|
|
817
|
+
|
|
818
|
+
移除所有附加文字。
|
|
819
|
+
|
|
820
|
+
```ts
|
|
821
|
+
removeAllTexts(): void
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
---
|
|
825
|
+
|
|
826
|
+
### `setDeviceText(cat, fontSize)`
|
|
827
|
+
|
|
828
|
+
按设备类型统一设置文字字号。
|
|
829
|
+
|
|
830
|
+
```ts
|
|
831
|
+
setDeviceText(cat: string, fontSize: number): void
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
**示例:**
|
|
835
|
+
```js
|
|
836
|
+
// 所有用户接入点字号设为 15
|
|
837
|
+
topo.setDeviceText('consumer', 15);
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
---
|
|
841
|
+
|
|
842
|
+
### `changeUserName(mode)`
|
|
843
|
+
|
|
844
|
+
切换所有用户名的显示方式。
|
|
845
|
+
|
|
846
|
+
```ts
|
|
847
|
+
changeUserName(mode: 'full' | 'short' | 'hidden'): void
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
**参数:**
|
|
851
|
+
- `'full'` — 显示完整名称
|
|
852
|
+
- `'short'` — 显示简称
|
|
853
|
+
- `'hidden'` — 隐藏名称
|
|
854
|
+
|
|
855
|
+
---
|
|
856
|
+
|
|
857
|
+
## 八、卡片盒
|
|
858
|
+
|
|
859
|
+
### `showCard(nodeId, content)`
|
|
860
|
+
|
|
861
|
+
在节点旁弹出信息卡片。
|
|
862
|
+
|
|
863
|
+
```ts
|
|
864
|
+
showCard(nodeId: string, content: CardContent): void
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
**示例:**
|
|
868
|
+
```js
|
|
869
|
+
topo.showCard('123', {
|
|
870
|
+
title: '设备信息',
|
|
871
|
+
fields: [
|
|
872
|
+
{ label: '设备类型', value: '配电变压器' },
|
|
873
|
+
{ label: 'PSR编号', value: 'GDDW000123' },
|
|
874
|
+
{ label: '状态', value: '正常' },
|
|
875
|
+
],
|
|
876
|
+
buttons: [
|
|
877
|
+
{ text: '查看运行曲线', type: 'primary', onClick: () => openChart('123') },
|
|
878
|
+
{ text: '查看量测曲线', onClick: () => openMeasure('123') },
|
|
879
|
+
],
|
|
880
|
+
});
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
---
|
|
884
|
+
|
|
885
|
+
### `hideCard(nodeId)`
|
|
886
|
+
|
|
887
|
+
关闭指定节点的卡片。
|
|
888
|
+
|
|
889
|
+
```ts
|
|
890
|
+
hideCard(nodeId: string): void
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
---
|
|
894
|
+
|
|
895
|
+
### `hideAllCards()`
|
|
896
|
+
|
|
897
|
+
关闭所有卡片。
|
|
898
|
+
|
|
899
|
+
```ts
|
|
900
|
+
hideAllCards(): void
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
---
|
|
904
|
+
|
|
905
|
+
## 九、连接线与拓扑线
|
|
906
|
+
|
|
907
|
+
### `addConnection(fromId, toId, options?)`
|
|
908
|
+
|
|
909
|
+
添加动态连接线(不参与布局/拓扑查询,直接绘制进 **G6 画布场景最上层**,
|
|
910
|
+
随画布缩放平移自动对齐)。默认**中心对中心直线 + 沿线若干简洁方向标记**
|
|
911
|
+
(开口 › 形、数量随线长自动增减、非实心,样式干净)。
|
|
912
|
+
|
|
913
|
+
**端点支持两种引用:**
|
|
914
|
+
1. **普通设备节点** —— 用该节点的 **`psrId`(设备编码)**(兼容节点内部 id);
|
|
915
|
+
变压器/开关/计量箱/用户接入点等均适用;
|
|
916
|
+
2. **箱内用户** —— 用客户档案里的 **`assetNo`(资产编号)**(兼容 `consNo`/`consId`),
|
|
917
|
+
自动落到该户表位中心 → 支持 **节点↔用户、用户↔用户**(可跨箱、可同箱内两户)。
|
|
918
|
+
|
|
919
|
+
```ts
|
|
920
|
+
addConnection(fromId: string, toId: string, options?: ConnectionOptions): string | false
|
|
921
|
+
// options: { color?, width?, style?: 'solid'|'dashed',
|
|
922
|
+
// midArrow?: boolean, // 沿线方向标记,默认 true
|
|
923
|
+
// arrowSize?: number, // 标记尺寸,默认 7
|
|
924
|
+
// arrowGap?: number, // 标记间距,默认 60
|
|
925
|
+
// startArrow?: boolean, endArrow?: boolean, // 显式 true 才画贴边两端箭头
|
|
926
|
+
// }
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
**示例:**
|
|
930
|
+
```js
|
|
931
|
+
// 节点(psrId)→ 某户(assetNo),橙色虚线 + 沿线方向标记(默认)
|
|
932
|
+
topo.addConnection('4241005000000040735831', '4230000100014444282', {
|
|
933
|
+
color: '#FF6600', width: 2, style: 'dashed',
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
// 户 ↔ 户(assetNo),方向标记更密更大
|
|
937
|
+
topo.addConnection('4230000100014444282', '4230000100014410530', {
|
|
938
|
+
color: '#00C8FF', arrowGap: 40, arrowSize: 9,
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
// 纯直线:midArrow: false
|
|
942
|
+
topo.addConnection('4241005000000040735831', '4230000100014444282', { midArrow: false });
|
|
943
|
+
|
|
944
|
+
// 想要贴边两端实心箭头:startArrow: true / endArrow: true
|
|
945
|
+
topo.addConnection('4241005000000040735831', '4230000100014444282', {
|
|
946
|
+
startArrow: true, endArrow: true,
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
// 解析调试:topo.resolveUserRef('4230000100014444282') → `${计量箱节点id}#cust${下标}`(无匹配为 null)
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
---
|
|
953
|
+
|
|
954
|
+
### `removeConnection(fromId, toId)`
|
|
955
|
+
|
|
956
|
+
移除动态连接线。
|
|
957
|
+
|
|
958
|
+
```ts
|
|
959
|
+
removeConnection(fromId: string, toId: string): void
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
---
|
|
963
|
+
|
|
964
|
+
### `removeAllConnections()`
|
|
965
|
+
|
|
966
|
+
移除所有动态连接线。
|
|
967
|
+
|
|
968
|
+
```ts
|
|
969
|
+
removeAllConnections(): void
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
---
|
|
973
|
+
|
|
974
|
+
### `addTopoLine(nodeIds, options?)`
|
|
975
|
+
|
|
976
|
+
沿节点路径添加拓扑高亮线(高亮已有边)。
|
|
977
|
+
|
|
978
|
+
```ts
|
|
979
|
+
addTopoLine(nodeIds: string[], options?: {
|
|
980
|
+
color?: string; // 高亮色,默认 '#00C8FF'
|
|
981
|
+
width?: number; // 线宽,默认 3
|
|
982
|
+
id?: string; // 线 ID(用于后续移除),默认自动生成
|
|
983
|
+
}): string // 返回线 ID
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
**示例:**
|
|
987
|
+
```js
|
|
988
|
+
// 高亮从变压器到用户的路径
|
|
989
|
+
const path = topo.getPath('transformer1', 'user456');
|
|
990
|
+
const lineId = topo.addTopoLine(path.map(n => n.id), { color: '#FF0000' });
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
---
|
|
994
|
+
|
|
995
|
+
### `removeTopoLine(id)`
|
|
996
|
+
|
|
997
|
+
移除拓扑高亮线。
|
|
998
|
+
|
|
999
|
+
```ts
|
|
1000
|
+
removeTopoLine(id: string): void
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
---
|
|
1004
|
+
|
|
1005
|
+
### `removeAllTopoLines()`
|
|
1006
|
+
|
|
1007
|
+
移除所有拓扑高亮线。
|
|
1008
|
+
|
|
1009
|
+
```ts
|
|
1010
|
+
removeAllTopoLines(): void
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
---
|
|
1014
|
+
|
|
1015
|
+
## 十、事件系统
|
|
1016
|
+
|
|
1017
|
+
### `on(event, handler)`
|
|
1018
|
+
|
|
1019
|
+
监听事件。
|
|
1020
|
+
|
|
1021
|
+
```ts
|
|
1022
|
+
on(event: string, handler: Function): void
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
---
|
|
1026
|
+
|
|
1027
|
+
### `off(event, handler?)`
|
|
1028
|
+
|
|
1029
|
+
移除监听。不传 handler 则移除该事件的所有监听。
|
|
1030
|
+
|
|
1031
|
+
```ts
|
|
1032
|
+
off(event: string, handler?: Function): void
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
---
|
|
1036
|
+
|
|
1037
|
+
### 标准事件列表
|
|
1038
|
+
|
|
1039
|
+
| 事件名 | 触发时机 | Payload |
|
|
1040
|
+
|---|---|---|
|
|
1041
|
+
| `node:click` | 单击节点 | `{ nodeId, node, event }` |
|
|
1042
|
+
| `node:dblclick` | 双击节点 | `{ nodeId, node, event }` |
|
|
1043
|
+
| `node:hover` | 鼠标进入节点 | `{ nodeId, node }` |
|
|
1044
|
+
| `node:unhover` | 鼠标离开节点 | `{ nodeId }` |
|
|
1045
|
+
| `edge:click` | 单击边 | `{ edgeId, source, target }` |
|
|
1046
|
+
| `canvas:click` | 单击空白区域 | `{ event }` |
|
|
1047
|
+
| `viewport:change` | 缩放/平移后 | `{ zoom, center }` |
|
|
1048
|
+
| `card:button` | 点击卡片按钮 | `{ nodeId, buttonIndex }` |
|
|
1049
|
+
| `consumer:click` | 点击计量箱内用户(多户箱点格子;单户箱整箱即该户) | `{ nodeId, index, customer, node }` |
|
|
1050
|
+
|
|
1051
|
+
> `consumer:click`:点中计量箱内的用户时触发——
|
|
1052
|
+
> 多用户箱(`_meterBoxMode='grid'`)点中箱内具体用户电表格;
|
|
1053
|
+
> 单用户箱(`_meterBoxMode='single'`)整箱即“这一个用户”,点击即触发。
|
|
1054
|
+
> `index` 为该用户在箱内客户列表 `consumerList` 中的下标;`customer` 为该客户档案
|
|
1055
|
+
> (含 `consId/consNo/consName/meterId/assetNo/realConsName` 等字段,视数据源而定)。
|
|
1056
|
+
> 多用户箱点击空白/外框仍按普通 `node:click` 选中整只计量箱。
|
|
1057
|
+
|
|
1058
|
+
**示例:**
|
|
1059
|
+
```js
|
|
1060
|
+
// 节点点击 → 弹卡片
|
|
1061
|
+
topo.on('node:click', ({ nodeId, node }) => {
|
|
1062
|
+
topo.showCard(nodeId, {
|
|
1063
|
+
title: node.name,
|
|
1064
|
+
fields: [
|
|
1065
|
+
{ label: '类型', value: node.catLabel },
|
|
1066
|
+
{ label: '编号', value: node.psrId },
|
|
1067
|
+
],
|
|
1068
|
+
});
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
// 鼠标悬停 → 高亮上下游
|
|
1072
|
+
topo.on('node:hover', ({ nodeId }) => {
|
|
1073
|
+
const { upstream, downstream } = topo.getNeighbors(nodeId);
|
|
1074
|
+
const keep = [nodeId, ...upstream.map(n => n.id), ...downstream.map(n => n.id)];
|
|
1075
|
+
topo.dimOthers(keep);
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
topo.on('node:unhover', () => {
|
|
1079
|
+
topo.resetAllNodeStyles();
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
// 点击空白 → 清除所有
|
|
1083
|
+
topo.on('canvas:click', () => {
|
|
1084
|
+
topo.unhighlightAll();
|
|
1085
|
+
topo.hideAllCards();
|
|
1086
|
+
topo.resetAllNodeStyles();
|
|
1087
|
+
});
|
|
1088
|
+
|
|
1089
|
+
// 多用户计量箱:点中箱内单个用户 → 打印客户档案
|
|
1090
|
+
topo.on('consumer:click', ({ nodeId, index, customer, node }) => {
|
|
1091
|
+
console.log(`箱 ${node.name} 内第 ${index + 1} 户`, customer);
|
|
1092
|
+
});
|
|
1093
|
+
// 也可编程式选中:topo.selectCustomer(nodeId, index)
|
|
1094
|
+
// 或查询当前选中用户:topo.getSelectedCustomer() → { nodeId, index, customer, node } | null
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
---
|
|
1098
|
+
|
|
1099
|
+
## 十一、导出
|
|
1100
|
+
|
|
1101
|
+
### `exportPng(filename?)`
|
|
1102
|
+
|
|
1103
|
+
导出整图为 PNG 文件并触发下载。
|
|
1104
|
+
|
|
1105
|
+
```ts
|
|
1106
|
+
exportPng(filename?: string): void
|
|
1107
|
+
```
|
|
1108
|
+
|
|
1109
|
+
**参数:**
|
|
1110
|
+
- `filename` — 文件名(不含扩展名),默认使用图标题
|
|
1111
|
+
|
|
1112
|
+
---
|
|
1113
|
+
|
|
1114
|
+
### `toDataURL(options?)`
|
|
1115
|
+
|
|
1116
|
+
获取图片 DataURL(不触发下载)。
|
|
1117
|
+
|
|
1118
|
+
```ts
|
|
1119
|
+
toDataURL(options?: {
|
|
1120
|
+
mode?: 'overall' | 'viewport'; // 默认 'overall'(整图)
|
|
1121
|
+
type?: 'image/png' | 'image/jpeg'; // 默认 'image/png'
|
|
1122
|
+
quality?: number; // JPEG 质量 (0-1)
|
|
1123
|
+
}): Promise<string>
|
|
1124
|
+
```
|
|
1125
|
+
|
|
1126
|
+
---
|
|
1127
|
+
|
|
1128
|
+
### `getGraphData()`
|
|
1129
|
+
|
|
1130
|
+
获取当前图的完整数据(可序列化为 JSON)。
|
|
1131
|
+
|
|
1132
|
+
```ts
|
|
1133
|
+
getGraphData(): {
|
|
1134
|
+
model: object; // 解析后的模型数据
|
|
1135
|
+
layout: {
|
|
1136
|
+
pos: Record<string, { x: number; y: number }>;
|
|
1137
|
+
bounds: object;
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
---
|
|
1143
|
+
|
|
1144
|
+
## 十二、生命周期
|
|
1145
|
+
|
|
1146
|
+
### `loadRaw(text)`
|
|
1147
|
+
|
|
1148
|
+
加载本地 JSON 文本并重新渲染。
|
|
1149
|
+
|
|
1150
|
+
```ts
|
|
1151
|
+
loadRaw(text: string): void
|
|
1152
|
+
```
|
|
1153
|
+
|
|
1154
|
+
---
|
|
1155
|
+
|
|
1156
|
+
### `destroy()`
|
|
1157
|
+
|
|
1158
|
+
销毁图实例,释放资源。组件卸载时自动调用。
|
|
1159
|
+
|
|
1160
|
+
```ts
|
|
1161
|
+
destroy(): void
|
|
1162
|
+
```
|
|
1163
|
+
|
|
1164
|
+
---
|
|
1165
|
+
|
|
1166
|
+
## 十三、TopoGraph 组件 Props / Events 与计量箱客户交互
|
|
1167
|
+
|
|
1168
|
+
> 前面章节的 API 均通过 `TopoGraph` 组件 ref 直接调用(组件把 `TopoApi` 全部方法代理到自身)。
|
|
1169
|
+
|
|
1170
|
+
### Props
|
|
1171
|
+
|
|
1172
|
+
| prop | 类型 | 默认 | 说明 |
|
|
1173
|
+
|---|---|---|---|
|
|
1174
|
+
| `data` | `Object` | `null` | 直接传入台区 JSON(优先于 `dataUrl`) |
|
|
1175
|
+
| `dataUrl` | `String` | `''` | 数据地址,内部 `fetch` 加载 |
|
|
1176
|
+
| `customerData` | `Array` | `null` | 客户数据(计量箱关联用户),见下 |
|
|
1177
|
+
| `theme` | `'dark' \| 'light'` | `'light'` | 画布/图元/导线主题,支持 `v-model:theme` |
|
|
1178
|
+
| `toolbar` | `Boolean` | `false` | 是否显示左上工具条(标题/统计/主题/适应画布/导出 PNG),默认隐藏 |
|
|
1179
|
+
|
|
1180
|
+
### Events(Vue 组件事件)
|
|
1181
|
+
|
|
1182
|
+
| 事件 | 触发时机 | payload |
|
|
1183
|
+
|---|---|---|
|
|
1184
|
+
| `node-select` | 点击节点 / 空白清除 | `{ node, upstream, downstream }`(空白处 `node=null`) |
|
|
1185
|
+
| `customer-select` | 点中计量箱内某个用户 | `{ node, customer, index, count, upstream, downstream }` |
|
|
1186
|
+
| `loaded` | 渲染完成 | `{ stats, title }` |
|
|
1187
|
+
| `top-distances` | Top10 距离计算完成 | `Array` |
|
|
1188
|
+
| `update:theme` | 点击主题切换 | 新主题值 |
|
|
1189
|
+
|
|
1190
|
+
### 组件 ref 上的快捷方法
|
|
1191
|
+
|
|
1192
|
+
`resetView()`、`exportPng()`、`selectNode(id)`、`selectCustomer(nodeId, index)`、
|
|
1193
|
+
`getSelectedCustomer()`(`{ nodeId, index, customer, node } \| null`);
|
|
1194
|
+
其余 `TopoApi` 方法(查询/样式/高亮/动画/卡片/连接线…)全部直接可用。
|
|
1195
|
+
|
|
1196
|
+
### 计量箱客户数据 → 渲染与交互
|
|
1197
|
+
|
|
1198
|
+
通过 `:customer-data` 传入,格式为数组:每项 `{ psrId, consumerList: [...] }`,
|
|
1199
|
+
`psrId` 对应台区 JSON 中计量箱节点的 PSR 编号:
|
|
1200
|
+
|
|
1201
|
+
```json
|
|
1202
|
+
[{
|
|
1203
|
+
"psrId": "4230000000109100079",
|
|
1204
|
+
"consumerList": [
|
|
1205
|
+
{ "assetNo": "4230010007008084768", "consNo": "4219930230186",
|
|
1206
|
+
"consId": "4226040301216283", "meterId": "4225112000503099", "realConsName": "郭勋豪" }
|
|
1207
|
+
]
|
|
1208
|
+
}]
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
- **渲染形态**:
|
|
1212
|
+
- 单户(1 户)→ 电表图标 + 户名(整箱即“这一个用户”);
|
|
1213
|
+
- 多户(2 户起)→ 外框内按网格排电表,每格 = 1 户(≤20 户显示户名,超过只显电表);
|
|
1214
|
+
- 无客户数据 → 保持原始 `JX` 图元。
|
|
1215
|
+
- **点击语义**:
|
|
1216
|
+
- 单户箱:点击整箱任意位置 = 点中该户;
|
|
1217
|
+
- 多户箱:点某个电表格/户名 = 点中该户;点箱体空白/外框 = 选中整箱;
|
|
1218
|
+
- 悬停某户青圈提示,选中金圈高亮。
|
|
1219
|
+
- **编程式选中 / 事件**:`selectCustomer(nodeId, index)`、`getSelectedCustomer()`、
|
|
1220
|
+
事件 `consumer:click`(见第十章)与组件事件 `customer-select`。
|
|
1221
|
+
- **用户级连线**:连接线的端点可用客户档案 `assetNo`(兼容 `consNo`/`consId`)直接引用(见第九章),
|
|
1222
|
+
连线终点会自动落到该户表位。
|
|
1223
|
+
|
|
1224
|
+
---
|
|
1225
|
+
|
|
1226
|
+
## 附录:G6 v5 底层实例访问
|
|
1227
|
+
|
|
1228
|
+
如需使用 G6 v5 原生 API(上述封装未覆盖的能力),可通过以下方式获取底层实例:
|
|
1229
|
+
|
|
1230
|
+
```ts
|
|
1231
|
+
getGraphInstance(): Graph | null
|
|
1232
|
+
```
|
|
1233
|
+
|
|
1234
|
+
> ⚠️ **注意:** 直接操作 G6 实例可能导致与引擎内部状态不一致,建议优先使用上述封装 API。
|
|
1235
|
+
|
|
1236
|
+
---
|
|
1237
|
+
|
|
1238
|
+
## 附录:引擎数据访问
|
|
1239
|
+
|
|
1240
|
+
如需直接访问引擎内部数据结构:
|
|
1241
|
+
|
|
1242
|
+
```ts
|
|
1243
|
+
getModel(): object // parseTopo 输出的完整模型
|
|
1244
|
+
getLayoutData(): object // computeOrthogonalLayout 输出的完整布局数据
|
|
1245
|
+
getNodeByIdMap(): Map // ID → NodeData 的 O(1) 查找表
|
|
1246
|
+
```
|