topo-engine 0.1.10 → 0.1.12
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 +48 -8
- package/dist/index.d.ts +14 -0
- package/dist/style.css +63 -11
- package/dist/topo-engine.cjs +826 -80
- package/dist/topo-engine.cjs.map +1 -1
- package/dist/topo-engine.js +827 -81
- package/dist/topo-engine.js.map +1 -1
- package/dist/topo-engine.umd.cjs +826 -80
- package/dist/topo-engine.umd.cjs.map +1 -1
- package/docs/API.md +48 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,9 @@
|
|
|
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 形折线
|
|
13
|
+
- 🏢 **站房/公配室多母线** — 站内含多条母线时**母线并排**(同一水平线);**母联开关经「半矩形(⊔)」走线连接两母线**(母线端向下 → 水平 → 母联开关 → 水平 → 向上),母联短名为「母联」并居中显示在 ⊔ 内部;其余开关各挂各自母线;单母线站房行为不变
|
|
12
14
|
- 🔍 **拓扑查询 API** — 节点 / 边 / 邻居 / 子树 / 主干链 / 路径 / 坐标 查询
|
|
13
15
|
- 🎨 **样式控制** — 节点、边样式覆盖与批量重置
|
|
14
16
|
- 🎨 **节点 / 电表染色** — 按 **psrId(设备编码)** 染普通节点、按 **assetNo(资产编号)** 染计量箱内电表户(状态色、告警色场景)
|
|
@@ -173,12 +175,12 @@ const g6Data = buildGraphData(model, layout); // → G6 可直接消费的 { n
|
|
|
173
175
|
|
|
174
176
|
| psrType | 类别 | 渲染 |
|
|
175
177
|
| ------- | ---- | ---- |
|
|
176
|
-
| `0302` |
|
|
177
|
-
| `3301` | 开关 / 熔丝 | 红色矩形(开关名自动缩写为 K 编号) |
|
|
178
|
+
| `0302` / `0110` | 配电变压器(柱上变) | 橙色圆 + 红圈 |
|
|
179
|
+
| `3301` / `321500000` | 开关 / 熔丝 | 红色矩形(开关名自动缩写为 K 编号) |
|
|
178
180
|
| `3303` | 低压母线 | 白色短粗线(无文字标签) |
|
|
179
181
|
| `3202` / `320300000` | 电缆终端头 / 分接点 | 三角 / 红色米字(无文字标签) |
|
|
180
|
-
| `310100000` |
|
|
181
|
-
| `3112` | 计量箱 | 黑底白框 "JX"(有客户数据时显示为电能表图标 + 用户名) |
|
|
182
|
+
| `310100000` / `3201` / `3102` / `3101` | 低压导线(含电杆/导线分段) | 青色连接点(名称缩写为杆号区间) |
|
|
183
|
+
| `3112` / `31120003` | 计量箱 | 黑底白框 "JX"(有客户数据时显示为电能表图标 + 用户名) |
|
|
182
184
|
| `3218000` | 用户接入点 | 白圈 "J"(名称缩写为户号) |
|
|
183
185
|
| `32500000` | 低压配电箱(台区) | 站房 |
|
|
184
186
|
|
|
@@ -192,7 +194,9 @@ const g6Data = buildGraphData(model, layout); // → G6 可直接消费的 { n
|
|
|
192
194
|
| `data` | `Object` | `null` | 直接传入 JSON 对象;优先级高于 `dataUrl`;深度 watch,变化自动重绘 |
|
|
193
195
|
| `customerData` | `Array` | `null` | 客户数据(`[{ psrId, consumerList }]`),注入计量箱并按户渲染 / 可点 |
|
|
194
196
|
| `theme` | `'dark' \| 'light'` | `'light'` | 画布主题:`dark`(黑底 SCADA)/ `light`(白底,图元配套加深,默认)。支持 `v-model:theme`,也可点内置工具栏 ☀️/🌙 按钮切换 |
|
|
195
|
-
| `toolbar` | `Boolean` | `false` | 是否显示左上工具条(标题 / 统计 / 主题 / 适应画布 / 导出 PNG),默认隐藏 |
|
|
197
|
+
| `toolbar` | `Boolean` | `false` | 是否显示左上工具条(标题 / 统计 / 主题 / 图例 / 适应画布 / 导出 PNG),默认隐藏 |
|
|
198
|
+
| `legend` | `Boolean` | `false` | **是否显示右下角图例面板,默认否**。支持 `v-model:legend`(开启 `toolbar` 后工具条内有 🗺 图例按钮)。图例按当前图**实际出现的设备类别**自动生成,颜色跟随主题;面板可点击标题折叠 |
|
|
199
|
+
| `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
200
|
|
|
197
201
|
### Emits
|
|
198
202
|
|
|
@@ -202,12 +206,37 @@ const g6Data = buildGraphData(model, layout); // → G6 可直接消费的 { n
|
|
|
202
206
|
| `node-select` | `{ node, upstream, downstream }`(均为解析后模型节点) | 点击节点(含金框选中与详情联动);空白清除时 `node=null` |
|
|
203
207
|
| `customer-select` | `{ node, customer, index, count, upstream, downstream }` | 点中计量箱内某个用户(展示客户档案) |
|
|
204
208
|
| `top-distances` | `Array<{ parent: {id,name,catLabel}, child: {id,name,catLabel}, distance }>`(≤10) | 渲染完成时,父-子连线折线长度 Top10(过滤站内边与主干鱼骨边) |
|
|
209
|
+
| `update:legend` | 新布尔值 | 工具条 🗺 图例按钮点击(配合 `v-model:legend`) |
|
|
210
|
+
|
|
211
|
+
### 图例(legend)
|
|
212
|
+
|
|
213
|
+
```vue
|
|
214
|
+
<!-- 默认不显示;开启即用(按图内容自动生成条目,颜色随主题) -->
|
|
215
|
+
<TopoGraph :data-url="'/data/topo.json'" legend />
|
|
216
|
+
|
|
217
|
+
<!-- 自定义图例项 -->
|
|
218
|
+
<TopoGraph
|
|
219
|
+
:data-url="'/data/topo.json'"
|
|
220
|
+
:legend="true"
|
|
221
|
+
:legend-items="[
|
|
222
|
+
{ label: '正常设备', shape: 'square', color: '#22C55E' },
|
|
223
|
+
{ label: '告警设备', shape: 'ring', color: '#EF4444' },
|
|
224
|
+
{ label: '停电', shape: 'triangle', color: '#9CA3AF' },
|
|
225
|
+
{ label: 'JX', shape: 'text', color: '#3A3A3A', text: 'JX' },
|
|
226
|
+
]"
|
|
227
|
+
/>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
> 自动图例内容:配电变压器 / 开关 / 熔丝 / 低压母线 / 电缆终端头 / 密母分接点 / 计量箱 /
|
|
231
|
+
> 用户接入点 / 低压导线点 / 低压配电箱 / 其它设备(仅显示图中存在的),末尾固定为
|
|
232
|
+
> **主干导线 / 分支导线**,图中含计量箱客户数据时再追加 **客户电表**。
|
|
205
233
|
|
|
206
234
|
### 内置交互与 UI
|
|
207
235
|
|
|
208
236
|
- 滚轮缩放、拖拽平移、悬停高亮(上下游与连线),点击选中(金色虚框,再次点空白取消)。
|
|
209
237
|
- **计量箱用户点击**:单户箱整箱即该户;多户箱点电表格 / 户名 = 该户客户档案(悬停青圈、选中金圈),点箱体空白 = 选中整箱(事件 `consumer:click` / `customer-select`)。
|
|
210
|
-
- 左上角工具条**默认隐藏**:传 `:toolbar="true"` 后显示标题 / `节点 n · 边 m · 深度 d · 叶子 l` 统计 /
|
|
238
|
+
- 左上角工具条**默认隐藏**:传 `:toolbar="true"` 后显示标题 / `节点 n · 边 m · 深度 d · 叶子 l` 统计 / 🌙 主题 / 🗺 图例 /「适应画布」/「导出 PNG」按钮。
|
|
239
|
+
- **图例默认关闭**:传 `:legend="true"`(或 `v-model:legend`)后右下角出现图例面板,点击标题可折叠。
|
|
211
240
|
- 加载中 / 出错(如 dataUrl 404)有内置遮罩提示。
|
|
212
241
|
- 卸载时自动 `destroy()` 图实例与事件监听,无内存泄漏。
|
|
213
242
|
|
|
@@ -230,8 +259,7 @@ const g6Data = buildGraphData(model, layout); // → G6 可直接消费的 { n
|
|
|
230
259
|
|
|
231
260
|
引擎内置两套主题,**浅色为默认**(白底,图元配套深色,适合打印或嵌入浅色页面);深色为**黑底 SCADA 风格**。
|
|
232
261
|
|
|
233
|
-
- `TopoGraph`:`:theme` 取值 `'light'`(默认)或 `'dark'`,推荐 `v-model:theme` 双向绑定;开启 `:toolbar="true"` 后工具条内置 ☀️ / 🌙 切换按钮(点击 emit `update:theme
|
|
234
|
-
- `SidePanel` / `DistanceTop10`:同样接收 `theme` prop,与画布保持一致观感。
|
|
262
|
+
- `TopoGraph`:`:theme` 取值 `'light'`(默认)或 `'dark'`,推荐 `v-model:theme` 双向绑定;开启 `:toolbar="true"` 后工具条内置 ☀️ / 🌙 切换按钮(点击 emit `update:theme`)。- `SidePanel` / `DistanceTop10`:同样接收 `theme` prop,与画布保持一致观感。
|
|
235
263
|
- 切换主题会**按当前数据自动重建画布**:G6 画布背景、图元、边、标注文字全部随主题更新,布局不变。
|
|
236
264
|
|
|
237
265
|
```vue
|
|
@@ -465,6 +493,18 @@ const size = getMeterBoxSize(node); // 获取动态尺寸 {
|
|
|
465
493
|
|
|
466
494
|
`TopoGraph` 组件内部即用上述默认参数,返回布局数据含每节点坐标、`edgeCP`(每条边的完整折线点序列)与 `fishboneRibs`,可配 `assertOrthogonal(model, edgeCP)` 做 0 交叉 / 正交性校验。
|
|
467
495
|
|
|
496
|
+
### 站房内部布局(含多母线)
|
|
497
|
+
|
|
498
|
+
站房(`stations[].contain`)内部按「进线开关 → 母线 → 出线开关」展开:
|
|
499
|
+
|
|
500
|
+
- **单母线**:进线开关竖直在母线正上方,出线开关全部竖直均匀下挂母线,出线从开关底穿出框底。
|
|
501
|
+
- **多母线(双母线等)**:站内多条母线**并排在同一水平线**上(各自长度随本母线开关数量自适应);
|
|
502
|
+
母联开关**沉到两母线间隙的下方**,连线按**「半矩形(⊔)」**走线——左母线端竖直向下 → 水平 → 母联开关 → 水平 → 竖直向上接右母线端
|
|
503
|
+
(电气方向与左右排列相反时自动翻转两侧,不横穿母线);母联短名为「母联」,标签居中画在 ⊔ 内部,不与相邻母线下的开关重叠;
|
|
504
|
+
其余开关按「父母线」归属,各自竖直下挂在自己母线上;站内根(如公变)与进线开关接在**主母线(进线开关所接的那条母线)**上方;
|
|
505
|
+
站内只有变压器、没有进线开关时,变压器直接挂在主母线上方(也会正常定位,不会丢坐标)。
|
|
506
|
+
- 布局结果自动保证母线/母联/开关两两不重叠、线段横平竖直(`assertOrthogonal` 校验为 0 非正交段)。
|
|
507
|
+
|
|
468
508
|
## TypeScript
|
|
469
509
|
|
|
470
510
|
类型声明随包发布(`dist/index.d.ts`),支持按需导入:
|
package/dist/index.d.ts
CHANGED
|
@@ -140,6 +140,20 @@ export class TopoApi {
|
|
|
140
140
|
destroy(): void;
|
|
141
141
|
}
|
|
142
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
|
+
|
|
143
157
|
// 工具函数
|
|
144
158
|
export function parseTopo(raw: object): any;
|
|
145
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
|
|