topo-engine

配电台区单线图拓扑成图引擎 (Vue3 + G6 v5 + Node/Vite)
1,490
Install
npm install topo-engine
Latest Version:0.1.12
Vue:3
License:MIT
Last Updated:Sep 14, 2026
Links: npm
Maintainer: ndk_npm

topo-engine

配电台区(低压配电网)单线图拓扑成图引擎,基于 Vue 3 + AntV G6 v5。

输入一份台区拓扑 JSON,自动完成「解析 → 建树找根 → 横平竖直、0 交叉 的正交布局 → 深色 SCADA 风格渲染」,并提供开箱即用的 Vue 组件与一整套拓扑查询 / 样式 / 动画 / 标注控制 API。

功能特性

  • 🧩 Vue 3 组件 — TopoGraph(画布;可选左上工具条默认隐藏,:toolbar 开启)、SidePanel(设备详情与上下游)、DistanceTop10(父子连线距离 Top10 面板)
  • 🎨 深色 / 浅色双主题 — 黑底 SCADA 或白底两种画布风格,图元 / 导线 / 文字随之配套适配,可随时切换(theme prop 或工具栏按钮)。默认浅色主题
  • 🗺 图例 — 可选图例面板(legend prop,默认关闭):按当前图实际设备类别自动生成、颜色随主题,支持 legendItems 自定义项与点击折叠
  • 📐 自研正交布局 — 主干沿最长路径横向铺开 + 分支带垂直直走,整图横平竖直、0 交叉、0 重叠,边缘路由为直线 / L 形折线
  • 🏢 站房/公配室多母线 — 站内含多条母线时母线并排(同一水平线);母联开关经「半矩形(⊔)」走线连接两母线(母线端向下 → 水平 → 母联开关 → 水平 → 向上),母联短名为「母联」并居中显示在 ⊔ 内部;其余开关各挂各自母线;单母线站房行为不变
  • 🔍 拓扑查询 API — 节点 / 边 / 邻居 / 子树 / 主干链 / 路径 / 坐标 查询
  • 🎨 样式控制 — 节点、边样式覆盖与批量重置
  • 🎨 节点 / 电表染色 — 按 psrId(设备编码) 染普通节点、按 assetNo(资产编号) 染计量箱内电表户(状态色、告警色场景)
  • ✨ 动画与高亮 — 节点脉动、节点光晕(发光环,颜色可设)、边流动、路径高亮、其余变暗、异常标注
  • 📝 文字标注 — 附加文字、用户名 full / short / hidden 切换
  • 🃏 卡片盒 — 节点信息卡片(字段 + 按钮),适配"运行曲线/工单跳转"类场景
  • 🔗 连接线 / 拓扑线 — 任意两节点动态连接线、路径拓扑高亮线
  • 🎧 事件系统 — 点击 / 悬停 / 画布空白 / 视口变化事件总线
  • 💾 导出 — 整图 PNG 下载、DataURL、图数据 JSON
  • 📦 零配置渲染 — 组件内置主题与解析渲染,data 或 dataUrl 二选一即可出图

安装

npm install topo-engine
# 或 yarn add topo-engine / pnpm add topo-engine
  • 环境要求:Vue 3.4+(peerDependency);@antv/g6 v5 已作为依赖随包安装,无需手动配置。
  • 组件深色样式不自动注入,使用时需引入样式文件:
import 'topo-engine/style.css';

📖 完整 API 参考手册随包发布:安装后可打开 node_modules/topo-engine/docs/API.md, 或在线查看仓库中的 docs/API.md(事件、卡片、连接线、布局参数、TS 类型等一应俱全)。

快速开始

1. 最小示例 —— 只画一张图

<script setup>
import { ref } from 'vue';
import { TopoGraph } from 'topo-engine';
import 'topo-engine/style.css';

// 两种数据来源任选其一:
//  - dataUrl:内部用 fetch 加载(注意放 public/ 下或跨域可达)
//  - data   :直接传入解析好的 JSON 对象(优先级高于 dataUrl)
const dataUrl = ref('/data/topology.json');

