topo-engine 0.1.3 → 0.1.5

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 CHANGED
@@ -7,7 +7,7 @@
7
7
  ## 功能特性
8
8
 
9
9
  - 🧩 **Vue 3 组件** — `TopoGraph`(画布,含标题栏 / 统计 / 适应画布 / 导出 PNG 按钮)、`SidePanel`(设备详情与上下游)、`DistanceTop10`(父子连线距离 Top10 面板)
10
- - 🎨 **深色 / 浅色双主题** — 黑底 SCADA 或白底两种画布风格,图元 / 导线 / 文字随之配套适配,可随时切换(`theme` prop 或工具栏按钮)
10
+ - 🎨 **深色 / 浅色双主题** — 黑底 SCADA 或白底两种画布风格,图元 / 导线 / 文字随之配套适配,可随时切换(`theme` prop 或工具栏按钮)。默认浅色主题
11
11
  - 📐 **自研正交布局** — 主干沿最长路径横向铺开 + 分支带垂直直走,整图**横平竖直、0 交叉、0 重叠**,边缘路由为直线 / L 形折线
12
12
  - 🔍 **拓扑查询 API** — 节点 / 边 / 邻居 / 子树 / 主干链 / 路径 / 坐标 查询
13
13
  - 🎨 **样式控制** — 节点、边样式覆盖与批量重置
@@ -171,10 +171,10 @@ const g6Data = buildGraphData(model, layout); // → G6 可直接消费的 { n
171
171
  | ------- | ---- | ---- |
172
172
  | `0302` | 配电变压器 | 橙色圆 + 红圈 |
173
173
  | `3301` | 开关 / 熔丝 | 红色矩形(开关名自动缩写为 K 编号) |
174
- | `3303` | 低压母线 | 白色短粗线 |
175
- | `3202` / `320300000` | 电缆终端头 / 分接点 | 三角 / 红色米字 |
174
+ | `3303` | 低压母线 | 白色短粗线(无文字标签) |
175
+ | `3202` / `320300000` | 电缆终端头 / 分接点 | 三角 / 红色米字(无文字标签) |
176
176
  | `310100000` | 低压导线 | 青色连接点(名称缩写为杆号区间) |
177
- | `3112` | 计量箱 | 黑底白框 "JX" |
177
+ | `3112` | 计量箱 | 黑底白框 "JX"(有客户数据时显示为电能表图标 + 用户名) |
178
178
  | `3218000` | 用户接入点 | 白圈 "J"(名称缩写为户号) |
179
179
  | `32500000` | 低压配电箱(台区) | 站房 |
180
180
 
@@ -186,7 +186,7 @@ const g6Data = buildGraphData(model, layout); // → G6 可直接消费的 { n
186
186
  | ---- | ---- | ---- | ---- |
187
187
  | `dataUrl` | `String` | `''` | 拓扑 JSON 的 URL(内部 `fetch` 加载)。变化后自动重新加载 |
188
188
  | `data` | `Object` | `null` | 直接传入 JSON 对象;优先级高于 `dataUrl`;深度 watch,变化自动重绘 |
189
- | `theme` | `'dark' \| 'light'` | `'dark'` | 画布主题:`dark`(黑底 SCADA,默认)/ `light`(白底,图元配套加深)。支持 `v-model:theme`,也可点内置工具栏 ☀️/🌙 按钮切换 |
189
+ | `theme` | `'dark' \| 'light'` | `'light'` | 画布主题:`dark`(黑底 SCADA)/ `light`(白底,图元配套加深,默认)。支持 `v-model:theme`,也可点内置工具栏 ☀️/🌙 按钮切换 |
190
190
 
191
191
  ### Emits
192
192
 
@@ -218,7 +218,7 @@ const g6Data = buildGraphData(model, layout); // → G6 可直接消费的 { n
218
218
 
219
219
  ### 主题切换(深色 / 浅色)
220
220
 
221
- 引擎内置两套主题,**深色为默认**(黑底 SCADA 风格,与历史版本一致);浅色为**白底**,图元(变压器 / 开关 / 计量箱 / 用户圈…)、导线(干线深灰 / 支线浅灰)、节点文字都已配套加深,适合打印或嵌入浅色页面。
221
+ 引擎内置两套主题,**浅色为默认**(白底,图元配套深色,适合打印或嵌入浅色页面);深色为**黑底 SCADA 风格**。
222
222
 
