topo-engine 0.1.9 → 0.1.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.
- package/README.md +34 -5
- package/dist/index.d.ts +32 -1
- package/dist/style.css +63 -11
- package/dist/topo-engine.cjs +766 -63
- package/dist/topo-engine.cjs.map +1 -1
- package/dist/topo-engine.js +767 -64
- package/dist/topo-engine.js.map +1 -1
- package/dist/topo-engine.umd.cjs +766 -63
- package/dist/topo-engine.umd.cjs.map +1 -1
- package/docs/API.md +94 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
- 🧩 **Vue 3 组件** — `TopoGraph`(画布;可选左上工具条默认隐藏,`:toolbar` 开启)、`SidePanel`(设备详情与上下游)、`DistanceTop10`(父子连线距离 Top10 面板)
|
|
10
10
|
- 🎨 **深色 / 浅色双主题** — 黑底 SCADA 或白底两种画布风格,图元 / 导线 / 文字随之配套适配,可随时切换(`theme` prop 或工具栏按钮)。默认浅色主题
|
|
11
|
+
- 🗺 **图例** — 可选图例面板(`legend` prop,**默认关闭**):按当前图实际设备类别自动生成、颜色随主题,支持 `legendItems` 自定义项与点击折叠
|
|
11
12
|
- 📐 **自研正交布局** — 主干沿最长路径横向铺开 + 分支带垂直直走,整图**横平竖直、0 交叉、0 重叠**,边缘路由为直线 / L 形折线
|
|
12
13
|
- 🔍 **拓扑查询 API** — 节点 / 边 / 邻居 / 子树 / 主干链 / 路径 / 坐标 查询
|
|
13
14
|
- 🎨 **样式控制** — 节点、边样式覆盖与批量重置
|
|
@@ -192,7 +193,9 @@ const g6Data = buildGraphData(model, layout); // → G6 可直接消费的 { n
|
|
|
192
193
|
| `data` | `Object` | `null` | 直接传入 JSON 对象;优先级高于 `dataUrl`;深度 watch,变化自动重绘 |
|
|
193
194
|
| `customerData` | `Array` | `null` | 客户数据(`[{ psrId, consumerList }]`),注入计量箱并按户渲染 / 可点 |
|
|
194
195
|
| `theme` | `'dark' \| 'light'` | `'light'` | 画布主题:`dark`(黑底 SCADA)/ `light`(白底,图元配套加深,默认)。支持 `v-model:theme`,也可点内置工具栏 ☀️/🌙 按钮切换 |
|
|
195
|
-
| `toolbar` | `Boolean` | `false` | 是否显示左上工具条(标题 / 统计 / 主题 / 适应画布 / 导出 PNG),默认隐藏 |
|
|
196
|
+
| `toolbar` | `Boolean` | `false` | 是否显示左上工具条(标题 / 统计 / 主题 / 图例 / 适应画布 / 导出 PNG),默认隐藏 |
|
|
197
|
+
| `legend` | `Boolean` | `false` | **是否显示右下角图例面板,默认否**。支持 `v-model:legend`(开启 `toolbar` 后工具条内有 🗺 图例按钮)。图例按当前图**实际出现的设备类别**自动生成,颜色跟随主题;面板可点击标题折叠 |
|
|
198
|
+
| `legendItems` | `Array` | `null` | 自定义图例项(覆盖自动生成):`[{ label, shape, color?, text?, key? }]`。`shape` 可选 `transformer/switch/fuse/bus/cableTerminal/junction/meterBox/consumer/line/meterUser/station/edge` 或通用 `square/ring/triangle/hline/text/dot` |
|
|
196
199
|
|
|
197
200
|
### Emits
|
|
198
201
|
|
|
@@ -202,12 +205,37 @@ const g6Data = buildGraphData(model, layout); // → G6 可直接消费的 { n
|
|
|
202
205
|
| `node-select` | `{ node, upstream, downstream }`(均为解析后模型节点) | 点击节点(含金框选中与详情联动);空白清除时 `node=null` |
|
|
203
206
|
| `customer-select` | `{ node, customer, index, count, upstream, downstream }` | 点中计量箱内某个用户(展示客户档案) |
|
|
204
207
|
| `top-distances` | `Array<{ parent: {id,name,catLabel}, child: {id,name,catLabel}, distance }>`(≤10) | 渲染完成时,父-子连线折线长度 Top10(过滤站内边与主干鱼骨边) |
|
|
208
|
+
| `update:legend` | 新布尔值 | 工具条 🗺 图例按钮点击(配合 `v-model:legend`) |
|
|
209
|
+
|
|
210
|
+
### 图例(legend)
|
|
211
|
+
|
|
212
|
+
```vue
|
|
213
|
+
<!-- 默认不显示;开启即用(按图内容自动生成条目,颜色随主题) -->
|
|
214
|
+
<TopoGraph :data-url="'/data/topo.json'" legend />
|
|
215
|
+
|
|
216
|
+
<!-- 自定义图例项 -->
|
|
217
|
+
<TopoGraph
|
|
218
|
+
:data-url="'/data/topo.json'"
|
|
219
|
+
:legend="true"
|
|
220
|
+
:legend-items="[
|
|
221
|
+
{ label: '正常设备', shape: 'square', color: '#22C55E' },
|
|
222
|
+
{ label: '告警设备', shape: 'ring', color: '#EF4444' },
|
|
223
|
+
{ label: '停电', shape: 'triangle', color: '#9CA3AF' },
|
|
224
|
+
{ label: 'JX', shape: 'text', color: '#3A3A3A', text: 'JX' },
|
|
225
|
+
]"
|
|
226
|
+
/>
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
> 自动图例内容:配电变压器 / 开关 / 熔丝 / 低压母线 / 电缆终端头 / 密母分接点 / 计量箱 /
|
|
230
|
+
> 用户接入点 / 低压导线点 / 低压配电箱 / 其它设备(仅显示图中存在的),末尾固定为
|
|
231
|
+
> **主干导线 / 分支导线**,图中含计量箱客户数据时再追加 **客户电表**。
|
|
205
232
|
|
|
206
233
|
### 内置交互与 UI
|
|
207
234
|
|
|
208
235
|
- 滚轮缩放、拖拽平移、悬停高亮(上下游与连线),点击选中(金色虚框,再次点空白取消)。
|
|
209
236
|
- **计量箱用户点击**:单户箱整箱即该户;多户箱点电表格 / 户名 = 该户客户档案(悬停青圈、选中金圈),点箱体空白 = 选中整箱(事件 `consumer:click` / `customer-select`)。
|
|
210
|
-
- 左上角工具条**默认隐藏**:传 `:toolbar="true"` 后显示标题 / `节点 n · 边 m · 深度 d · 叶子 l` 统计 /
|
|
237
|
+
- 左上角工具条**默认隐藏**:传 `:toolbar="true"` 后显示标题 / `节点 n · 边 m · 深度 d · 叶子 l` 统计 / 🌙 主题 / 🗺 图例 /「适应画布」/「导出 PNG」按钮。
|
|
238
|
+
- **图例默认关闭**:传 `:legend="true"`(或 `v-model:legend`)后右下角出现图例面板,点击标题可折叠。
|
|
211
239
|
- 加载中 / 出错(如 dataUrl 404)有内置遮罩提示。
|
|
212
240
|
- 卸载时自动 `destroy()` 图实例与事件监听,无内存泄漏。
|
|
213
241
|
|
|
@@ -230,8 +258,7 @@ const g6Data = buildGraphData(model, layout); // → G6 可直接消费的 { n
|
|
|
230
258
|
|
|
231
259
|
引擎内置两套主题,**浅色为默认**(白底,图元配套深色,适合打印或嵌入浅色页面);深色为**黑底 SCADA 风格**。
|
|
232
260
|
|
|
233
|
-
- `TopoGraph`:`:theme` 取值 `'light'`(默认)或 `'dark'`,推荐 `v-model:theme` 双向绑定;开启 `:toolbar="true"` 后工具条内置 ☀️ / 🌙 切换按钮(点击 emit `update:theme
|
|
234
|
-
- `SidePanel` / `DistanceTop10`:同样接收 `theme` prop,与画布保持一致观感。
|
|
261
|
+
- `TopoGraph`:`:theme` 取值 `'light'`(默认)或 `'dark'`,推荐 `v-model:theme` 双向绑定;开启 `:toolbar="true"` 后工具条内置 ☀️ / 🌙 切换按钮(点击 emit `update:theme`)。- `SidePanel` / `DistanceTop10`:同样接收 `theme` prop,与画布保持一致观感。
|
|
235
262
|
- 切换主题会**按当前数据自动重建画布**:G6 画布背景、图元、边、标注文字全部随主题更新,布局不变。
|
|
236
263
|
|
|
237
264
|
```vue
|
|
@@ -268,6 +295,7 @@ const dataUrl = ref('/data/topology.json');
|
|
|
268
295
|
> topo.locateNode(assetNo); // 定位到某户表位中心
|
|
269
296
|
> topo.highlightNode(assetNo, { color: '#FF0000' }); // 该户表位高亮环
|
|
270
297
|
> topo.setNodeGlow(assetNo, { color: '#FF6600' }); // 该户表位光晕
|
|
298
|
+
> topo.setNodeGlow(assetNo, { blink: true, color: '#FF6600' }); // 该户表位整体闪烁
|
|
271
299
|
> topo.setNodePulse(assetNo); // 该户电表格脉动
|
|
272
300
|
> topo.setText(assetNo, '异常'); // 表位上方标注
|
|
273
301
|
> topo.showCard(assetNo); // 客户档案卡片(定位在表位旁)
|
|
@@ -337,7 +365,8 @@ topo.unhighlightAll();
|
|
|
337
365
|
|
|
338
366
|
```javascript
|
|
339
367
|
topo.setNodePulse('2', { color: '#00C8FF', duration: 1500 }); // 节点脉动
|
|
340
|
-
topo.setNodeGlow('2', { color: '#FF0000'
|
|
368
|
+
topo.setNodeGlow('2', { color: '#FF0000' }); // 节点光晕(多层光环 + shadowBlur 辉光 + blur 面光底衬;ref 支持 psrId)
|
|
369
|
+
topo.setNodeGlow('2', { color: '#FF0000', intensity: 2, spread: 30, blink: true, duration: 800 }); // 更夸张:加强 + 更大扩散 + 图元整体闪烁
|
|
341
370
|
topo.removeNodeGlow('2');
|
|
342
371
|
topo.setEdgeFlow('1', '2', { color: '#00C8FF', duration: 2000 }); // 边流动
|
|
343
372
|
topo.removeAnimation('2');
|
package/dist/index.d.ts
CHANGED
|
@@ -76,7 +76,24 @@ export class TopoApi {
|
|
|
76
76
|
removeAllAnimations(): void;
|
|
77
77
|
|
|
78
78
|
// 节点光晕动画(ref 支持节点 id / psrId / assetNo)
|
|
79
|
-
|
|
79
|
+
// 渲染栈:blur 柔光底衬 + 实心光块 → 图元 → 外扩散环 ×2 → 霓虹主环(shadowBlur) → 亮芯环
|
|
80
|
+
// intensity: 强度倍率(默认 1;1.5~2.5 更夸张,0.5~0.7 更收敛)
|
|
81
|
+
// spread: 光环外扩半径,默认按图元大小自适应(短边 ×0.7,16~46px)
|
|
82
|
+
// width: 主环初始线宽 (px),默认 5.6(户表位 3.6)
|
|
83
|
+
// blink: 图元「整体闪烁」——false 默认只画光环;true = 0.85;数字 0~1 为强度
|
|
84
|
+
setNodeGlow(ref: string, opts?: {
|
|
85
|
+
color?: string;
|
|
86
|
+
spread?: number;
|
|
87
|
+
radius?: number;
|
|
88
|
+
duration?: number;
|
|
89
|
+
opacity?: number;
|
|
90
|
+
width?: number;
|
|
91
|
+
intensity?: number;
|
|
92
|
+
level?: number;
|
|
93
|
+
strength?: number;
|
|
94
|
+
blink?: boolean | number;
|
|
95
|
+
flash?: boolean | number;
|
|
96
|
+
}): boolean;
|
|
80
97
|
removeNodeGlow(ref: string): boolean;
|
|
81
98
|
removeAllNodeGlows(): void;
|
|
82
99
|
|
|
@@ -123,6 +140,20 @@ export class TopoApi {
|
|
|
123
140
|
destroy(): void;
|
|
124
141
|
}
|
|
125
142
|
|
|
143
|
+
// 图例项(TopoGraph 组件 legend / legendItems 参数)
|
|
144
|
+
export type LegendShape =
|
|
145
|
+
| 'transformer' | 'switch' | 'fuse' | 'bus' | 'cableTerminal' | 'junction'
|
|
146
|
+
| 'meterBox' | 'consumer' | 'line' | 'meterUser' | 'station' | 'edge'
|
|
147
|
+
| 'square' | 'ring' | 'triangle' | 'hline' | 'text' | 'dot';
|
|
148
|
+
|
|
149
|
+
export interface LegendItem {
|
|
150
|
+
key?: string; // 唯一键(可选)
|
|
151
|
+
label: string; // 显示文字
|
|
152
|
+
shape?: LegendShape; // 图标形状,默认 'dot'
|
|
153
|
+
color?: string; // 覆盖色(不传用当前主题色)
|
|
154
|
+
text?: string; // shape='text' 时的文字(默认 'JX')
|
|
155
|
+
}
|
|
156
|
+
|
|
126
157
|
// 工具函数
|
|
127
158
|
export function parseTopo(raw: object): any;
|
|
128
159
|
export function computeOrthogonalLayout(model: any, options?: object): any;
|
package/dist/style.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
/* —— 主题变量:dark 为默认值,light 由 [data-theme='light'] 覆盖 —— */
|
|
3
|
-
.topo-wrap[data-v-
|
|
3
|
+
.topo-wrap[data-v-0736fa17] {
|
|
4
4
|
--tp-bg: #050505;
|
|
5
5
|
--tp-toolbar-bg: rgba(20, 20, 20, 0.88);
|
|
6
6
|
--tp-toolbar-border: #333;
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
overflow: hidden;
|
|
20
20
|
background: var(--tp-bg);
|
|
21
21
|
}
|
|
22
|
-
.topo-wrap[data-theme='light'][data-v-
|
|
22
|
+
.topo-wrap[data-theme='light'][data-v-0736fa17] {
|
|
23
23
|
--tp-bg: #ffffff;
|
|
24
24
|
--tp-toolbar-bg: rgba(255, 255, 255, 0.92);
|
|
25
25
|
--tp-toolbar-border: #d9d9d9;
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
--tp-text: #555;
|
|
34
34
|
--tp-error: #d32f2f;
|
|
35
35
|
}
|
|
36
|
-
.topo-container[data-v-
|
|
36
|
+
.topo-container[data-v-0736fa17] {
|
|
37
37
|
width: 100%;
|
|
38
38
|
height: 100%;
|
|
39
39
|
}
|
|
40
|
-
.topo-toolbar[data-v-
|
|
40
|
+
.topo-toolbar[data-v-0736fa17] {
|
|
41
41
|
position: absolute;
|
|
42
42
|
top: 10px;
|
|
43
43
|
left: 12px;
|
|
@@ -52,14 +52,14 @@
|
|
|
52
52
|
color: var(--tp-text);
|
|
53
53
|
z-index: 10;
|
|
54
54
|
}
|
|
55
|
-
.topo-title[data-v-
|
|
55
|
+
.topo-title[data-v-0736fa17] {
|
|
56
56
|
color: var(--tp-title);
|
|
57
57
|
font-weight: 600;
|
|
58
58
|
}
|
|
59
|
-
.topo-meta[data-v-
|
|
59
|
+
.topo-meta[data-v-0736fa17] {
|
|
60
60
|
color: var(--tp-meta);
|
|
61
61
|
}
|
|
62
|
-
.btn[data-v-
|
|
62
|
+
.btn[data-v-0736fa17] {
|
|
63
63
|
margin-left: 4px;
|
|
64
64
|
padding: 3px 10px;
|
|
65
65
|
border: 1px solid var(--tp-btn-border);
|
|
@@ -69,12 +69,64 @@
|
|
|
69
69
|
cursor: pointer;
|
|
70
70
|
font-size: 12px;
|
|
71
71
|
}
|
|
72
|
-
.btn[data-v-
|
|
72
|
+
.btn[data-v-0736fa17]:hover {
|
|
73
73
|
border-color: var(--tp-accent);
|
|
74
74
|
color: var(--tp-accent);
|
|
75
|
+
}
|
|
76
|
+
/* —— 图例(legend prop 开启后显示) —— */
|
|
77
|
+
.topo-legend[data-v-0736fa17] {
|
|
78
|
+
position: absolute;
|
|
79
|
+
right: 12px;
|
|
80
|
+
bottom: 12px;
|
|
81
|
+
z-index: 9;
|
|
82
|
+
min-width: 132px;
|
|
83
|
+
max-width: 240px;
|
|
84
|
+
max-height: 62%;
|
|
85
|
+
overflow: auto;
|
|
86
|
+
padding: 8px 10px;
|
|
87
|
+
background: var(--tp-toolbar-bg);
|
|
88
|
+
border: 1px solid var(--tp-toolbar-border);
|
|
89
|
+
border-radius: 6px;
|
|
90
|
+
font-size: 12px;
|
|
91
|
+
color: var(--tp-text);
|
|
92
|
+
pointer-events: auto;
|
|
93
|
+
}
|
|
94
|
+
.topo-legend-title[data-v-0736fa17] {
|
|
95
|
+
display: flex;
|
|
96
|
+
align-items: center;
|
|
97
|
+
gap: 4px;
|
|
98
|
+
color: var(--tp-title);
|
|
99
|
+
font-weight: 600;
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
user-select: none;
|
|
102
|
+
}
|
|
103
|
+
.topo-legend-arrow[data-v-0736fa17] {
|
|
104
|
+
display: inline-block;
|
|
105
|
+
transition: transform 0.15s ease;
|
|
106
|
+
transform: rotate(0deg);
|
|
107
|
+
}
|
|
108
|
+
.topo-legend-arrow.open[data-v-0736fa17] {
|
|
109
|
+
transform: rotate(90deg);
|
|
110
|
+
}
|
|
111
|
+
.topo-legend-body[data-v-0736fa17] {
|
|
112
|
+
margin-top: 6px;
|
|
113
|
+
}
|
|
114
|
+
.topo-legend-row[data-v-0736fa17] {
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
gap: 6px;
|
|
118
|
+
padding: 1px 0;
|
|
119
|
+
white-space: nowrap;
|
|
120
|
+
}
|
|
121
|
+
.topo-legend-icon[data-v-0736fa17] {
|
|
122
|
+
flex: none;
|
|
123
|
+
}
|
|
124
|
+
.topo-legend-label[data-v-0736fa17] {
|
|
125
|
+
color: var(--tp-text);
|
|
126
|
+
line-height: 1.2;
|
|
75
127
|
}
|
|
76
|
-
.topo-loading[data-v-
|
|
77
|
-
.topo-error[data-v-
|
|
128
|
+
.topo-loading[data-v-0736fa17],
|
|
129
|
+
.topo-error[data-v-0736fa17] {
|
|
78
130
|
position: absolute;
|
|
79
131
|
inset: 0;
|
|
80
132
|
display: flex;
|
|
@@ -85,7 +137,7 @@
|
|
|
85
137
|
z-index: 5;
|
|
86
138
|
background: var(--tp-overlay-bg);
|
|
87
139
|
}
|
|
88
|
-
.topo-error[data-v-
|
|
140
|
+
.topo-error[data-v-0736fa17] {
|
|
89
141
|
color: var(--tp-error);
|
|
90
142
|
}
|
|
91
143
|
|