技术解析2026年6月27日

用代码画图:diagram-as-code 的原理、引擎与能力边界

Mermaid、PlantUML、Graphviz 这类『用文字描述、自动生成图』的方案是怎么工作的?本文讲清从文本到图形的解析—布局—渲染三段流水线、各引擎的取舍,以及自动布局的能力边界。

"用文字描述,自动生成一张图"听起来像魔法,其实是一条清晰的三段流水线:把文本解析成抽象结构、用算法算出每个图元的位置、再渲染成矢量图形。理解这三段,就能判断这类方案能做什么、做不到什么。

文章核心论点配图

diagram-as-code 到底是什么?

diagram-as-code 指用纯文本描述图的逻辑结构,由程序自动生成图形的一类方案,代表有 Mermaid、PlantUML、Graphviz/DOT、D2 等。它的核心主张是:作者只声明"有哪些节点、节点之间有哪些关系",而不手动指定每个图元的坐标

这与 draw.io、Visio 这类手动画图工具形成鲜明对照。手动画图里,一个方框在哪、多大、连线怎么拐弯,都由人逐一摆放;diagram-as-code 里这些全交给算法。这一根本差异决定了两者后续的全部取舍——可控性、可维护性、适用场景,都从这里分叉。

从文本到图形要经过哪几步?

从一段文本到最终图形,几乎所有引擎都走同一条三段流水线:

  1. 解析(parse):把领域特定语言(DSL)文本解析成抽象语法树 / 内部图模型——节点集合、边集合、以及它们的属性(标签、形状、方向)。
  2. 布局(layout):核心难点。算法根据图的拓扑计算每个节点的坐标、每条边的走线,使图尽量少交叉、对齐整齐、间距合理。
  3. 渲染(render):把带坐标的几何模型画成 SVG / Canvas,应用主题样式、字体、配色。
阶段 输入 输出 主要难点
解析 DSL 文本 图模型(点/边/属性) 语法歧义、错误定位
布局 图模型 带坐标的几何 减少交叉、自动对齐
渲染 几何 + 样式 SVG / 位图 字体度量、主题一致性

三段里,布局是把"逻辑"变成"好看的图"的关键,也是不同引擎拉开差距的地方。

自动布局是怎么算出来的?

布局的本质是一个优化问题:在二维平面上摆放节点、安排连线,使整体可读性最高(交叉最少、层次最清、间距均匀)。不同图类用不同算法族:

  • 有向无环图 / 分层图(流程图、依赖图):常用 Sugiyama 分层布局——先给节点分层(rank),层内排序以最小化边交叉,再分配坐标。Graphviz 的 dot、前端常用的 dagre 都属此类。
  • 通用关系图 / 网络图:常用力导向布局(force-directed)——把边当弹簧、节点当带斥力的粒子,迭代到能量最低的稳定态。
  • 时序图、甘特图:几乎不需要复杂优化,因为时间轴/参与者已经隐含了强约束,布局接近确定性排布。

这里藏着一个常被误解的特性:布局是实时计算的,不是固定坐标。所以引擎或布局库升级后,同一份源码可能渲染出略有差异的排布——这是自动布局的固有性质,而非缺陷。

几个主流引擎怎么取舍?

同样是 diagram-as-code,设计目标不同,能力侧重也不同:

引擎 运行环境 强项 取舍
Graphviz (DOT) 原生 / WASM 大规模图、成熟分层算法 语法偏底层,样式较朴素
Mermaid 浏览器 JS 图类型多、Markdown 生态集成好 复杂大图布局可控性有限
PlantUML JVM UML 全家桶(类图/时序/组件) 依赖 Java 运行时
D2 原生 现代语法、布局引擎可插拔 生态较新

选型不存在"最优":要画规范的 UML、且能接受 JVM,PlantUML 覆盖最全;要在网页/Markdown 里轻量嵌图,Mermaid 集成成本最低;要处理超大依赖图,Graphviz 的分层算法最经得起考验。

能力边界与已知限制

diagram-as-code 不是万能的,把它用在不擅长的场景只会事倍功半。常见边界:

  • 布局不完全可控:你能影响方向(如自上而下)和分组,但很难强制"这个框必须在那个框左边 20px"。需要像素级摆位时,它不是合适工具。
  • 大图易退化:节点和边到几百上千时,自动布局可能产生大量交叉或超长连线,可读性反而下降,往往要拆子图。
  • 样式表达有限:相比手绘画布,配色、图标、自由形状的表现力较弱,不适合做强视觉设计的信息图。
  • DSL 学习与调试成本:语法错误、未加引号的特殊字符(尤其 CJK 标签)会导致解析失败,错误定位有时不直观。
  • 版本间渲染漂移:如前所述,布局算法升级会让同源码图产生位置变化,对"图必须逐像素一致"的归档场景不友好。

判断一类图适不适合 diagram-as-code,关键看它是否结构化、关系是否明确、是否需要纳入版本管理:结构清晰、要 diff、要随代码演进的,用文本生成最划算;要自由排布、强设计感的,手动画布更合适。

小结

diagram-as-code 的本质是"声明结构、算法布局、自动渲染"的三段流水线,把图的坐标决策权从人手里交给布局算法。它换来的是纯文本可版本管理、与文档/代码同源演进的好处,代价是布局不完全可控、大图易退化、版本间可能漂移。流程图、时序图、ER 图这类结构化关系图是它的主场;像素级精确和强视觉设计,则仍属于手动画图工具的领域。

本文用到的工具

常见问题

手动画图(如 draw.io)由人决定每个图元的坐标;diagram-as-code 由人只描述『有哪些节点、哪些连线』,坐标交给自动布局算法计算。前者可精确控位但难版本管理,后者可纯文本 diff 但布局不完全可控。