const onLoaded = ({ title, stats }) => {
  console.log('加载完成', title, stats); // { total, depth, leaves, byCat }
};
</script>

<template>
  <!-- 组件撑满父容器,父容器必须有明确高度 -->
  <div class="page">
    <TopoGraph :data-url="dataUrl" @loaded="onLoaded" />
  </div>
</template>

<style scoped>
.page { height: 640px; }
</style>

2. 组合示例 —— 图 + 详情面板 + Top10 距离面板

<script setup>
import { ref } from 'vue';
import { TopoGraph, SidePanel, DistanceTop10 } from 'topo-engine';
import 'topo-engine/style.css';

const topo = ref(null);              // ref → 调用完整控制 API
const graphData = ref(null);         // 直接传数据对象
const panelOpen = ref(false);
const selected = ref(null);
const upstream = ref([]);
const downstream = ref([]);
const stats = ref({});
const distances = ref([]);

function onSelect({ node, upstream: up, downstream: down }) {
  selected.value = node;
  upstream.value = up;
  downstream.value = down;
  panelOpen.value = true;
}
function onTopDistances(list) { distances.value = list; }
function jumpTo(id) { topo.value?.selectNode(id); }
</script>

<template>
  <div class="app">
    <div class="graph-area">
      <TopoGraph
        ref="topo"
        :data="graphData"
        @node-select="onSelect"
        @top-distances="onTopDistances"
      />
      <SidePanel
        v-if="panelOpen"
        :node="selected"
        :upstream="upstream"
        :downstream="downstream"
        :stats="stats"
        @close="panelOpen = false"
        @jump="jumpTo"
      />
    </div>
    <DistanceTop10
      v-if="distances.length"
      :distances="distances"
      @close="distances = []"
      @jump="jumpTo"
    />
  </div>
</template>

<style scoped>
.app { display: flex; height: 720px; }
.graph-area { flex: 1; display: flex; min-width: 0; position: relative; }
</style>

3. 只用布局 / 解析工具函数(不依赖组件)

import { parseTopo, computeOrthogonalLayout, buildGraphData } from 'topo-engine';

const model  = parseTopo(rawJson);              // 原始 JSON → 图模型(含 nodes/edges/rootId/stats)
const layout = computeOrthogonalLayout(model);  // 正交布局结果(节点坐标 + 每边折线点序列)
const g6Data = buildGraphData(model, layout);   // → G6 可直接消费的 { nodes, edges }

说明:包内渲染使用的自定义图元节点(svg-symbol)与正交折线边(orth-polyline)目前仅在 TopoGraph 内部注册使用,未作为公开 API 导出。直接用 G6 手工拼图时建议以 TopoGraph 组件(或它的 render 流程)为基准,保证节点与边风格一致。

输入数据格式

顶层可以是 { code, msg, data: { nodes, relationships, stations } }(常见接口包装格式),也可以是直接 { nodes, relationships, stations } —— 引擎两种都接受。

{
  "data": {
    "nodes": [
      { "id": 1, "name": "1#台区.", "psrType": "0302", "symbolId": "1664029", "status": "0" },
      { "id": 2, "name": "1#台区低压熔丝.", "psrType": "3301", "symbolId": "68688", "status": "0" }
    ],
    "relationships": [ { "from": 1, "to": 2 } ],
    "stations": [
      { "id": 1, "name": "1#台区.", "contain": ["8ff4786d548a7073a2517297e801518ff456732f4d"] }
    ]
  }
}
字段 说明
nodes[] 设备/线路节点:id、name(可带结尾 .,渲染时会去掉)、psrType(图元类型码)、symbolId、psrId、status("0" 视为正常)
relationships[] 有向边 { from, to },方向为 电源 → 负荷;自动防环(BFS),入度为 0 者作为根,优先选变压器/开关
stations[] 台区/站房:name 作为画布标题,contain 内为箱内设备的 psrId 列表

parseTopo 后模型节点会附带派生抽像字段:cat、catLabel、shortName、isLine、insideStation、isFuse 等(完整类型见 dist/index.d.ts)。