223
223
  - `TopoGraph`:`:theme` 取值 `'dark'`(默认)或 `'light'`,推荐 `v-model:theme` 双向绑定;组件左上工具栏内置 ☀️ / 🌙 切换按钮(点击 emit `update:theme`)。
224
224
  - `SidePanel` / `DistanceTop10`:同样接收 `theme` prop,与画布保持一致观感。
@@ -230,7 +230,7 @@ import { ref } from 'vue';
230
230
  import { TopoGraph } from 'topo-engine';
231
231
  import 'topo-engine/style.css';
232
232
 
233
- const theme = ref('dark'); // 初始深色,可在运行时切换
233
+ const theme = ref('light'); // 初始浅色(默认),可在运行时切换
234
234
  const dataUrl = ref('/data/topology.json');
235
235
  </script>
236
236
 
@@ -347,6 +347,55 @@ topo.off('node:click', handler); // 不传 handler 则移除该事件全部监
347
347
 
348
348
  `exportPng(filename?)`(整图下载)、`toDataURL(opts?)`、`getGraphData()`、`getGraphInstance()`(原始 G6 Graph)、`getModel()`、`getLayoutData()`、`getNodeByIdMap()`、`update(graph, model, layout, map)`、`destroy()`
349
349
 
350
+ ## 文字渲染
351
+
352
+ - **设备标签自动换行**:开关标签、站房标题、下方名称标签等文字根据设备宽度自动换行,避免文字重叠
353
+ - **站房标题自适应高度**:站房框高度会根据标题换行行数自动扩展,确保多行标题完整显示在框内
354
+ - **母线 / 电缆终端头**:不渲染额外文字标签(母线不显示"母线",电缆终端头不显示名称)
355
+ - **站房标题**:使用独立属性 `_stationTitle` 渲染,避免 G6 默认 label 重复绘制
356
+
357
+ ## 计量箱客户数据
358
+
359
+ 计量箱(psrType `3112`)支持关联客户数据,渲染时根据客户数量自动切换显示模式:
360
+
361
+ | 模式 | 条件 | 渲染效果 |
362
+ | ---- | ---- | ---- |
363
+ | 无客户数据 | 未传入 customerData 或无匹配 | 原始 JX 黑底白字方框 |
364
+ | 单用户 | customerList 有 1 个用户 | 电能表图标(圆圈 + 竖线)+ 用户名 |
365
+ | 多用户(显示名称) | customerList 2~20 个用户 | 方框内电能表网格,每个格子含图标 + 用户名(每行最多 5 个) |
366
+ | 多用户(仅图标) | customerList >20 个用户 | 方框内电能表网格,仅显示图标(格子更紧凑) |
367
+
368
+ 客户数据格式(与拓扑 JSON 配套的 customer JSON):
369
+
370
+ ```json
371
+ [
372
+ {
373
+ "psrId": "4230000000109100079",
374
+ "consumerList": [
375
+ { "consId": "...", "consName": "...", "realConsName": "张三", "meterId": "..." }
376
+ ]
377
+ }
378
+ ]
379
+ ```
380
+
381
+ 配套文件命名规则:拓扑文件为 `XXX.json` 时,客户文件为 `XXXcustomer.json`(Demo 模式下自动加载)。
382
+
383
+ ### TopoGraph 新增 Props
384
+
385
+ | Prop | 类型 | 默认 | 说明 |
386
+ | ---- | ---- | ---- | ---- |
387
+ | `customerData` | `Array` | `null` | 客户数据数组,传入后自动注入到计量箱节点 |
388
+
389
+ ### 工具函数
390
+
391
+ ```javascript
392
+ import { buildCustomerMap, injectCustomers, getMeterBoxSize } from 'topo-engine';
393
+
394
+ const customerMap = buildCustomerMap(customerJsonArray); // psrId → consumerList
395
+ injectCustomers(model, customerMap); // 注入到模型的 meterBox 节点
396
+ const size = getMeterBoxSize(node); // 获取动态尺寸 { w, h } | null
397
+ ```
398
+
350
399
  ## 布局与渲染参数
351
400
 
352
401
  `computeOrthogonalLayout(model, options)`:
