1. 从一张草图到一套系统:diagram-design 到底在解决什么问题
第一次看到 diagram-design 这个词,很多人会以为它只是“画图”的另一种说法。但真正在项目里被图表折磨过的人知道,画一张图不难,难的是让一百张图看起来像同一个人画的,难的是改一个节点颜色不用把整张图重画,难的是让开发、产品、运营三个角色拿到同一份图之后不会各自理解成三个版本。diagram-design 要处理的,正是这些“画完之后”的问题。
我把它理解成一套围绕图表的设计方法论加实现工具链:它关心的不只是“这张图好不好看”,而是“这套图能不能被复用、被维护、被协作、被自动化生成”。核心关键词包括图表设计系统、节点与连线抽象、布局算法、主题令牌、可复用组件、导出与嵌入。它适合谁?适合那些需要频繁产出架构图、流程图、时序图、状态机图、组织关系图的开发者、技术写作者、产品经理,以及任何被“图到用时方恨乱”困扰的人。
举个我自己的场景。早些年做项目文档,架构图用绘图工具手拖,流程图用另一个在线工具,时序图又换一个代码生成器。结果就是三套视觉语言、三种字体、三种箭头风格,放在同一份文档里像拼贴画。后来我意识到,问题不在于工具不够多,而在于没有把“图表”当成一个有设计约束的系统来对待。diagram-design 的价值就在这里:它把图表从“一次性美术劳动”拉回到“可工程化的设计资产”。
这篇文章我会按实际落地顺序拆开讲:先讲整体设计思路和方案选型,再讲核心细节和实操要点,然后是完整实现流程,最后是我踩过的坑和排查技巧。每一部分都尽量给到可以直接抄作业的参数、结构和判断依据,而不是停留在“要重视设计”这种正确的废话上。
2. 内容整体设计与思路拆解
2.1 为什么图表需要“设计系统”而不是“绘图技巧”
大多数人学画图,学的是技巧:怎么对齐、怎么调色、怎么让箭头不穿过文字。这些当然有用,但它们是局部最优。真正让图表质量稳定的,是约束。设计系统本质上就是一组预先定好的约束:颜色只能用这几个、字号只有这几档、节点间距必须是某个基数的倍数、连线只能走正交或曲线两种模式。
我做过一个对比实验。让两组人分别画同一套微服务架构图,A 组自由发挥,B 组拿到一份只有 12 条规则的图表设计规范。结果 B 组的图在“一致性评分”上高出很多,而且修改耗时平均少了将近一半。原因很简单:自由发挥时,每个决策都要重新想一遍;有约束时,大部分决策已经被提前做完了。
diagram-design 的第一个核心思路,就是把“决策”从绘制阶段前移到系统定义阶段。你要先定义好一套令牌(token):主色、辅色、警示色、成功色、中性色各一到两个;字号定义标题、节点标签、连线标签、注释四档;间距定义 4、8、16、24、32 这样的基数序列。定义完之后,画图就变成了“选令牌”,而不是“调颜色”。
注意:令牌数量不是越多越好。我见过有人定义了 20 种颜色,结果每次画图还是纠结用哪个。颜色超过 8 种,人眼就很难在图上建立稳定的语义映射了。
2.2 节点、连线、容器:图表的三层抽象模型
任何一张结构化图表,拆到最底层都只有三类元素:节点(node)、连线(edge)、容器(container)。节点是实体,连线是关系,容器是分组。diagram-design 的第二个核心思路,就是把这三种元素抽象成可复用的组件,而不是每次重新画形状。
节点组件需要定义的属性包括:形状(矩形、圆角矩形、圆形、菱形、圆柱)、尺寸策略(固定、内容自适应、最小宽度)、内容槽(标题、副标题、图标、状态标记)、状态样式(默认、选中、警告、禁用)。连线组件需要定义:线型(实线、虚线、点线)、箭头(无、单箭头、双箭头、空心、实心)、路由方式(直线、正交、曲线)、标签位置(中点、起点、终点、自动避让)。
容器组件最容易被忽略,但它恰恰是让复杂图可读的关键。一个容器可以是一个边界框、一个泳道、一个分组区域。它需要定义:内边距、标题位置、嵌套层级、折叠状态。我个人的经验是,容器层级不要超过三层,超过三层读者就会迷失在框里。
把这三层抽象清楚之后,你会发现大部分图表需求都可以用“节点 + 连线 + 容器”的组合来表达。流程图是节点加有向连线,时序图是节点加带顺序的连线,状态机是节点加带条件的连线,组织图是节点加层级容器。这就是抽象带来的杠杆。
2.3 布局算法:手动拖拽和自动布局的取舍
图表设计里最耗时的环节往往是布局。手动拖拽的优点是精确可控,缺点是改一个节点就要重排一片。自动布局的优点是改结构不用改位置,缺点是复杂图的自动结果经常“能看但不好看”。
diagram-design 的第三个核心思路,是分层布局策略。对于层级明确的图(组织图、树状图、依赖图),用层次布局算法,按层级分配坐标,同层节点等距排列。对于流程明确的图(流程图、状态机),用正交布局,让连线尽量走直角,减少交叉。对于关系复杂的图(网络图、知识图谱),用力导向布局,让节点按连接强度自然聚散。
我实测下来的判断标准是这样的:节点数少于 15 个,手动布局完全够用,而且效果最好;15 到 40 个,用层次或正交自动布局,再手动微调;超过 40 个,必须自动布局,否则维护成本会失控。这个阈值不是绝对的,但可以作为起步参考。
提示:自动布局之后一定要留出“手动微调”的余地。完全锁死自动布局的图,在需要强调某个节点时会非常别扭。好的设计系统允许你在自动结果上做局部覆盖。
2.4 主题令牌与视觉一致性:让一百张图像一套图
视觉一致性不是“都用同一个蓝色”这么简单。它涉及颜色语义、字号层级、间距节奏、圆角半径、阴影强度、线条粗细这一整套参数。diagram-design 把它们统一收敛到主题令牌里,好处是换主题时只改令牌,所有图自动更新。
我建议的令牌结构分四组。第一组是颜色:主色用于强调和主路径,辅色用于次要信息,中性色用于背景和边框,语义色用于成功、警告、错误。第二组是排版:标题字号、节点字号、标签字号、注释字号,以及对应的行高和字重。第三组是间距:基础单位设为 4 或 8,所有间距都是它的倍数。第四组是形状:圆角半径、边框宽度、阴影偏移和模糊。
这套令牌一旦定下来,团队里任何人画图都从令牌里选,而不是自己调。我见过一个团队把令牌做成了一份共享配置文件,新人在绘图工具里导入之后,画出来的图和老成员的几乎看不出差别。这就是系统化的力量。
3. 核心细节解析与实操要点
3.1 节点设计的五个关键参数
节点看起来简单,但真正决定图表专业度的往往是细节。我总结了五个必须定义的参数。
第一个是最小宽度和最大宽度。没有最小宽度,短标签的节点会缩成一个小方块,视觉上不稳定;没有最大宽度,长标签的节点会拉成一条长条,破坏整体节奏。我的经验值是:最小宽度设为字号乘以 6,最大宽度设为字号乘以 20,超过就换行。
第二个是内边距。节点文字离边框太近会显得局促,太远会显得空洞。水平内边距建议是字号乘以 1.5,垂直内边距建议是字号乘以 1。这个比例在大多数中英文字体下都比较舒服。
第三个是圆角半径。直角显得硬朗但冷,大圆角显得柔和但不够专业。我一般用 4 到 8 像素的小圆角,既现代又不轻浮。如果是强调“流程节点”,可以用稍大的圆角;如果是“数据实体”,直角或极小圆角更合适。
第四个是状态样式。默认态、悬停态、选中态、警告态、禁用态,这五种状态要提前定义好。很多图表在静态展示时没问题,一旦交互就露馅,就是因为状态样式没设计。
第五个是内容槽的优先级。一个节点里可能同时有图标、标题、副标题、状态点、徽标。必须定义清楚谁先显示、谁在空间不足时隐藏。我的优先级排序是:标题 > 状态点 > 图标 > 副标题 > 徽标。
3.2 连线路由:正交、曲线和直线的选择逻辑
连线是图表里最容易被低估的元素。一条乱穿的连线可以让整张图的可读性归零。diagram-design 里连线路由有三种基本模式,各有适用场景。
正交路由走直角,适合流程图、架构图、组织图这类强调层级和方向的图。它的优点是路径清晰、容易追踪,缺点是节点密集时拐角会很多,显得杂乱。用正交路由时,我建议设置一个“拐角圆角”,让直角稍微圆润一点,视觉上会舒服很多。
曲线路由走贝塞尔曲线,适合关系图、依赖图这类没有明确方向的图。它的优点是柔和、自然,缺点是曲线交叉时很难判断谁连谁。用曲线路由时,一定要给连线加“避让”,让线尽量不穿过节点。
直线路由最简单,适合节点少、关系清晰的图。它的优点是干净,缺点是节点一多就会变成蜘蛛网。我的判断标准是:节点少于 8 个用直线,8 到 20 个用正交,20 个以上用曲线加避让。
注意:无论用哪种路由,连线标签的位置都要单独设计。标签压线、标签重叠、标签离连线太远,都是常见问题。我一般把标签放在连线中点,并给标签加一个和背景同色的底衬,避免被线穿过。
3.3 容器与分组:让复杂图有呼吸感
容器的作用是“把相关的东西框在一起”,但框不好反而会增加视觉噪音。我见过太多图,框套框套框,最后读者根本不知道在看哪一层。
我的做法是:容器只用于表达三种关系——归属(这些节点属于同一个系统)、边界(这些节点在同一个网络区域)、阶段(这些节点属于同一个流程阶段)。不属于这三种关系的,不要用容器,用间距和留白来分组就够了。
容器的视觉设计也有讲究。边框建议用虚线或浅色实线,不要用和节点一样粗的实线,否则容器会抢节点的视觉权重。容器标题放在左上角,字号比节点标题小一档,颜色用中性色。嵌套容器时,内层容器的内边距要比外层小,形成视觉上的层级递减。
我个人的经验是,一张图里容器数量不要超过 5 个,嵌套层级不要超过 2 层。超过这个数,读者就需要“解谜”而不是“阅读”了。
3.4 主题令牌的落地:从配置文件到实际图表
令牌定义得再好,如果不能落地到实际绘图流程里,就是纸上谈兵。我试过几种落地方式,分享下取舍。
第一种是设计工具里的共享样式库。适合设计主导的团队,优点是所见即所得,缺点是开发和文档同学用不上。第二种是代码里的主题配置对象。适合代码生成图表的场景,优点是版本可控、可编程,缺点是需要一定的开发能力。第三种是中间格式加渲染器。用一份结构化的图表描述文件,配合不同的渲染器输出不同风格的图,优点是灵活,缺点是需要维护渲染器。
我目前最推荐的是第二种和第三种结合:用一份 JSON 或 YAML 描述图表结构,主题令牌单独抽成一个配置文件,渲染时合并。这样换主题只改一个文件,改结构只改另一个文件,职责清晰。下面是一个简化的令牌配置示例:
{ "color": { "primary": "#2F6FED", "secondary": "#7A8CA3", "success": "#2E9E6B", "warning": "#D98B2B", "danger": "#D9534F", "neutral": "#E4E8EE", "background": "#FFFFFF", "text": "#1F2933" }, "typography": { "titleSize": 18, "nodeSize": 14, "labelSize": 12, "noteSize": 11, "lineHeight": 1.4 }, "spacing": { "base": 8, "nodePaddingX": 16, "nodePaddingY": 10, "containerPadding": 24 }, "shape": { "radius": 6, "borderWidth": 1.5, "shadowBlur": 8, "shadowOffsetY": 2 } }这份配置的好处是,任何绘图脚本或渲染器都可以读它,保证视觉一致。我实测下来,团队里只要有人维护这份文件,其他人基本不需要关心具体色值。
3.5 图表描述格式:结构、语义和渲染分离
diagram-design 里一个很关键的工程决策,是把“图表是什么”和“图表长什么样”分开。前者是结构描述,后者是渲染样式。这样做的好处是同一份结构可以用不同风格渲染,也可以被不同工具消费。
结构描述我建议包含这些字段:节点列表(id、标签、类型、分组)、连线列表(源、目标、标签、类型)、容器列表(id、标签、包含的节点)、元信息(标题、描述、版本)。下面是一个流程图的简化描述:
title: 订单处理流程 nodes: - id: start label: 用户下单 type: start - id: check label: 库存校验 type: process - id: pay label: 支付处理 type: process - id: done label: 订单完成 type: end edges: - from: start to: check - from: check to: pay label: 库存充足 - from: check to: done label: 库存不足 - from: pay to: done这份描述里没有任何颜色、字号、位置信息,全是语义。渲染器负责把它变成图。这样做最大的好处是,改流程只改结构,改风格只改令牌,两者互不干扰。我踩过的坑是早期把样式和结构混在一起写,结果每次调整视觉都要动结构文件,非常痛苦。
4. 实操过程与核心环节实现
4.1 第一步:定义图表类型和元素清单
动手之前先想清楚你要画哪几类图。不要一上来就追求“支持所有图表”,那会导致抽象过度。我的建议是先支持两到三类最常用的,比如流程图、架构图、时序图,把这三类的元素清单列出来。
以流程图为例,元素清单包括:开始节点、结束节点、处理节点、判断节点、输入输出节点、普通连线、条件连线。以架构图为例,元素清单包括:服务节点、数据库节点、缓存节点、消息队列节点、外部系统节点、同步调用连线、异步调用连线。以时序图为例,元素清单包括:参与者、生命线、激活条、同步消息、异步消息、返回消息。
列清单的目的是确定你要为哪些元素设计样式和布局规则。清单之外的,先不做。我见过有人一开始就列了三十种节点类型,结果每种都做得半吊子,反而不如先把五种做精。
4.2 第二步:搭建令牌和基础组件
令牌定义好之后,接下来是搭建基础组件。这一步的核心是“先做原子,再做组合”。原子是单个节点、单条连线、单个容器;组合是带图标的节点、带条件的连线、带标题的容器。
我建议按这个顺序做:先做最基础的矩形节点和直线连线,确认渲染没问题;然后加圆角、加颜色、加文字;接着做判断节点和条件连线;最后做容器和分组。每做完一个组件,就用它画一张小图验证,不要等全部做完再测。
这一步有个容易忽略的点:文字换行和溢出处理。节点标签太长怎么办?是换行、缩小字号、还是截断加省略号?我的做法是优先换行,换行超过三行就缩小字号,缩小到最小字号还放不下就截断。这个规则要写进组件里,而不是每次手动处理。
4.3 第三步:实现布局和路由
布局和路由是技术含量最高的部分。如果用的是现成的图表库,这一步可能只需要配置参数;如果自己实现,就需要一些算法基础。
层次布局的基本思路是:先做拓扑排序确定层级,再按层级分配纵坐标,同层节点按顺序分配横坐标,最后做一次交叉最小化调整。交叉最小化的常用方法是重心法:每个节点放在其相邻节点横坐标的平均值附近,迭代几次就能明显减少交叉。
正交路由的基本思路是:先确定起点和终点的出线方向,再在两者之间找一条由水平和垂直线段组成的路径,路径尽量避开节点占用的区域。简单实现可以用“曼哈顿路由”,复杂实现需要做障碍物避让。
我实测下来的经验是:如果节点数不多,不要过度优化布局算法,手动微调往往更快。把自动布局当成“初稿生成器”,而不是“最终答案”。真正省时间的是“改结构不用重排”,而不是“一次排得完美”。
4.4 第四步:导出、嵌入和版本管理
图画完之后要能导出和嵌入。常见的导出格式有 SVG、PNG、PDF。SVG 适合网页嵌入,清晰且可交互;PNG 适合文档和聊天工具;PDF 适合打印和正式文档。
我的建议是:源文件用结构化描述保存,导出格式按用途选择。不要把 PNG 当成源文件,那样改起来会疯掉。源文件进版本管理,每次改动都有记录,出问题可以回滚。
嵌入方面,如果图表要放进文档或网页,优先用 SVG 内联,这样可以继承页面的字体和颜色变量,主题切换时图表也能跟着变。如果必须用图片,导出时记得用两倍分辨率,避免在高分屏上模糊。
版本管理有个小技巧:在图表描述文件里加一个version字段和updatedAt字段。这样一眼就能看出这张图是什么时候改的,避免用错版本。我踩过的坑是,同一张架构图在三个文档里有三个版本,最后没人知道哪个是最新的。
4.5 第五步:建立评审和更新机制
图表设计系统建好之后,最难的不是技术,而是习惯。团队里总有人想“就这一次,我手动调一下”。一旦开了口子,一致性就会慢慢瓦解。
我的做法是建立一个轻量评审机制:新图提交时,检查三件事——是否用了令牌里的颜色和字号、节点和连线是否符合组件规范、布局是否在自动结果基础上微调。三件事都过,就合并;有一件不过,就退回修改。
更新机制也很重要。业务变了,图表结构要跟着变。我建议把图表更新纳入需求变更流程:需求变更时,同步评估受影响的图表,该改的改,该废弃的废弃。不要让图表变成“历史遗迹”,那样还不如没有。
5. 常见问题与排查技巧实录
5.1 图表看起来“乱”的五个根因
图表乱,通常不是审美问题,而是结构问题。我总结了五个最常见的根因,按出现频率排序。
第一个是连线交叉过多。解决方法是调整节点顺序,让连接紧密的节点靠近。如果用的是自动布局,检查交叉最小化是否开启。
第二个是节点大小差异过大。有的节点特别大,有的特别小,视觉重心不稳。解决方法是设置最小宽度和最大宽度,让节点尺寸在一个合理区间内。
第三个是颜色语义不统一。同一个颜色在不同图里代表不同含义,读者会困惑。解决方法是严格使用令牌,一个颜色只表达一个语义。
第四个是层级不清晰。主流程和分支流程混在一起,读者不知道先看哪。解决方法是用容器或间距把主次分开,主流程放中间,分支放两侧。
第五个是文字过多。节点里塞了一整段话,图变成了文档。解决方法是节点只放关键词,详细说明放到图外的注释或文档里。
5.2 自动布局结果不理想的调整策略
自动布局经常出现“能看但不好看”的情况。我的调整策略分三步。
第一步是调整输入顺序。很多布局算法对节点输入顺序敏感,把相关的节点放在一起输入,结果会好很多。这一步不需要改算法,只需要改数据。
第二步是调整布局参数。层次布局的层间距、节点间距、方向(从上到下还是从左到右),都会影响结果。我一般先把层间距调大,让层级更清晰;再把节点间距调匀,让同层节点分布均匀。
第三步是局部手动覆盖。如果整体布局可以,只有几个节点位置别扭,就手动挪那几个。好的设计系统应该支持“自动布局加手动覆盖”,而不是二选一。
提示:手动覆盖的位置信息要单独存,不要混进结构描述里。这样重新布局时,结构不变,覆盖可以保留或清除。
5.3 主题切换后图表“崩了”怎么排查
主题切换是设计系统的核心价值,但也是最容易出问题的地方。常见问题和对策我整理成了下面这张表。
| 问题现象 | 可能原因 | 排查方法 | 解决对策 |
|---|---|---|---|
| 文字看不清 | 文字色和背景色对比度不足 | 检查令牌里 text 和 background 的对比度 | 对比度至少 4.5:1,深色主题要单独定义文字色 |
| 连线消失 | 连线色和背景色太接近 | 检查 edge 颜色是否引用了中性色 | 连线色要比背景色深至少两档 |
| 节点边框看不见 | 边框色和填充色对比不足 | 检查 border 和 fill 的色差 | 边框色用中性色加深,或加阴影区分 |
| 图标颜色不对 | 图标用了固定色而非令牌 | 检查图标是否引用了 color 变量 | 图标颜色改为引用令牌,不写死 |
| 整体发灰 | 中性色占比过高 | 统计各颜色使用比例 | 主色占比控制在 20% 到 30%,中性色不超过 60% |
这张表是我实际排查时总结的,基本覆盖了八成以上的主题问题。核心原则就一条:所有颜色都必须来自令牌,不能有硬编码。只要有一条硬编码,主题切换就会露馅。
5.4 团队协作中的版本冲突和命名混乱
多人协作画图,最容易出的问题是命名冲突和版本冲突。A 同学建了一个叫“订单服务”的节点,B 同学也建了一个,合并时发现是两个不同的东西。
我的对策是建立命名规范。节点 id 用“领域-功能-序号”的格式,比如order-service-01、order-db-01。标签用业务语言,id 用技术语言,两者分开。这样即使标签一样,id 也不会冲突。
版本冲突方面,我建议图表描述文件按“一张图一个文件”来组织,不要把所有图塞进一个大文件。文件粒度细,冲突概率就低。如果多人同时改一张图,用分支加合并请求的方式,改完先评审再合并。
还有个实用技巧:在图表描述文件里加一个owner字段,标明谁负责这张图。出问题时知道找谁,更新时也知道通知谁。这个字段看起来小,但能省很多沟通成本。
5.5 性能问题:节点多了之后渲染变慢怎么办
节点数超过一百之后,有些渲染器会明显变慢。我遇到过拖动卡顿、导出超时的情况。排查下来,瓶颈通常在三个地方。
第一个是DOM 节点过多。如果用 SVG 渲染,每个节点和连线都是 DOM 元素,数量一多浏览器就吃力。解决方法是虚拟化渲染,只渲染视口内的元素。或者改用 Canvas 渲染,牺牲一点交互性换性能。
第二个是布局算法复杂度过高。力导向布局的复杂度是节点数的平方级,节点一多就慢。解决方法是先用快速算法生成初稿,再用慢算法局部优化,或者直接限制力导向布局的节点数上限。
第三个是样式计算重复。每次渲染都重新计算样式,而不是复用。解决方法是把样式计算缓存起来,结构不变时直接复用。
我的经验阈值是:节点少于 50 个,随便怎么渲染都行;50 到 200 个,要注意 DOM 数量和布局算法;超过 200 个,必须做虚拟化或分片渲染。这个阈值因设备和渲染器而异,但可以作为起步参考。
5.6 导出图片模糊和字体丢失的处理
导出图片模糊,通常是因为导出分辨率不够。SVG 导出一般不会模糊,PNG 导出要设置两倍或三倍分辨率。如果导出的是 PDF,注意嵌入字体,否则在别的设备上打开会变成默认字体。
字体丢失是更隐蔽的问题。你在本地看着好好的,发给别人就变了样。原因是对方设备没装你用的字体。解决方法是导出时把文字转成路径,或者使用系统通用字体。转路径的缺点是文字不可编辑,优点是绝对一致。我的建议是:对外分享的图转路径,内部编辑的图保留文字。
还有个细节:导出时注意画布边距。边距太小,图会贴边;边距太大,图会显得小。我一般留 16 到 24 像素的边距,视觉上比较舒服。
6. 我在这套方法上踩过的坑和真实体会
做 diagram-design 这套东西,我最大的体会是:图表的问题,九成不是画的问题,而是定义的问题。你定义清楚了节点是什么、连线是什么、颜色代表什么,画图就变成了填空题。定义不清楚,画图就变成了作文题,每次都要重新构思。
我踩过最深的坑,是一开始追求“大而全”,想支持所有图表类型、所有导出格式、所有主题。结果做了三个月,什么都没做完。后来砍到只支持两类图、一种导出、一套主题,两周就跑通了。跑通之后再慢慢加,反而快得多。
第二个坑是忽略了“改图”的成本。我早期设计的图表,画的时候很爽,改的时候很痛苦。后来我把“可修改性”当成第一优先级,宁可画的时候多花一点时间,也要保证改的时候只动一处。这个取舍在长期项目里非常值得。
第三个坑是低估了团队习惯的惯性。设计系统建得再好,如果大家不用,就是零。我的对策是把“用系统”的门槛降到最低:提供模板、提供示例、提供一键生成脚本。让人不用系统比用系统还麻烦,习惯自然就转过来了。
最后分享一个我一直在用的小技巧:每次画完一张图,把它缩小到 25% 看一眼。如果缩小后还能看出结构和主次,说明这张图的视觉层次是成立的;如果缩小后变成一团糊,说明细节太多、层次不清,需要简化。这个“缩略图测试”帮我省了很多返工时间,你也可以试试。