主要 psrType → 图元类别:

psrType 类别 渲染
0302 / 0110 配电变压器(柱上变) 橙色圆 + 红圈
3301 / 321500000 开关 / 熔丝 红色矩形(开关名自动缩写为 K 编号)
3303 低压母线 白色短粗线(无文字标签)
3202 / 320300000 电缆终端头 / 分接点 三角 / 红色米字(无文字标签)
310100000 / 3201 / 3102 / 3101 低压导线(含电杆/导线分段) 青色连接点(名称缩写为杆号区间)
3112 / 31120003 计量箱 黑底白框 "JX"(有客户数据时显示为电能表图标 + 用户名)
3218000 用户接入点 白圈 "J"(名称缩写为户号)
32500000 低压配电箱(台区) 站房

TopoGraph 组件参考

Props

Prop 类型 默认 说明
dataUrl String '' 拓扑 JSON 的 URL(内部 fetch 加载)。变化后自动重新加载
data Object null 直接传入 JSON 对象;优先级高于 dataUrl;深度 watch,变化自动重绘
customerData Array null 客户数据([{ psrId, consumerList }]),注入计量箱并按户渲染 / 可点
theme 'dark' | 'light' 'light' 画布主题:dark(黑底 SCADA)/ light(白底,图元配套加深,默认)。支持 v-model:theme,也可点内置工具栏 ☀️/🌙 按钮切换
toolbar Boolean false 是否显示左上工具条(标题 / 统计 / 主题 / 图例 / 适应画布 / 导出 PNG),默认隐藏
legend Boolean false 是否显示右下角图例面板,默认否。支持 v-model:legend(开启 toolbar 后工具条内有 🗺 图例按钮)。图例按当前图实际出现的设备类别自动生成,颜色跟随主题;面板可点击标题折叠
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

Emits

事件 载荷 触发时机
loaded { title, stats },stats = { total, depth, leaves, byCat } 每次数据渲染完成
node-select { node, upstream, downstream }(均为解析后模型节点) 点击节点(含金框选中与详情联动);空白清除时 node=null
customer-select { node, customer, index, count, upstream, downstream } 点中计量箱内某个用户(展示客户档案)
top-distances Array<{ parent: {id,name,catLabel}, child: {id,name,catLabel}, distance }>(≤10) 渲染完成时,父-子连线折线长度 Top10(过滤站内边与主干鱼骨边)
update:legend 新布尔值 工具条 🗺 图例按钮点击(配合 v-model:legend)

图例(legend)

<!-- 默认不显示;开启即用(按图内容自动生成条目,颜色随主题) -->
<TopoGraph :data-url="'/data/topo.json'" legend />

<!-- 自定义图例项 -->
<TopoGraph
  :data-url="'/data/topo.json'"
  :legend="true"
  :legend-items="[
    { label: '正常设备', shape: 'square', color: '#22C55E' },
    { label: '告警设备', shape: 'ring',   color: '#EF4444' },
    { label: '停电',     shape: 'triangle', color: '#9CA3AF' },
    { label: 'JX',       shape: 'text',   color: '#3A3A3A', text: 'JX' },
  ]"
/>

自动图例内容:配电变压器 / 开关 / 熔丝 / 低压母线 / 电缆终端头 / 密母分接点 / 计量箱 / 用户接入点 / 低压导线点 / 低压配电箱 / 其它设备(仅显示图中存在的),末尾固定为 主干导线 / 分支导线,图中含计量箱客户数据时再追加 客户电表。

内置交互与 UI

  • 滚轮缩放、拖拽平移、悬停高亮(上下游与连线),点击选中(金色虚框,再次点空白取消)。
  • 计量箱用户点击:单户箱整箱即该户;多户箱点电表格 / 户名 = 该户客户档案(悬停青圈、选中金圈),点箱体空白 = 选中整箱(事件 consumer:click / customer-select)。
  • 左上角工具条默认隐藏:传 :toolbar="true" 后显示标题 / 节点 n · 边 m · 深度 d · 叶子 l 统计 / 🌙 主题 / 🗺 图例 /「适应画布」/「导出 PNG」按钮。
  • 图例默认关闭:传 :legend="true"(或 v-model:legend)后右下角出现图例面板,点击标题可折叠。
  • 加载中 / 出错(如 dataUrl 404)有内置遮罩提示。
  • 卸载时自动 destroy() 图实例与事件监听,无内存泄漏。

