简介:这份资源面向电力系统设计、绘图软件开发者及电气工程相关技术人员,提供以SVG格式定义的标准化电力图元与图符集合,用于解决电力接线图中设备符号不统一、缩放失真、跨平台复用困难等问题。压缩包内共1个doc文档,约5.2MB,以文字与SVG代码片段相结合的方式,系统整理单线图绘制中常用的图符定义。内容涵盖隔离开关、断路器等典型设备的图元规范,并详细给出竖直与水平方向下刀上分合、刀下分合等多种状态的Symbol ID与SVG几何描述,如通过circle、line、path等元素构建图符,并借助rotate、scale等transform属性实现旋转与镜像变换,从而扩展出不同方向与位置的图元,避免重复绘制、提升坐标精度。目前已有2968人学习下载,适合需要统一图元标准、提升接线图绘制效率与图形质量的电气设计与开发人员参考使用。
1. 从一份 SVG 电力图元库说起:为什么刀片方向值得单独定义
接手过一个变电站单线图编辑器的维护,最头疼的不是拓扑计算,而是图元。同一把隔离开关,竖直画、水平画、刀在上、刀在下、分闸、合闸,六种组合,如果每种都手绘一遍,坐标对不齐、线宽不一致,图面看着就是歪的。后来拿到一份 SVG 格式定义的电力图元库,里面把隔离开关、机械式开关、负荷隔离开关、圆形隔离开关、菱形隔离开关、小车隔离开关、接地隔离开关按方向和刀片位置拆成了独立 symbol,每个都有唯一 Symbol ID,比如Dis_V_D_OPen表示竖直、刀下、分闸。这份资源解决的就是电力接线图里图符标准化和复用的问题,适合做 SCADA 组态、单线图编辑器、电力图形文件交换的开发者,也适合需要把图元导入不同绘图软件的前端或 C++/Java 工程师。它不依赖特定语言,只要解析 SVG 就能用,缩放不糊,这是矢量格式在电力图元场景里的硬优势。
2. 拆解图元命名规则:Symbol ID 里藏着的方向与状态
2.1 命名三段式:设备类型_方向_刀片位置_状态
这份图元库的 Symbol ID 不是随便起的,它遵循一套可推导的命名规则。以隔离开关为例,Dis是设备类型前缀,V或H表示竖直或水平,D或U表示刀片在下或在上,L或R表示刀片在左或在右,Open和Close表示分闸与合闸。组合起来就是Dis_V_D_OPen、Dis_H_L_Close这样的 ID。机械式开关用Mec前缀,负荷隔离开关用LoadDis,圆形隔离开关用RoundDis,菱形隔离开关用DiamondDis,小车隔离开关用DrawoutDis,接地隔离开关用GroundDis。这套命名让程序在运行时可以根据设备类型、方向、刀片位置和状态直接拼出 symbol 引用,不需要维护一张巨大的映射表。
注意:原文中
Dis_V_D_OPen的OPen大小写不统一,实际使用时建议统一为Open,否则在大小写敏感的环境里会找不到 symbol。
2.2 viewBox 统一为 -40 -40 81 81 的用意
每个 symbol 的viewBox都是-40 -40 81 81,这意味着坐标系原点在中心,x 和 y 各向两侧延伸 40 个单位,总宽高 81。这样定义的好处是图元在旋转和镜像时,中心点不变,变换后仍然落在同一个 viewBox 内,不会因为旋转导致图元跑出可视区域。比如竖直隔离开关的引线从 y=-30 到 y=-12 和 y=30 到 y=12,水平隔离开关的引线从 x=-30 到 x=-12 和 x=30 到 x=12,都是对称的。如果 viewBox 不是以中心为原点,旋转 90 度后图元就会偏移,需要额外计算平移量,既影响效率又容易出错。
2.3 基础图元与扩展图元的关系
文档里明确说了,先定义基础图元,再通过旋转、镜像生成不同方向和位置的图元。但实际这份资源并没有用transform属性去引用基础图元,而是把每个方向的图元都写成了独立的 symbol,坐标直接写死。这样做的好处是每个 symbol 都是自包含的,解析时不需要处理 transform 继承和嵌套,渲染引擎的兼容性更好。代价是文件体积大一些,但电力图元数量有限,这点体积换来的稳定性是值得的。如果自己扩展新图元,建议也按这个思路,直接写坐标,不要依赖 transform 链。
3. 把 symbol 用起来:从 SVG 文件到可交互接线图
3.1 定义 symbol 库并引用
拿到这份图元定义后,第一步是把它整理成一个 SVG 文件,放在<defs>里。下面是一个最小可用的结构,把隔离开关的几个 symbol 放进去,然后在<use>里引用。
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="200"> <defs> <!-- 竖直隔离开关,刀下,分闸 --> <symbol id="Dis_V_D_OPen" viewBox="-40 -40 81 81"> <circle cx="0" cy="10" r="2" stroke-width="1" fill-opacity="0"/> <line x1="0" y1="-30" x2="0" y2="-12" stroke-width="1"/> <line x1="0" y1="30" x2="0" y2="12" stroke-width="1"/> <line x1="-2" y1="-12" x2="2" y2="-12" stroke-width="1"/> <line x1="1.3" y1="8.5" x2="14" y2="-10" stroke-width="2"/> </symbol> <!-- 竖直隔离开关,刀下,合闸 --> <symbol id="Dis_V_D_Close" viewBox="-40 -40 81 81"> <circle cx="0" cy="10" r="2" stroke-width="1" fill-opacity="0"/> <line x1="0" y1="-30" x2="0" y2="-12" stroke-width="1"/> <line x1="0" y1="30" x2="0" y2="12" stroke-width="1"/> <line x1="-2" y1="-12" x2="2" y2="-12" stroke-width="1"/> <line x1="0" y1="-12" x2="0" y2="8" stroke-width="2"/> </symbol> </defs> <!-- 在画布上引用两个图元 --> <use href="#Dis_V_D_OPen" x="80" y="100" width="81" height="81"/> <use href="#Dis_V_D_Close" x="200" y="100" width="81" height="81"/> </svg>逻辑说明:<defs>里放 symbol 定义,<use>通过href引用 symbol 的 id,x和y决定图元在画布上的位置,width和height控制渲染尺寸。因为 viewBox 是-40 -40 81 81,图元中心在(x+40.5, y+40.5)附近,实际布局时按这个偏移量对齐引线端点。
参数说明:stroke-width="1"是引线和固定触点的线宽,stroke-width="2"是刀片的线宽,刀片比引线粗,视觉上更突出。fill-opacity="0"让圆点透明填充,只保留描边。合闸状态下刀片从y=-12到y=8,分闸状态下刀片从(1.3, 8.5)斜向(14, -10),这个斜线角度和长度是固定的,不要随意改,否则不同图元之间刀片开口大小不一致。
3.2 用 JavaScript 动态切换分合状态
实际接线图里,开关状态是随数据变化的,不能写死。下面这段代码演示如何根据设备状态动态切换 symbol 引用。
// 假设设备对象包含 type、orientation、bladePos、state function getSymbolId(device) { const prefixMap = { disconnector: 'Dis', mechanical: 'Mec', loadDisconnector: 'LoadDis', roundDisconnector: 'RoundDis', diamondDisconnector: 'DiamondDis', drawoutDisconnector: 'DrawoutDis', groundDisconnector: 'GroundDis' }; const prefix = prefixMap[device.type]; const dir = device.orientation === 'vertical' ? 'V' : 'H'; let blade = ''; if (device.orientation === 'vertical') { blade = device.bladePos === 'down' ? 'D' : 'U'; } else { blade = device.bladePos === 'left' ? 'L' : 'R'; } const state = device.state === 'open' ? 'Open' : 'Close'; return `${prefix}_${dir}_${blade}_${state}`; } // 更新 use 元素的 href function updateSymbol(useEl, device) { const id = getSymbolId(device); useEl.setAttribute('href', `#${id}`); }逻辑说明:getSymbolId根据设备类型、方向、刀片位置和状态拼出 symbol ID,updateSymbol把<use>的href指向新的 symbol。这样切换状态时不需要重新创建 DOM 元素,只改属性,渲染开销小。
参数说明:device.type的取值要和 prefixMap 的键一致,device.orientation只接受vertical或horizontal,device.bladePos在竖直时是down或up,在水平时是left或right,device.state是open或close。如果数据源里字段名不同,在传入前做一层映射。
3.3 小车隔离开关的特殊处理
小车隔离开关在闭合状态下不区分刀片位置,文档里明确说了:竖直方向刀片在上或在下图元一样,水平方向刀片在左或右图元一样。所以DrawoutDis_V_Close和DrawoutDis_H_Close各只有一个 symbol,没有_D_、_U_、_L_、_R_的区分。分闸状态下才有DrawoutDis_V_D_Open、DrawoutDis_V_U_Open、DrawoutDis_H_L_Open、DrawoutDis_H_R_Open四个。写状态切换逻辑时,如果设备类型是小车隔离开关且状态是合闸,直接拼DrawoutDis_V_Close或DrawoutDis_H_Close,不要带刀片位置段,否则会找不到 symbol。
4. 避坑与排查:图元对不齐、状态不切换、缩放糊
4.1 图元引线端点对不上
现象:两个隔离开关串联时,引线端点差几个像素,图面看着有断口。
原因:<use>的x和y是图元 viewBox 左上角在画布上的位置,而 viewBox 是-40 -40 81 81,所以图元中心在(x+40.5, y+40.5)。如果按(x, y)当中心去布局,就会偏 40.5 个单位。
解决:布局时统一用中心坐标,渲染前把中心坐标减去 40.5 得到x和y。或者封装一个placeSymbol(cx, cy, id)函数,内部做偏移。
4.2 切换状态后图元不更新
现象:改了device.state,调用updateSymbol,但画面没变化。
原因:<use>的href在部分浏览器里需要用setAttributeNS设置,或者旧版浏览器只认xlink:href。
解决:优先用href,如果目标环境兼容性要求高,同时设置href和xlink:href。另外检查拼出的 symbol ID 是否和<defs>里的 id 完全一致,大小写敏感。
4.3 缩放后线宽变粗或变细
现象:图元放大后,线条比预期粗,或者缩小后线条几乎看不见。
原因:SVG 默认vector-effect是none,线宽会随缩放比例变化。如果希望线宽固定,需要加vector-effect="non-scaling-stroke"。
解决:在 symbol 的每个<line>、<circle>、<path>上加vector-effect="non-scaling-stroke"。但注意,这样线宽不随缩放变化,图元放大后线条相对变细,视觉上可能不协调。电力图元一般按固定尺寸渲染,不缩放,所以这个坑在动态缩放场景才出现。
4.4 圆形隔离开关合闸填充色不一致
现象:RoundDis_V_Close的圆填充红色,但RoundDis_H_Close的圆填充也是红色,可有些图元合闸时圆没填充。
原因:原文里RoundDis_V_Close的 symbol id 写成了RoundDisV_V_Close,多了一个V,和命名规则不一致。如果程序按规则拼RoundDis_V_Close,就找不到这个 symbol,回退到默认样式,圆就不填充。
解决:统一 symbol id,把RoundDisV_V_Close改成RoundDis_V_Close。同时检查所有 symbol id 是否符合前缀_方向_刀片_状态的格式,发现不一致的批量修正。
4.5 接地隔离开关刀片方向反了
现象:接地隔离开关的刀片应该连在接地端,但渲染出来刀片连到了线路端。
原因:接地隔离开关的刀片位置取决于接地符在上、下、左、右哪个方向,文档里说“根据接地符的上、下、左、右位置绘制不同的图符”。如果数据里接地端方向没传对,或者拼 ID 时把方向段搞反了,刀片就会画反。
解决:在设备数据里明确记录接地端方向,拼 ID 时用接地端方向而不是线路端方向。渲染前用一条测试用例验证:接地端在下时,刀片应该朝下。
5. 进阶:用脚本批量校验 symbol 定义的一致性
图元库用久了,难免有人手动改坐标、改 id,改出不一致。我一般会写一个校验脚本,在 CI 里跑一遍,把问题拦在合并之前。下面这个 Python 脚本读取 SVG 文件,检查所有 symbol 的 id 是否符合命名规则、viewBox 是否统一、刀片线宽是否为 2。
import re import xml.etree.ElementTree as ET NS = {'svg': 'http://www.w3.org/2000/svg'} def validate_symbols(svg_path): tree = ET.parse(svg_path) root = tree.getroot() symbols = root.findall('.//svg:symbol', NS) errors = [] id_pattern = re.compile( r'^(Dis|Mec|LoadDis|RoundDis|DiamondDis|DrawoutDis|GroundDis)_' r'(V|H)_' r'([DULR])_' r'(Open|Close)$' ) for sym in symbols: sid = sym.get('id') if not id_pattern.match(sid): errors.append(f'ID 不符合命名规则: {sid}') vb = sym.get('viewBox') if vb != '-40 -40 81 81': errors.append(f'viewBox 不统一: {sid} -> {vb}') # 检查刀片线宽 for line in sym.findall('.//svg:line', NS): sw = line.get('stroke-width') if sw == '2': break else: errors.append(f'未找到线宽为 2 的刀片: {sid}') return errors if __name__ == '__main__': errs = validate_symbols('power_symbols.svg') for e in errs: print(e) print(f'共发现 {len(errs)} 个问题')逻辑说明:id_pattern用正则匹配命名规则,viewBox检查是否统一为-40 -40 81 81,刀片线宽检查每个 symbol 里是否至少有一条stroke-width="2"的线。如果某个 symbol 没有,说明刀片线宽被改过或者漏画了。
参数说明:svg_path是 SVG 文件路径,NS是 SVG 命名空间。如果 symbol 定义在带前缀的 XML 里,需要调整命名空间映射。这个脚本只做静态检查,不渲染,跑得快,适合放在 pre-commit 钩子里。
提示:校验脚本不要只检查 id 格式,还要检查引线端点坐标是否在 viewBox 范围内。我遇到过有人把
y1="-30"改成y1="-50",图元超出 viewBox,渲染时被裁剪,引线看着短了一截。
从那以后我每次拿到新的图元库,都先跑一遍校验脚本,再拿几个典型设备手动拼一遍状态切换,确认引线对齐、刀片方向正确、合闸填充色一致,才往项目里合。希望帮到你。
本文还有配套的精品资源,点击获取