ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

纯HTML+SVG架构图工具:出版级矢量图的工程实践

纯HTML+SVG架构图工具:出版级矢量图的工程实践 1. 项目概述为什么一个纯HTMLSVG的架构图工具能引发设计师和工程师集体转发最近在GitHub trending榜上刷到一个叫diagram-design的仓库标题写着“告别粗糙架构图”我第一反应是——又一个画图工具但点进去后连续看了三遍README又扒了源码结构最后在本地跑通demo时手有点抖。不是因为技术多炫酷而是它用最朴素的Web原生技术精准戳中了我们日常协作中最痛的那个点一张图要同时让架构师信服逻辑严谨、让前端确认交互路径、让UI设计师认可视觉质感还要让产品经理一眼看懂业务流向。这事儿过去十年里要么靠Visio拖拽凑合要么用draw.io导出再PS精修要么直接扔给设计师重做——成本高、版本乱、改起来像考古。diagram-design不搞复杂渲染引擎不依赖Node.js服务端甚至不打包构建。它就一个index.html文件里面全是标准HTML标签 原生SVG元素 纯CSS控制样式 少量ES6 JavaScript逻辑。没有React/Vue框架包袱没有Webpack配置地狱没有npm install半小时还在下载依赖。你把它丢进任意静态服务器甚至双击打开就能立刻编辑、缩放、导出高清SVG/PNG。更关键的是它生成的SVG不是位图截图而是语义化、可访问、可编程、可嵌入文档的矢量图——这意味着你可以把架构图直接贴进Confluence页面用CSS统一换主题色可以给每个模块加aria-label供屏幕阅读器识别可以在CI流程里用Puppeteer自动截取部署前后的对比图甚至能用Python脚本批量解析SVG里的g idservice-auth节点自动生成微服务健康检查报告。我试过用它重绘公司核心支付系统的三层架构图网关层、业务中台、数据底座。原来用draw.io做的版本导出PNG后放大200%就糊了发给移动端团队看不清接口调用箭头方向而diagram-design生成的SVG在Figma里放大到400%依然锐利设计师直接拖进设计稿当参考基准线。更意外的是我把SVG代码复制进邮件HTML模板收件人用Outlook打开图照样清晰显示——这点连很多付费SaaS工具都做不到。它不追求“全能”但把“架构图作为沟通媒介”这件事做到了极致克制与极致可用。如果你也受够了画图工具导出失真、协作版本混乱、嵌入文档变形、无法自动化集成那这个项目值得你花30分钟真正吃透它怎么工作。2. 核心设计思路拆解为什么放弃Canvas/WebGL死磕原生SVG2.1 不是技术保守而是场景倒逼选择很多人看到“纯HTMLSVG”第一反应是太老派了吧现在不都上Canvas渲染、WebGL加速、Three.js做3D可视化了吗但diagram-design的作者在issue里明确写过一句话“架构图不是游戏画面它不需要每秒60帧的动态渲染它需要的是可读性、可维护性、可追溯性”。这句话直击本质。我们来拆解真实协作场景中的硬需求可读性架构图里一个矩形框代表“订单服务”字体必须清晰可辨哪怕打印在A4纸上箭头上的文字“HTTP/2”不能因抗锯齿模糊连线弯曲度要符合UML规范不能为了性能牺牲语义精度。可维护性当“用户中心”模块拆分为“认证服务”和“资料服务”时工程师要能直接在HTML里找到g iduser-center删掉旧节点插入两个新rect并更新连线path dM100,200 Q150,150 200,200——而不是打开GUI界面点选、拖拽、右键导出、再上传。可追溯性Git diff要能看清哪一行SVG代码改了——比如把fill#4CAF50改成fill#2196F3代表从“已上线”状态切换为“灰度中”。Canvas渲染出的base64图片或WebGL纹理Git根本没法做文本比对。SVG原生支持这些能力它是XML格式可被任何文本编辑器打开每个元素有明确ID和class可被CSS精准控制text标签支持xml:spacepreserve保留换行空格defs里定义的渐变/滤镜可全局复用use href#icon-db实现图标复用降低体积。而Canvas是位图缓冲区所有绘制操作都是命令式调用一旦ctx.fillRect()执行完像素就固化了想改颜色得重绘整块区域WebGL更底层调试一个着色器错误可能耗掉半天。2.2 HTML容器层不只是外壳而是语义锚点diagram-design没把所有东西塞进svg里而是用标准HTML结构包裹div classdiagram-container header classdiagram-header h1支付系统架构图/h1 p classversion-tagv2.3.1 · 2024-06-15/p /header div classdiagram-body svg viewBox0 0 1200 800 xmlnshttp://www.w3.org/2000/svg !-- 所有图形元素 -- /svg /div footer classdiagram-footer button onclickexportSVG()导出SVG/button button onclickcopyToClipboard()复制代码/button /footer /div这个看似简单的结构实则暗藏玄机diagram-container作为整体尺寸控制锚点配合CSSmax-width: 100vw; overflow-x: auto;实现响应式缩放手机上看自动横向滚动桌面端可全屏查看diagram-header和diagram-footer不是装饰而是元信息载体标题用h1保证SEO和无障碍阅读版本号用p便于CI脚本正则提取按钮绑定JS事件避免内联onclick污染SVG纯净性diagram-body里的svg设置viewBox而非固定宽高确保缩放时比例不变形——这是SVG区别于Canvas的核心优势Canvas需手动监听resize事件重设canvas.width/height并重绘全部内容。我实测过把这段HTML丢进Hexo博客的Markdown文章里用{% raw %}...{% endraw %}包裹渲染后图完全正常且支持博客主题CSS覆盖比如把.diagram-header h1改成深蓝色。而Canvas方案必须引入额外JS库且常因博客主题禁用script标签导致白屏。2.3 SVG图元层用最少的标签表达最丰富的语义diagram-design的SVG部分极度克制只用5类基础标签标签典型用途关键属性示例为什么不用替代方案rect服务模块、数据库、网关等矩形组件x100 y200 width180 height80 rx8 fill#E3F2FD stroke#2196F3 stroke-width2Canvas需计算4个点坐标再beginPath()rect()fill()SVG一行搞定且rx圆角天然抗锯齿circle节点标识、状态指示灯cx500 cy300 r12 fill#FF5252Canvas画圆需arc()方法参数多易错SVGr属性直观且circle天生支持animate做心跳动效path弯曲连线、UML关联线dM200,250 C250,200 350,200 400,250Canvas贝塞尔曲线需bezierCurveTo()三次调用SVG单个d属性描述完整路径Git diff可读性强text模块名称、接口协议、备注说明x190 y245 font-size14 dominant-baselinemiddle text-anchormiddleCanvas文本定位需手动计算基线偏移SVGdominant-baseline和text-anchor精准控制对齐支持tspan换行g逻辑分组、图层管理g idauth-layer classlayer.../gCanvas无原生分组概念需用数组管理对象SVGg可整体transform缩放/平移且ID可被CSS/JS直接操作特别值得注意的是path的d属性。diagram-design没用D3.js的d3.line()生成路径而是手写贝塞尔曲线指令。比如一条从“API网关”到“订单服务”的带标注箭头!-- 连线主体 -- path dM150,180 C180,150 220,150 250,180 stroke#78909C stroke-width2 fillnone marker-endurl(#arrowhead)/ !-- 箭头定义 -- defs marker idarrowhead markerWidth10 markerHeight7 refX10 refY3.5 orientauto polygon points0 0, 10 3.5, 0 7 fill#78909C/ /marker /defs !-- 接口标注 -- text x200 y145 font-size12 text-anchormiddle fill#546E7A tspanHTTPS/tspan /text这种写法看似原始但好处巨大dM150,180 C180,150 220,150 250,180中的控制点坐标直接对应设计稿里的锚点位置UI设计师给的PSD标注值如“控制点距起点水平偏移30px”可直接填入marker-end引用预定义箭头修改全局箭头样式只需改defs里一处无需遍历所有pathtspan支持多行文本比如把“HTTPS/REST”分成两行dy1.2em即可控制行距Canvas需拆成两次fillText()调用。3. 核心细节解析与实操要点如何让SVG架构图真正“出版级”3.1 颜色系统不是随便挑色而是建立可扩展的语义色板diagram-design的CSS里没有#ff0000这类魔法数字而是定义了一套基于Material Design色阶的CSS变量:root { --color-service: #E3F2FD; /* 服务模块背景 */ --color-service-border: #2196F3; /* 服务边框 */ --color-db: #F3E5F5; /* 数据库背景 */ --color-db-border: #9C27B0; /* 数据库边框 */ --color-external: #FFF3CD; /* 外部系统背景 */ --color-external-border: #FF9800; /* 外部系统边框 */ --color-line: #78909C; /* 连线颜色 */ --color-label: #546E7A; /* 文字颜色 */ }这套色板不是凭空而来而是严格对应架构图通用语义蓝色系#2196F3代表内部可控服务符合“信任、稳定”心理暗示紫色系#9C27B0代表持久化存储紫色在色彩心理学中关联“深度、可靠”橙色系#FF9800代表外部依赖如微信支付SDK、短信平台橙色传递“注意、边界”信号灰色系#78909C作为中性连线色避免干扰主视觉且在彩色背景下仍保持足够对比度。提示实际使用时我建议在style标签里追加媒体查询适配暗色模式media (prefers-color-scheme: dark) { :root { --color-service: #1E88E5; --color-service-border: #42A5F5; --color-db: #4A148C; --color-db-border: #7E57C2; } }这样设计师在Dark Mode下看图颜色依然协调无需额外导出暗色版本。3.2 字体与排版让文字成为架构图的可信度背书架构图里文字大小、行高、字重直接影响专业感。diagram-design强制使用系统安全字体栈.diagram-text { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif; font-size: 14px; line-height: 1.4; font-weight: 500; }为什么不用Google Fonts或自定义woff两点硬约束离线可用性客户现场演示时网络可能受限Web Font加载失败会导致文字回退到默认字体如Windows的Times New Roman破坏设计一致性渲染性能SVG里每个text元素都要触发字体度量计算Web Font需额外HTTP请求解析首屏渲染延迟明显。更关键的是排版细节处理dominant-baselinemiddle确保文字垂直居中避免Canvas里手动计算y fontSize * 0.35的误差text-anchormiddle水平居中配合x坐标精准落在模块中心对长文本如“用户行为分析与实时推荐引擎”启用textLength和lengthAdjust属性强制等宽压缩text x300 y400 text-anchormiddle font-size12 textLength160 lengthAdjustspacingAndGlyphs 用户行为分析与实时推荐引擎 /text这样即使文字超长也不会溢出矩形框且字符间距均匀比CSS的overflow: hidden或text-overflow: ellipsis更符合出版级要求。3.3 交互增强不靠框架用原生SVG事件实现专业体验diagram-design的交互极简但精准悬停高亮CSS:hover直接作用于rect改变fill和stroke无需JS监听点击聚焦为每个g添加tabindex0支持键盘Tab导航按Enter键触发focus事件缩放平移svg外层用div classzoom-container包裹CSStransform: scale(1.5)overflow: hidden实现硬件加速缩放导出逻辑exportSVG()函数不调用第三方库而是直接序列化svg的outerHTMLfunction exportSVG() { const svg document.querySelector(svg); const serializer new XMLSerializer(); const svgString serializer.serializeToString(svg); // 添加XML声明和DOCTYPE确保浏览器可直接打开 const fullString ?xml version1.0 encodingUTF-8 standaloneno?\n!DOCTYPE svg PUBLIC -//W3C//DTD SVG 1.1//EN http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\n${svgString}; const blob new Blob([fullString], {type: image/svgxml}); const url URL.createObjectURL(blob); const a document.createElement(a); a.href url; a.download architecture-diagram.svg; a.click(); URL.revokeObjectURL(url); }这段代码亮点在于XMLSerializer是浏览器原生API兼容IE11无需引入xmlserializer包手动拼接?xml?和!DOCTYPE声明确保导出的SVG在Inkscape、Illustrator等专业软件里能正确解析命名空间URL.createObjectURL()比data:URI更安全避免超长字符串导致Chrome崩溃。我曾用此方案导出一张含200节点的微服务图文件大小仅387KB而同等复杂度的draw.io PNG达8MB。SVG可压缩率高且矢量特性让设计师在Figma里无限放大不失真。4. 实操过程与核心环节实现从零开始搭建你的第一个出版级架构图4.1 初始化三步创建最小可行架构图不要被“源码深度评测”吓住diagram-design的最小运行单元就是一个HTML文件。按以下步骤5分钟内完成首个架构图Step 1创建基础HTML骨架新建architecture.html粘贴以下内容删减了非必要注释保留核心结构!doctype html html langzh-cn head meta charsetutf-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title我的第一个架构图/title style * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif; background: #f5f5f5; } .diagram-container { max-width: 1200px; margin: 0 auto; padding: 20px; } .diagram-header h1 { color: #333; font-weight: 600; margin-bottom: 10px; } .diagram-body { background: white; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.08); overflow: hidden; } .diagram-footer { margin-top: 20px; text-align: center; } button { background: #2196F3; color: white; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; font-size: 14px; } button:hover { background: #0d7cdc; } /style /head body div classdiagram-container header classdiagram-header h1用户登录流程架构图/h1 p© 2024 架构组 · 内部使用/p /header div classdiagram-body svg viewBox0 0 800 400 xmlnshttp://www.w3.org/2000/svg !-- 后续将在此处添加SVG图形 -- /svg /div footer classdiagram-footer button onclickexportSVG()导出SVG/button button onclickcopyToClipboard()复制代码/button /footer /div script function exportSVG() { const svg document.querySelector(svg); const serializer new XMLSerializer(); const svgString serializer.serializeToString(svg); const fullString ?xml version1.0 encodingUTF-8 standaloneno?\n!DOCTYPE svg PUBLIC -//W3C//DTD SVG 1.1//EN http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\n${svgString}; const blob new Blob([fullString], {type: image/svgxml}); const url URL.createObjectURL(blob); const a document.createElement(a); a.href url; a.download login-flow.svg; a.click(); URL.revokeObjectURL(url); } function copyToClipboard() { const svg document.querySelector(svg); const serializer new XMLSerializer(); const svgString serializer.serializeToString(svg); navigator.clipboard.writeText(svgString) .then(() alert(SVG代码已复制到剪贴板)) .catch(err console.error(复制失败:, err)); } /script /body /htmlStep 2添加核心组件矩形文字在svg标签内插入用户中心和认证服务两个模块!-- 用户中心模块 -- g iduser-center rect x100 y100 width160 height80 rx6 fill#E3F2FD stroke#2196F3 stroke-width2/ text x180 y145 font-size14 text-anchormiddle dominant-baselinemiddle fill#1976D2 classdiagram-text 用户中心 /text /g !-- 认证服务模块 -- g idauth-service rect x400 y100 width160 height80 rx6 fill#E8F5E9 stroke#4CAF50 stroke-width2/ text x480 y145 font-size14 text-anchormiddle dominant-baselinemiddle fill#2E7D32 classdiagram-text 认证服务 /text /gStep 3绘制连接线并标注协议在两个模块间添加HTTPS连接!-- 连接线 -- path dM260,140 C300,120 360,120 400,140 stroke#78909C stroke-width2 fillnone marker-endurl(#arrowhead)/ !-- 箭头定义放在svg顶部 -- defs marker idarrowhead markerWidth10 markerHeight7 refX10 refY3.5 orientauto polygon points0 0, 10 3.5, 0 7 fill#78909C/ /marker /defs !-- 协议标注 -- text x330 y105 font-size12 text-anchormiddle fill#546E7A classdiagram-text tspanHTTPS/tspan /text保存文件双击用Chrome打开你会看到两个蓝色/绿色模块中间有带箭头的曲线连接上方标注“HTTPS”。这就是出版级架构图的起点——所有元素均可直接编辑HTML源码无需启动任何服务。4.2 进阶技巧用CSS变量和JS动态控制提升生产力当架构图节点超过20个手动改fill颜色会疯掉。diagram-design提供两种动态控制方案方案ACSS变量批量控制主题色在style里定义变量然后用var(--color-service)替代硬编码:root { --color-service: #E3F2FD; --color-service-border: #2196F3; } .service-rect { fill: var(--color-service); stroke: var(--color-service-border); }然后在SVG里应用classrect classservice-rect x100 y100 width160 height80 rx6/方案BJS脚本批量注入节点对于重复性高的组件如K8s Pod写个生成函数function createPod(x, y, name, replicas 3) { const g document.createElementNS(http://www.w3.org/2000/svg, g); g.setAttribute(id, pod-${name}); // Pod容器 const rect document.createElementNS(http://www.w3.org/2000/svg, rect); rect.setAttribute(x, x); rect.setAttribute(y, y); rect.setAttribute(width, 120); rect.setAttribute(height, 60); rect.setAttribute(rx, 4); rect.setAttribute(fill, #BBDEFB); rect.setAttribute(stroke, #1976D2); rect.setAttribute(stroke-width, 1.5); g.appendChild(rect); // 副本数标签 const text document.createElementNS(http://www.w3.org/2000/svg, text); text.setAttribute(x, x 60); text.setAttribute(y, y 35); text.setAttribute(font-size, 12); text.setAttribute(text-anchor, middle); text.setAttribute(dominant-baseline, middle); text.textContent ${name} ×${replicas}; g.appendChild(text); return g; } // 批量创建 const svg document.querySelector(svg); svg.appendChild(createPod(100, 100, api-gateway, 2)); svg.appendChild(createPod(300, 100, order-service, 4)); svg.appendChild(createPod(500, 100, payment-service, 3));这样新增Pod只需调用createPod()颜色、尺寸、标签格式全部继承避免复制粘贴出错。4.3 导出与集成让架构图真正融入工程流程diagram-design的终极价值不在“画图”而在“可编程”。以下是三个真实落地场景场景1Confluence文档自动嵌入Confluence支持HTML宏把导出的SVG代码粘贴进去它会自动渲染为矢量图。更重要的是你可以用CSS覆盖其样式style .confluence-embedded-svg .service-rect { fill: #e3f2fd !important; } .confluence-embedded-svg text { font-family: Helvetica Neue, sans-serif !important; } /style这样整个团队文档风格统一无需设计师反复调整。场景2Git提交时自动校验在.git/hooks/pre-commit里添加校验脚本确保每次提交的架构图都包含版本号#!/bin/sh if git diff --cached --name-only | grep -q \.html$; then if ! git diff --cached | grep -q p classversion-tagv[0-9]\\.[0-9]\\.[0-9]\/p; then echo 错误架构图HTML必须包含版本号 p class\version-tag\vX.Y.Z/p exit 1 fi fi场景3CI流水线自动生成变更报告用Python脚本解析前后两次提交的SVG提取g id...节点差异import xml.etree.ElementTree as ET def get_nodes(svg_path): tree ET.parse(svg_path) root tree.getroot() return {g.get(id) for g in root.findall(.//{http://www.w3.org/2000/svg}g) if g.get(id)} old_nodes get_nodes(old.svg) new_nodes get_nodes(new.svg) print(新增节点:, new_nodes - old_nodes) print(删除节点:, old_nodes - new_nodes)输出结果可直接发到企业微信机器人提醒团队“支付服务模块已下线订单服务新增Redis缓存”。5. 常见问题与排查技巧实录那些官方文档不会写的坑5.1 “导出的SVG在Illustrator里文字变成方块”——字体嵌入陷阱现象用exportSVG()导出的文件在Adobe Illustrator打开后中文显示为方块英文正常。原因SVG标准不强制嵌入字体Illustrator默认用系统字体渲染。如果系统没装-apple-system等字体栈里的字体就会回退到缺失字体。解决方案临时方案在Illustrator里选中文字 →文字 创建轮廓CtrlShiftO把文字转为矢量路径根治方案修改导出函数用textPath或tspan的font-family强制指定Web安全字体// 替换所有text元素的font-family const texts svg.querySelectorAll(text); texts.forEach(t { t.setAttribute(font-family, sans-serif); // 改为通用字体 });实操心得我最终采用折中方案——在CSS里定义font-family: PingFang SC, Hiragino Sans GB, Microsoft YaHei, sans-serif;覆盖中文字体确保跨平台一致。测试发现只要系统装了任一中文字体渲染就正常。5.2 “缩放后连线箭头消失”——marker坐标系误区现象给path添加marker-endurl(#arrowhead)后用CSStransform: scale(1.5)缩放整个SVG箭头不见了。原因SVGmarker的refX/refY是相对于marker自身坐标系而transform缩放会影响marker的渲染尺寸导致箭头偏移出视野。解决方案推荐用svg自身的viewBox缩放而非CSStransform。比如原viewBox0 0 800 400改为viewBox0 0 533.33 266.67除以1.5SVG自动等比缩放marker不受影响备选在marker里添加orientauto-start-reverse让箭头自动适应路径方向。避坑技巧我在调试时发现Chrome开发者工具的“Elements”面板里右键SVG元素 → “Edit as HTML”实时修改viewBox值比写CSS更快验证效果。5.3 “多人协作时SVG代码冲突严重”——结构化提交策略现象两个工程师同时修改架构图Git合并时出现大量SVG标签行冲突手动解决极其痛苦。根源SVG是扁平XML节点顺序敏感rect和text谁先谁后影响渲染但Git diff无法理解语义。实战策略强制结构分层在svg内按逻辑分组用注释标记区块!-- 用户层 -- g iduser-layer !-- 用户中心 -- g iduser-center.../g !-- 认证服务 -- g idauth-service.../g /g !-- 服务层 -- g idservice-layer ... /g约定提交规范每次提交只改一个g区块commit message写明“feat(arch): update auth-service layout”避免“chore: fix svg”这类模糊描述引入prettier插件用prettier-plugin-svg自动格式化SVG统一缩进和换行减少无意义diff。血泪教训我们曾因未分层一次合并冲突涉及300行花了2小时逐行核对。分层后冲突集中在特定g内10分钟解决。5.4 “在邮件里显示异常”——HTML邮件客户端兼容性清单现象把SVG代码粘贴进Outlook邮件部分客户端显示空白。真相HTML邮件客户端对SVG支持极差。Litmus测试显示✅ Outlook DesktopWindows支持内联SVG❌ Outlook WebOWA不支持SVG需fallback✅ Apple Mail完美支持⚠️ Gmail App仅支持简单SVG禁用defs和marker可靠fallback方案!-- 邮件HTML片段 -- div classsvg-fallback !--[if mso] img srchttps://example.com/arch-diagram.png alt架构图 width800 height400/ ![endif]-- !--[if !mso]!-- svg viewBox0 0 800 400 ....../svg !--![endif]-- /div用条件注释为Outlook Desktop提供PNG fallback其他客户端走SVG原生渲染。我实测此方案在Gmail、Apple Mail、Outlook全平台100%显示正常。6. 工具链延伸与生态整合让diagram-design不止于画图6.1 与Mermaid的互补而非替代看到这里你可能疑惑既然有Mermaid这么火的文本绘图工具为什么还要折腾SVG答案是Mermaid擅长快速草图diagram-design专注终稿交付。Mermaid适合写PR描述里的流程图“mermaid graph LR A[用户] -- B[API网关] -- C[订单服务]”5秒生成但导出PNG模糊无法精细控制圆角/阴影/字体diagram-design适合交付给客户的《系统架构白皮书》每个模块加阴影filterurl(#shadow)连线用path精确控制曲率文字用tspan分行导出PDF时矢量不失真。我的工作流是用Mermaid在Confluence里快速画初稿 → 团队评审通过 → 导出PNG截图 → 用diagram-design重绘终稿 → 插入正式文档。两者共存各司其职。6.2 自动化生成用Python解析OpenAPI生成架构图diagram-design的SVG结构规整极易被脚本解析。我写
返回列表