通过 ref 调用的方法

<TopoGraph ref="topo"> 后,topo 暴露 TopoApi 的全部公开方法(下节 API 表),外加:

方法 说明
loadRaw(jsonText) 用一段 JSON 文本(如本地文件上传内容)重新成图
selectNode(id) 选中某节点并联动 node-select 事件
selectCustomer(nodeId, index) 编程式选中计量箱内第 index 户(联动 customer-select)
getSelectedCustomer() 当前选中的户:{ nodeId, index, customer, node } | null
resetView() 适应画布
exportPng() 导出整图 PNG(按画布标题命名下载)
getLayoutData() 获取当前正交布局数据(坐标 / 折线 / stats)
getTopDistances() 获取最近一次 Top10 距离结果

主题切换(深色 / 浅色)

引擎内置两套主题,浅色为默认(白底,图元配套深色,适合打印或嵌入浅色页面);深色为黑底 SCADA 风格。

  • TopoGraph::theme 取值 'light'(默认)或 'dark',推荐 v-model:theme 双向绑定;开启 :toolbar="true" 后工具条内置 ☀️ / 🌙 切换按钮(点击 emit update:theme)。- SidePanel / DistanceTop10:同样接收 theme prop,与画布保持一致观感。
  • 切换主题会按当前数据自动重建画布:G6 画布背景、图元、边、标注文字全部随主题更新,布局不变。
<script setup>
import { ref } from 'vue';
import { TopoGraph } from 'topo-engine';
import 'topo-engine/style.css';

const theme = ref('light');          // 初始浅色(默认),可在运行时切换
const dataUrl = ref('/data/topology.json');
</script>

<template>
  <div class="page">
    <TopoGraph v-model:theme="theme" :data-url="dataUrl" />
  </div>
</template>

说明:主题色板定义在包内 theme.js(THEMES.dark / THEMES.light,已随库打包,未作为公开导出);若需要按自有品牌定制,可在外层自行覆盖 dist/style.css 中各组件的 --tp-* / --sp-* / --dt-* CSS 变量。

控制 API(TopoApi 方法,经组件 ref 直接调用)

也可自行 import { TopoApi },按 new TopoApi(graph, model, layout, nodeByIdMap) 构造后调用同一套方法;事件与查询见下。使用组件时无需关心内部构造。

📌 引用统一(id / psrId / assetNo):所有目标入参(查询/定位/样式/高亮/动画/文字/卡片/连线…)都可传 节点内部 id、psrId(设备编码) 或 客户 assetNo(资产编号,兼容 consNo/consId):

  • 命中普通节点 → 作用在该节点;
  • 命中箱内电表户 → 视觉/定位/动画精确作用在该户表位(光环/高亮环/脉动/文字/染色/卡片), 查询/拓扑按所在计量箱参与(getNode(assetNo) 返回箱节点并附 customer 信息), 定位聚焦表位中心(locateNode(assetNo)、getNodePosition(assetNo))。
topo.locateNode(assetNo);                                  // 定位到某户表位中心
topo.highlightNode(assetNo, { color: '#FF0000' });          // 该户表位高亮环
topo.setNodeGlow(assetNo, { color: '#FF6600' });            // 该户表位光晕
topo.setNodeGlow(assetNo, { blink: true, color: '#FF6600' }); // 该户表位整体闪烁
topo.setNodePulse(assetNo);                                 // 该户电表格脉动
topo.setText(assetNo, '异常');                              // 表位上方标注
topo.showCard(assetNo);                                     // 客户档案卡片(定位在表位旁)
topo.selectNode(assetNo);                                   // 编程选中该户(联动 customer-select)
topo.getNode(assetNo);          // → 所在箱节点副本 { …, customer, customerIndex, targetKind:'customer' }
topo.resolveRef(assetNo);       // → { kind:'customer', boxId, index, customer, … } | null

