Reladraw 是一类"位置由你说了算"的图表工具:你用一段文本描述节点放在哪个坐标、连到谁、长什么样,它负责渲染。和那些"拖一下、对齐一下、第二天打开发现全乱了"的画图软件相比,它的好处是图变成了可以进 Git、可以 diff、可以复制的文本。
这篇教程带你从零写出一张四层架构图(客户端 → 网关 → 服务 → 数据库),位置全部由坐标控制,最后导出成可以贴进文档的 SVG。文中的字段名、子命令名属于通用写法,不同版本的 Reladraw 可能略有差异,具体语法以官方文档当前版本为准,方法本身是通用的。
这篇能做出什么
完成后你会得到:
1. 一份纯文本的图定义文件,大约 40 行,写清楚每个节点放在画布的第几个格子;
2. 一条命令导出 SVG / PNG,改一个数字图就变,不需要重新拖拽;
3. 一套"网格坐标法",让你不用试错也能算出位置;
4. 一份踩坑清单,包含坐标原点、容器相对坐标、中文文字溢出等高频问题。
先看最终效果对应的结构:左边一列是入口,中间两列是服务,右边一列是存储,横向三条连线。位置全部由 x、y 两个数字决定。
前置条件清单
- Reladraw 的运行环境(桌面客户端、网页版或命令行工具,看你装的是哪个,以官方文档为准);
- 任意文本编辑器,能看 YAML 缩进就行;
- 一张纸上先列好节点清单:有哪些模块、谁连谁、分成几组;
- 如果走命令行导出路线,需要本机有对应的运行时环境(比如 Node.js 一类的运行时),具体依赖以官方文档为准;
- 一颗不着急的心:第一次算坐标会慢,第二次开始就是复制粘贴。
第 1 步:先定坐标系,别急着写字
绝对定位类工具的坐标系几乎都是这样的:原点在左上角,x 向右增大,y 向下增大,单位是像素。这一点必须先确认,因为很多人的直觉是数学坐标系(y 向上),画出来整个图会上下颠倒。
先决定三件事:
- 画布多大:给个
1200 x 720,比 A4 横版略宽,贴文档刚好; - 列宽多少:取
280,够放 6~8 个中文字符加内边距; - 行高多少:取
120,节点高度64,上下各留 28 的间隙。
有了这三个数,坐标就不是"试出来"的,而是"算出来"的:
```text
x = 80 + 列号 * 280 列号从 0 开始
y = 80 + 行号 * 120 行号从 0 开始
```
于是四列的 x 分别是 80、360、640、920;四行的 y 分别是 80、200、320、440。
第 2 步:写出第一个最小可运行的图
下面是一份 YAML 风格的图定义。这类 DSL 常见两种写法:YAML 风格(缩进敏感、适合程序生成)和括号风格(适合手写),下面用前者举例。
```yaml
canvas:
width: 1200
height: 720
background: "#ffffff"
nodes:
- id: client
label: 浏览器 / App
x: 80
y: 320
w: 160
h: 64
- id: gateway
label: API 网关
x: 360
y: 320
w: 160
h: 64
- id: order
label: 订单服务
x: 640
y: 200
w: 160
h: 64
- id: user
label: 用户服务
x: 640
y: 440
w: 160
h: 64
- id: db
label: 主库
x: 920
y: 320
w: 180
h: 64
edges:
- from: client
to: gateway
label: HTTPS
- from: gateway
to: order
- from: gateway
to: user
- from: order
to: db
- from: user
to: db
```
把它保存成 arch.yaml,用 Reladraw 打开或渲染。这时候你应该看到一条从左往右的主干,中间在网关处分叉成上下两条,再汇到右边的数据库。
注意 y: 320 那一行:行号其实是 2(80 + 2×120 = 320),所以网关和数据库在同一水平线上,订单服务在它上方,用户服务在下方。这就是"网格法"的价值——你脑子里想的是"网关在第 3 行",手上打出来的是数字。
第 3 步:用分组框把边界画出来
架构图好看不好看,很大程度取决于有没有分组。加一层容器,把服务圈在一起:
```yaml
groups:
- id: g_front
label: 接入层
x: 40
y: 280
w: 220
h: 144
- id: g_service
label: 业务服务
x: 600
y: 160
w: 240
h: 384
- id: g_data
label: 数据层
x: 880
y: 280
w: 260
h: 144
```
分组框的画法通常是"先画框、再画里面的节点",因为框通常要在填充和描边上都更淡一点,视觉上才会退到后面去。如果工具支持 z 或 layer 字段,把分组框的层级调到节点之下。
这里有一个关键问题:分组内部的节点,坐标是相对框还是相对画布? 两种设计都有人做,行为完全不同。相对坐标的话,节点 x 要从分组框的左上角重新算;绝对坐标的话,上面那份 nodes 一个数字都不用改。第一次用务必只放一个节点测一下,再批量写。
第 4 步:控制连线从哪里出发
默认情况下,连线会自动选最近的两个边作为出入口。图简单的时候没问题,节点一多就会出现连线贴着文字走、或者两条线重叠。
处理办法通常是给边加锚点或端口:
```yaml
edges:
- from: gateway
to: order
fromAnchor: right
toAnchor: left
route: orthogonal
label: gRPC
labelPosition: 0.5
```
几个概念:
fromAnchor/toAnchor:指定从节点的哪条边出去(top/right/bottom/left);route: orthogonal:走直角折线,架构图里比斜线好读;需要曲线时换成对应的值;label:边上的文字,比如协议名、数据流向;labelPosition:0 到 1 之间的数字,控制标签落在连线的哪个位置,避免压到节点。
如果两条线还是重叠,可以给其中一条加一个 waypoints(中间控制点)列表,手动把线掰开:
```yaml
edges:
- from: user
to: db
waypoints:
- x: 840
y: 480
- x: 1010
y: 480
```
这本质上还是在"自己定位置",只不过定的是连线的位置。
第 5 步:样式、字体和深浅色
样式一般分三层:全局主题、分组级、节点级。能放全局的就别放节点级,否则改一次颜色要改 20 个地方。
```yaml
theme:
fontFamily: "Source Han Sans, Noto Sans CJK SC, sans-serif"
fontSize: 14
node:
fill: "#f7f9fc"
stroke: "#c8d3e0"
radius: 8
edge:
stroke: "#6b7a90"
width: 1.5
nodes:
- id: db
label: 主库
x: 920
y: 320
w: 180
h: 64
style:
fill: "#eef6ff"
stroke: "#7aa7d6"
```
关于字体,有一点必须提前做:如果图上会出现中文,字体列表里一定要写中文字体,或者把字体文件嵌进导出结果。否则在别人的电脑上打开 SVG,中文可能变成方框。
第 6 步:导出与进版本库
导出通常有命令行和图形界面两条路。命令行的形态大致是这样:
```bash
渲染成 SVG(子命令与参数名以官方文档为准)
reladraw export arch.yaml --format svg --out arch.svg
渲染成高清 PNG,倍率按需调整
reladraw export arch.yaml --format png --scale 2 --out arch.png
```
SVG 和 PNG 各有用途:SVG 放大不糊、适合贴网页和文档,但字体依赖环境;PNG 到处都能看,但不方便再编辑。稳妥的做法是两份都出,SVG 进仓库当源文件,PNG 用来发消息。
如果工具支持渲染到标准输出(--out - 或者省略输出路径),就能接进 CI:
```bash
提交前自动检查图能不能渲染出来
reladraw export arch.yaml --format svg --out /dev/null
```
这一步能拦住"改了 YAML 缩进、图直接渲染失败"的低级事故。
常见坑与排错
图整个上下颠倒或跑出画布。 九成是坐标系方向理解反了。先放一个节点在 (0, 0),看它出现在左上角还是左下角。
节点位置比预期偏了半个身位。 有些实现里 x / y 指的是节点左上角,有些指的是中心点。判断方法:把同一个坐标给两个不同尺寸的节点,看它们的左上角是否重合。
分组加进去之后节点全跑偏。 容器内坐标是相对还是绝对的问题,见第 3 步。测一个节点就能确定。
中文标签溢出边框。 手动定位置的代价就是得自己留够宽度。经验值:中文按每字约 14~16 px 估(跟随字号变化),英文字符按一半估,再左右各留 16 px 内边距。拿不准就把 w 加大 20 px,宁可松一点。
连线和文字叠在一起。 用 labelPosition 挪标签,或者换 fromAnchor / toAnchor 让线走另一条边。
YAML 缩进报错。 缩进只能用空格,同一层级必须对齐。别在文件里混用 Tab。报错信息通常会给出行号,从那一行的上一行开始看。
id 重复。 两个节点用了同一个 id,连线会连到意料之外的地方。命名上建议加前缀区分模块,比如 svc_order、db_order。
导出后中文变方框。 目标环境没装对应字体。解决办法是把字体内嵌进导出文件,或者导出时把文字转成路径。具体开关以官方文档为准。
改了 YAML 但画面没变。 有些客户端有缓存或需要手动刷新。先确认保存了,再确认工具读的是不是同一个文件路径。
下一步建议
把坐标抽成常量。 如果 DSL 支持变量或引用,把列宽、行高、起始边距定义成一组数字,后面所有坐标都用表达式算。改一次间距,全图跟着变,这是"手写图"能长期维护的关键。
把大图拆成多个文件。 前端一张、后端一张、数据一张,用 include 或 import 合成。单文件超过 200 行之后,找节点会变成体力活。
给自己留一份坐标草图。 在 YAML 顶上写注释,标明列 0/1/2/3 的 x 值分别是多少。三个月后回来改图,你会感谢现在的自己。
用同一套方法画别的图。 RAG 管线、Agent 编排、部署拓扑、审批流程,只要是"有明确分层和流向"的图,都可以用同一套网格法加绝对定位来写。DSL 画图真正省时间的场景,不是画一次,而是画完还要改十次。
把图交给 CI 检查。 渲染失败就报错,顺带把导出的 SVG 存档,文档里引用最新版本,图再也不会和代码脱节。