package/dist/index.d.ts CHANGED
@@ -108,6 +108,11 @@ export function edgeStyle(datum: any): any;
108
108
  export function calculateTopDistances(edges: any[], nodes: any[], edgeCP: Map<string, number[][]>, fishboneRibs: Set<string>, topN?: number): any[];
109
109
  export function getSymbolSpec(cat: string): { w: number, h: number };
110
110
 
111
+ // 计量箱客户数据
112
+ export function buildCustomerMap(customerData: Array<any>): Map<string, Array<any>>;
113
+ export function injectCustomers(model: any, customerMap: Map<string, Array<any>>): void;
114
+ export function getMeterBoxSize(node: any): { w: number, h: number } | null;
115
+
111
116
  // 常量
112
117
  export const SYMBOL_SPEC: Record<string, { w: number, h: number }>;
113
118
  export const FONT: string;
package/dist/style.css CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  /* —— 主题变量:dark 为默认值,light 由 [data-theme='light'] 覆盖 —— */
3
- .topo-wrap[data-v-562b2247] {
3
+ .topo-wrap[data-v-c213df91] {
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-562b2247] {
22
+ .topo-wrap[data-theme='light'][data-v-c213df91] {
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-562b2247] {
36
+ .topo-container[data-v-c213df91] {
37
37
  width: 100%;
38
38
  height: 100%;
39
39
  }
40
- .topo-toolbar[data-v-562b2247] {
40
+ .topo-toolbar[data-v-c213df91] {
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-562b2247] {
55
+ .topo-title[data-v-c213df91] {
56
56
  color: var(--tp-title);
57
57
  font-weight: 600;
58
58
  }
59
- .topo-meta[data-v-562b2247] {
59
+ .topo-meta[data-v-c213df91] {
60
60
  color: var(--tp-meta);
61
61
  }
62
- .btn[data-v-562b2247] {
62
+ .btn[data-v-c213df91] {
63
63
  margin-left: 4px;
64
64
  padding: 3px 10px;
65
65
  border: 1px solid var(--tp-btn-border);
@@ -69,12 +69,12 @@
69
69
  cursor: pointer;
70
70
  font-size: 12px;
71
71
  }
72
- .btn[data-v-562b2247]:hover {
72
+ .btn[data-v-c213df91]:hover {
73
73
  border-color: var(--tp-accent);
74
74
  color: var(--tp-accent);
75
75
  }
76
- .topo-loading[data-v-562b2247],
77
- .topo-error[data-v-562b2247] {
76
+ .topo-loading[data-v-c213df91],
77
+ .topo-error[data-v-c213df91] {
78
78
  position: absolute;
79
79
  inset: 0;
80
80
  display: flex;
@@ -85,7 +85,7 @@
85
85
  z-index: 5;
86
86
  background: var(--tp-overlay-bg);
87
87
  }
88
- .topo-error[data-v-562b2247] {
88
+ .topo-error[data-v-c213df91] {
89
89
  color: var(--tp-error);
90
90
  }
91
91
 
@@ -1216,6 +1216,53 @@ const SYMBOL_SPEC = {
1216
1216
  function getSymbolSpec(cat) {
1217
1217
  return SYMBOL_SPEC[cat] || SYMBOL_SPEC.other;
1218
1218
  }
1219
+ function buildCustomerMap(customerData) {
1220
+ const map = /* @__PURE__ */ new Map();
1221
+ if (!Array.isArray(customerData)) return map;
1222
+ for (const entry of customerData) {
1223
+ if (entry && entry.psrId && Array.isArray(entry.consumerList)) {
1224
+ map.set(String(entry.psrId), entry.consumerList);
1225
+ }
1226
+ }
1227
+ return map;
1228
+ }
1229
+ const METER_CELL_W = 26;
1230
+ const METER_CELL_H = 38;
1231
+ const METER_GAP = 4;
1232
+ const METER_PAD = 6;
1233
+ const MAX_COLS = 5;
1234
+ const SHOW_NAME_LIMIT = 20;
1235
+ function injectCustomers(model, customerMap) {
1236
+ for (const node of model.nodes) {
1237
+ if (node.cat !== "meterBox") continue;
1238
+ const customers = customerMap.get(node.psrId);
1239
+ if (!customers || customers.length === 0) continue;
1240
+ node._customers = customers;
1241
+ if (customers.length === 1) {
1242
+ node._meterBoxMode = "single";
1243
+ node._meterBoxW = 30;
1244
+ node._meterBoxH = 38;
1245
+ } else {
1246
+ const showName = customers.length <= SHOW_NAME_LIMIT;
1247
+ const cols = Math.min(customers.length, MAX_COLS);
1248
+ const rows = Math.ceil(customers.length / cols);
1249
+ const cellW = METER_CELL_W;
1250
+ const cellH = showName ? METER_CELL_H : METER_CELL_W;
1251
+ node._meterBoxMode = "grid";
1252
+ node._meterBoxCols = cols;
1253
+ node._meterBoxRows = rows;
1254
+ node._meterBoxShowName = showName;
1255
+ node._meterBoxW = METER_PAD * 2 + cols * cellW + (cols - 1) * METER_GAP;
1256
+ node._meterBoxH = METER_PAD * 2 + rows * cellH + (rows - 1) * METER_GAP;
1257
+ }
1258
+ }
1259
+ }
1260
+ function getMeterBoxSize(node) {
1261
+ if (node._meterBoxW != null && node._meterBoxH != null) {
1262
+ return { w: node._meterBoxW, h: node._meterBoxH };
1263
+ }
1264
+ return null;
1265
+ }
1219
1266
  function stationPlans(model) {
1220
1267
  const nodesById = new Map(model.nodes.map((n) => [n.id, n]));
1221
1268
  const plans = [];
@@ -1267,6 +1314,10 @@ function stationInner(plan, model, band = 50, nodeMap) {
1267
1314
  const nmap = nodeMap || new Map(model.nodes.map((n) => [n.id, n]));
1268
1315
  const specOf = (id2) => {
1269
1316
  const n = nmap.get(id2);
1317
+ if (n && n.cat === "meterBox") {
1318
+ const dim = getMeterBoxSize(n);
1319
+ if (dim) return dim;
1320
+ }
1270
1321
  const s2 = getSymbolSpec(n ? n.cat : "other");
1271
1322
  return { w: s2.w, h: s2.h };
1272
1323
  };
@@ -1924,6 +1975,10 @@ function computeOrthogonalLayout(model, opts = {}) {
1924
1975
  const sz = (id2) => {
1925
1976
  const n = extNodeMap.get(id2);
1926
1977
  if (n && n._size) return n._size;
1978
+ if (n && n.cat === "meterBox") {
1979
+ const dim = getMeterBoxSize(n);
1980
+ if (dim) return dim;
1981
+ }
1927
1982
  const spec = getSymbolSpec(n ? n.cat : "other");
1928
1983
  return { w: spec.w, h: spec.h };
1929
1984
  };
@@ -2522,22 +2577,30 @@ function buildGraphData(model, layout) {
2522
2577
  const nodes = model.nodes.map((n) => {
2523
2578
  const spec = getSymbolSpec(n.cat);
2524
2579
  const busW = layout.stationBusWidth && layout.stationBusWidth.get(n.id);
2525
- const w = busW || spec.w;
2580
+ const meterBoxDim = n.cat === "meterBox" ? getMeterBoxSize(n) : null;
2581
+ const w = busW || (meterBoxDim ? meterBoxDim.w : spec.w);
2582
+ const h = meterBoxDim ? meterBoxDim.h : spec.h;
2526
2583
  const p = layout.pos.get(n.id) || { x: 0, y: 0 };
2527
2584
  return {
2528
2585
  id: n.id,
2529
- data: { ...n, width: w, height: spec.h },
2586
+ data: { ...n, width: w, height: h },
2530
2587
  style: {
2531
2588
  x: p.x,
2532
2589
  y: p.y,
2533
- size: [w, spec.h],
2590
+ size: [w, h],
2534
2591
  // 自定义字段(进 attributes,供 svg-symbol 节点绘制使用)
2535
2592
  cat: n.cat,
2536
- labelText: n.cat === "bus" || n.cat === "cableTerminal" ? "" : n.shortName || "",
2593
+ labelText: n.cat === "bus" || n.cat === "cableTerminal" || n.cat === "consumer" ? "" : n.shortName || "",
2537
2594
  rotate: layout.stationRotate && layout.stationRotate.get(n.id) || 0,
2538
2595
  highlight: 0,
2539
2596
  cursor: "pointer",
2540
- _nodeId: n.id
2597
+ _nodeId: n.id,
2598
+ // 计量箱客户数据
2599
+ _meterBoxMode: n._meterBoxMode || null,
2600
+ _meterBoxCols: n._meterBoxCols || 0,
2601
+ _meterBoxRows: n._meterBoxRows || 0,
2602
+ _meterBoxShowName: n._meterBoxShowName || false,
2603
+ _customers: n._customers || null
2541
2604
  }
2542
2605
  };
2543
2606
  });
@@ -27789,8 +27852,45 @@ function drawStationTerminal(attributes, group) {
27789
27852
  group.appendChild(new Polygon({ style: { points: [[0, -5], [0, 5], [9, 0]], fill: "none", stroke: C2.red, lineWidth: 1.4 } }));
27790
27853
  }
27791
27854
  function drawMeterBox(attributes, group) {
27792
- group.appendChild(new Rect({ style: { x: -9.5, y: -9.5, width: 19, height: 19, fill: C2.meterFill, stroke: C2.meterText, lineWidth: 0.9 } }));
27793
- text(attributes, group, "JX", 0, 0.5, 7.5, C2.meterText);
27855
+ const [w, h] = attributes.size;
27856
+ if (attributes._meterBoxMode === "single") {
27857
+ group.appendChild(new Circle({ style: { cx: 0, cy: -3, r: 11, fill: "none", stroke: C2.white, lineWidth: 1.6 } }));
27858
+ group.appendChild(new Line({ style: { x1: 0, y1: -14, x2: 0, y2: -7, stroke: C2.white, lineWidth: 1.6 } }));
27859
+ const name = attributes._customers && attributes._customers[0] ? attributes._customers[0].realConsName || attributes._customers[0].consName || "" : "";
27860
+ if (name) {
27861
+ group.appendChild(new Text({ style: { text: name, x: 0, y: 12, fontSize: 8, fill: C2.white, fontFamily: FONT, textAlign: "center", textBaseline: "middle" } }));
27862
+ }
27863
+ } else if (attributes._meterBoxMode === "grid" && attributes._customers) {
27864
+ group.appendChild(new Rect({ style: { x: -w / 2, y: -h / 2, width: w, height: h, fill: C2.meterFill, stroke: C2.meterText, lineWidth: 0.9, radius: 2 } }));
27865
+ const cols = attributes._meterBoxCols || 5;
27866
+ const customers = attributes._customers;
27867
+ const showName = attributes._meterBoxShowName;
27868
+ const cellW = METER_CELL_W;
27869
+ const cellH = showName ? METER_CELL_H : METER_CELL_W;
27870
+ const gridW = cols * cellW + (cols - 1) * METER_GAP;
27871
+ const rows = attributes._meterBoxRows || Math.ceil(customers.length / cols);
27872
+ const gridH = rows * cellH + (rows - 1) * METER_GAP;
27873
+ const startX = -gridW / 2;
27874
+ const startY = -gridH / 2;
27875
+ const meterR = 9;
27876
+ for (let i = 0; i < customers.length; i++) {
27877
+ const row2 = Math.floor(i / cols);
27878
+ const col = i % cols;
27879
+ const cx = startX + col * (cellW + METER_GAP) + cellW / 2;
27880
+ const cy = startY + row2 * (cellH + METER_GAP) + cellW / 2;
27881
+ group.appendChild(new Circle({ style: { cx, cy, r: meterR, fill: "none", stroke: C2.meterText, lineWidth: 0.8 } }));
27882
+ group.appendChild(new Line({ style: { x1: cx, y1: cy - meterR, x2: cx, y2: cy - meterR + 4, stroke: C2.meterText, lineWidth: 0.8 } }));
27883
+ if (showName) {
27884
+ const name = customers[i].realConsName || customers[i].consName || "";
27885
+ if (name) {
27886
+ group.appendChild(new Text({ style: { text: name, x: cx, y: cy + meterR + 6, fontSize: 7, fill: C2.meterText, fontFamily: FONT, textAlign: "center", textBaseline: "middle" } }));
27887
+ }
27888
+ }
27889
+ }
27890
+ } else {
27891
+ group.appendChild(new Rect({ style: { x: -9.5, y: -9.5, width: 19, height: 19, fill: C2.meterFill, stroke: C2.meterText, lineWidth: 0.9 } }));
27892
+ text(attributes, group, "JX", 0, 0.5, 7.5, C2.meterText);
27893
+ }
27794
27894
  }
27795
27895
  function drawConsumer(attributes, group) {
27796
27896
  group.appendChild(new Circle({ style: { cx: 0, cy: 0, r: 12.5, fill: "none", stroke: C2.white, lineWidth: 1.8 } }));
@@ -27916,8 +28016,10 @@ const _sfc_main$2 = {
27916
28016
  props: {
27917
28017
  dataUrl: { type: String, default: "" },
27918
28018
  data: { type: Object, default: null },
28019
+ /** 客户数据(计量箱关联的用户列表),直接传入 JSON 数组 */
28020
+ customerData: { type: Array, default: null },
27919
28021
  /** 主题:'dark'(默认,黑底 SCADA 风)| 'light'(白底);支持 v-model:theme 双向绑定 */
27920
- theme: { type: String, default: "dark" }
28022
+ theme: { type: String, default: "light" }
27921
28023
  },
27922
28024
  emits: ["node-select", "loaded", "top-distances", "update:theme"],
27923
28025
  setup(__props, { expose: __expose, emit: __emit }) {
@@ -28033,6 +28135,10 @@ const _sfc_main$2 = {
28033
28135
  lastRaw.value = raw;
28034
28136
  const theme = applyTheme();
28035
28137
  model = parseTopo(raw);
28138
+ if (props.customerData && props.customerData.length) {
28139
+ const customerMap = buildCustomerMap(props.customerData);
28140
+ injectCustomers(model, customerMap);
28141
+ }
28036
28142
  nodeByIdMap = new Map(model.nodes.map((n) => [n.id, n]));
28037
28143
  title.value = String(model.title || "").replace(/\.+$/, "");
28038
28144
  stats.value = model.stats;
@@ -28164,6 +28270,13 @@ const _sfc_main$2 = {
28164
28270
  if (lastRaw.value) render(lastRaw.value);
28165
28271
  }
28166
28272
  );
28273
+ vue.watch(
28274
+ () => props.customerData,
28275
+ () => {
28276
+ if (lastRaw.value) render(lastRaw.value);
28277
+ },
28278
+ { deep: true }
28279
+ );
28167
28280
  vue.onBeforeUnmount(() => {
28168
28281
  if (api) {
28169
28282
  api.destroy();
@@ -28223,7 +28336,7 @@ const _sfc_main$2 = {
28223
28336
  };
28224
28337
  }
28225
28338
  };
28226
- const TopoGraph = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-562b2247"]]);
28339
+ const TopoGraph = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-c213df91"]]);
28227
28340
  const _hoisted_1$1 = ["data-theme"];
28228
28341
  const _hoisted_2$1 = { class: "panel-head" };
28229
28342
  const _hoisted_3$1 = {
@@ -28533,7 +28646,7 @@ const _sfc_main = {
28533
28646
  }
28534
28647
  };
28535
28648
  const DistanceTop10 = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-438b6017"]]);
28536
- const VERSION = "0.1.3";
28649
+ const VERSION = "0.1.5";
28537
28650
  const DESCRIPTION = "配电台区单线图拓扑成图引擎";
28538
28651
  exports.DESCRIPTION = DESCRIPTION;
28539
28652
  exports.DistanceTop10 = DistanceTop10;
@@ -28544,10 +28657,13 @@ exports.TopoApi = TopoApi;
28544
28657
  exports.TopoGraph = TopoGraph;
28545
28658
  exports.VERSION = VERSION;
28546
28659
  exports.assertOrthogonal = assertOrthogonal;
28660
+ exports.buildCustomerMap = buildCustomerMap;
28547
28661
  exports.buildGraphData = buildGraphData;
28548
28662
  exports.calculateTopDistances = calculateTopDistances;
28549
28663
  exports.computeOrthogonalLayout = computeOrthogonalLayout;
28550
28664
  exports.edgeStyle = edgeStyle;
28665
+ exports.getMeterBoxSize = getMeterBoxSize;
28551
28666
  exports.getSymbolSpec = getSymbolSpec;
28667
+ exports.injectCustomers = injectCustomers;
28552
28668
  exports.parseTopo = parseTopo;
28553
28669
  //# sourceMappingURL=topo-engine.cjs.map