查询

方法 说明
getNode(nodeId) 按 ID 取节点(解析后模型节点)
getAllNodes() 全部节点
findNodes(filter) 多条件 AND 过滤,filter 支持 { cat, psrType, name, shortName, status, insideStation, … },值可为字符串 / 布尔 / RegExp
getSelectedId() 当前选中节点 ID
getNeighbors(id) { upstream: [], downstream: [] }
getStreamNodes(id, 'upstream'|'downstream') 沿流向 BFS 取节点链
getTrunkNodes() / getSubtreeNodes(id) 主干链节点 / 子树节点
getPath(a, b) 两节点间路径(不可达返回 null)
getEdge(src, tgt) / getEdges() 按端点取边 / 全部边
getStreamEdges(id, dir) / getMainEdge() 沿流边的链 / 主干边
getNodePosition(id) / getEdgePath(src, tgt) / getGraphBounds() 坐标 / 边折线点序列 / 全图包围盒
getStats() { total, depth, leaves, byCat }

视图

fitView(padding?)、zoomTo(ratio, center?)、zoomIn(step?)、zoomOut(step?)、locateNode(id, zoom?)、getViewport()

样式

setNodeStyle(id, style)、batchSetNodeStyle(ids, style)、resetNodeStyle(id)、resetAllNodeStyles() setEdgeStyle(src, tgt, style)、batchSetEdgeStyle([[src,tgt],…], style)、resetEdgeStyle(src, tgt)

节点 / 箱内电表户染色(psrId / 资产编号)

// 普通节点:按 psrId(设备编码)整图单色换装(主体/引线/描边换成该色,白字细节保留)
topo.setNodeColor('8ff4786d548a7073a2517297e801518ff456732f4d', '#FF0000');
// 箱内电表户:按资产编号(assetNo,兼容 consNo/consId)染该户电表图标 + 户名
topo.setNodeColor('4230010007008084768', '#FF6600');
// 批量(数组 / 对象数组 / ref→color 对象均可)
topo.batchSetNodeColor({ '8ff4…': '#FF0000', '4230…': '#FF6600' });
// 清除 / 查询
topo.resetNodeColor('4230010007008084768');
topo.resetAllNodeColors();
topo.getNodeColor('4230010007008084768'); // → { kind, id, color } | null

引用规则与 addConnection 一致:节点 id / psrId 命中普通节点;assetNo 命中计量箱内某户电表。 染色记录随主题切换 / 数据重渲染自动保留并重放(无需重新设置)。详见 docs/API.md。

高亮 / 变暗

topo.highlightNode('5', { color: '#FF0000', label: '异常', labelColor: '#FF0000' });
topo.unhighlightNode('5');

const path = topo.getPath('1', '5');        // 高亮一条供电路径
if (path) topo.highlightPath(path.map(n => n.id), { color: '#00FF00' });

topo.dimOthers(['1', '2'], 0.15);           // 除指定节点外整体变暗
topo.unhighlightAll();

动画

topo.setNodePulse('2', { color: '#00C8FF', duration: 1500 });   // 节点脉动
topo.setNodeGlow('2', { color: '#FF0000' });                     // 节点光晕(多层光环 + shadowBlur 辉光 + blur 面光底衬;ref 支持 psrId)
topo.setNodeGlow('2', { color: '#FF0000', intensity: 2, spread: 30, blink: true, duration: 800 }); // 更夸张:加强 + 更大扩散 + 图元整体闪烁
topo.removeNodeGlow('2');
topo.setEdgeFlow('1', '2', { color: '#00C8FF', duration: 2000 }); // 边流动
topo.removeAnimation('2');
topo.removeAllAnimations();

文字标注

setText(id, text, { color, fontSize })、removeText(id)、removeAllTexts()、setDeviceText(cat, fontSize)、changeUserName('full' | 'short' | 'hidden')

卡片盒

topo.showCard('5', {
  title: '设备名称',
  fields: [
    { label: '类型', value: '配电变压器' },
    { label: 'PSR编号', value: 'xxx' },
  ],
  buttons: [{ text: '查看运行曲线', type: 'primary', onClick: () => console.log('click') }],
  closable: true,
});
topo.hideCard('5');
topo.hideAllCards();

连接线 / 拓扑线

topo.addConnection('1', '8', { color: '#FF6600', width: 2, style: 'dashed' }); // 任意两节点连线
topo.removeAllConnections();

const lineId = topo.addTopoLine(['1', '3', '8'], { color: '#FF0000', width: 3 }); // 沿线路径画高亮线
topo.removeTopoLine(lineId);
topo.removeAllTopoLines();

事件总线(on / off)

事件 载荷 说明
node:click { nodeId, node } 节点点击
node:hover / node:unhover { nodeId, node } / { nodeId } 悬停进入 / 离开
edge:click { edgeId, source, target } 边点击
canvas:click { event } 画布空白处点击
viewport:change { zoom, center } 视口缩放 / 平移变化
card:button { nodeId, buttonIndex } 卡片按钮点击
consumer:click { nodeId, index, customer, node } 点中计量箱内用户(多户箱点格子;单户箱整箱即该户)
const handler = ({ nodeId }) => console.log('点击了', nodeId);
topo.on('node:click', handler);
topo.off('node:click', handler); // 不传 handler 则移除该事件全部监听

导出 / 底层

exportPng(filename?)(整图下载)、toDataURL(opts?)、getGraphData()、getGraphInstance()(原始 G6 Graph)、getModel()、getLayoutData()、getNodeByIdMap()、update(graph, model, layout, map)、destroy()

文字渲染

  • 设备标签自动换行:开关标签、站房标题、下方名称标签等文字根据设备宽度自动换行,避免文字重叠
  • 站房标题自适应高度:站房框高度会根据标题换行行数自动扩展,确保多行标题完整显示在框内
  • 母线 / 电缆终端头:不渲染额外文字标签(母线不显示"母线",电缆终端头不显示名称)
  • 站房标题:使用独立属性 _stationTitle 渲染,避免 G6 默认 label 重复绘制

计量箱客户数据

计量箱(psrType 3112)支持关联客户数据,渲染时根据客户数量自动切换显示模式:

模式 条件 渲染效果
无客户数据 未传入 customerData 或无匹配 原始 JX 黑底白字方框
单用户 customerList 有 1 个用户 电能表图标(圆圈 + 竖线)+ 用户名;整箱即该户,点击即客户档案
多用户(显示名称) customerList 2~20 个用户 方框内电能表网格,每个格子含图标 + 用户名(每行最多 5 个)
多用户(仅图标) customerList >20 个用户 方框内电能表网格,仅显示图标(格子更紧凑)

交互:多用户箱内点击某个电表格 / 户名 = 选中该户(金圈高亮 + customer-select / consumer:click), 点箱体空白 / 外框 = 选中整箱;悬停该户有青圈提示。用户端点(连接线)用客户档案 assetNo 引用即可。

客户数据格式(与拓扑 JSON 配套的 customer JSON):

[
  {
    "psrId": "4230000000109100079",
    "consumerList": [
      { "consId": "...", "consName": "...", "realConsName": "张三", "meterId": "..." }
    ]
  }
]

配套文件命名规则:拓扑文件为 XXX.json 时,客户文件为 XXXcustomer.json(Demo 模式下自动加载)。

TopoGraph 新增 Props

Prop 类型 默认 说明
customerData Array null 客户数据数组,传入后自动注入到计量箱节点

工具函数

import { buildCustomerMap, injectCustomers, getMeterBoxSize } from 'topo-engine';

const customerMap = buildCustomerMap(customerJsonArray); // psrId → consumerList
injectCustomers(model, customerMap);                     // 注入到模型的 meterBox 节点
const size = getMeterBoxSize(node);                      // 获取动态尺寸 { w, h } | null

布局与渲染参数

computeOrthogonalLayout(model, options):

参数 默认 含义
nodeGap 26 链上相邻节点边界间距
band 50 侧分支根到父节点中心线的距离(分支带宽)
packGap 22 分支带内并排子分支间距
sideGap 40 相邻主干节点的分支带隔离间距
margin 40 画布外框留白

TopoGraph 组件内部即用上述默认参数,返回布局数据含每节点坐标、edgeCP(每条边的完整折线点序列)与 fishboneRibs,可配 assertOrthogonal(model, edgeCP) 做 0 交叉 / 正交性校验。

站房内部布局(含多母线)

站房(stations[].contain)内部按「进线开关 → 母线 → 出线开关」展开:

  • 单母线:进线开关竖直在母线正上方,出线开关全部竖直均匀下挂母线,出线从开关底穿出框底。
  • 多母线(双母线等):站内多条母线并排在同一水平线上(各自长度随本母线开关数量自适应); 母联开关沉到两母线间隙的下方,连线按**「半矩形(⊔)」走线——左母线端竖直向下 → 水平 → 母联开关 → 水平 → 竖直向上接右母线端 (电气方向与左右排列相反时自动翻转两侧,不横穿母线);母联短名为「母联」,标签居中画在 ⊔ 内部,不与相邻母线下的开关重叠; 其余开关按「父母线」归属,各自竖直下挂在自己母线上;站内根(如公变)与进线开关接在主母线(进线开关所接的那条母线)**上方; 站内只有变压器、没有进线开关时,变压器直接挂在主母线上方(也会正常定位,不会丢坐标)。
  • 布局结果自动保证母线/母联/开关两两不重叠、线段横平竖直(assertOrthogonal 校验为 0 非正交段)。

TypeScript

类型声明随包发布(dist/index.d.ts),支持按需导入:

import { TopoApi, TopoGraph } from 'topo-engine';
import type { TopoApi } from 'topo-engine'; // 需要类型时

常见问题

  • 图不显示 / 高度为 0:TopoGraph 撑满父容器(内部 width/height: 100%),请给外层元素设置明确高度(如 height: 600px)。
  • 样式错乱 / 没有深色背景:确认已 import 'topo-engine/style.css'。
  • dataUrl 加载失败:确认文件可被 fetch 访问(Vite 放 public/,不要用相对路径);失败会触发 error 态显示并 console.error。
  • 切换数据源:响应式修改 :data / :data-url 会自动重新加载;本地文件可用 ref.loadRaw(text)。
  • 节点 ID 传字符串:内部统一按字符串存储(String(id)),查询 API 请传字符串,如 getNode('1')。
  • 和 Vue 2 / 其它 G6 版本混用:仅支持 Vue 3.4+,图内部依赖 @antv/g6 v5,请勿重复安装不同版本。

本地开发

npm install          # 安装依赖
npm run dev          # 开发演示(内置 API Playground,可试所有控制 API)→ http://127.0.0.1:5173/
npm run build        # 生产构建(应用 + 库)
npm run build:lib    # 仅构建库产物到 dist/
npm run preview      # 预览生产构建
npm pack --dry-run   # 查看发布包内容清单

License

MIT

Related Packages

genoany-g6-v2

A flowchart editor component base on Vue and G6, enjoy ~

5,696
vue-flowchart-editor

A flowchart editor component base on Vue and G6

1,086 197
kgraph

简易流程图绘制工具

3,211
vue3-network-graph

A Vue 3 + SVG network topology graph component: node dragging, infinite pan & zo...

1,236
topology-graph-vue

基于 PixiJS v8 的高性能 Vue 3 拓扑图组件库,支持 50,000+ 节点以 60 FPS 流畅渲染

5,108

Version History

Version Released Vue License
0.1.12 ^3.4.0 MIT
0.1.11 ^3.4.0 MIT
0.1.10 ^3.4.0 MIT
0.1.9 ^3.4.0 MIT
0.1.8 ^3.4.0 MIT