前言
Markdown 的原生语法不支持绘制图形,但通过 Mermaid 扩展,我们可以将一些格式化的文字渲染成我们需要的图形。Mermaid 是一个类似 Markdown 的开源脚步语言,它能够根据输入的语句自动生成合适的图像,方便于 Markdown 文档撰写者通过文本方式生成图形的扩展工具。相比 Visio 它要轻很多,几行文字便可生成一幅完整且美观的流程图。
Mermaid 中包含多种可以使用的图表定义结构,考虑到实用性和学习成本,仅重点学习几种图形语法,分别是流程图(FlowChart)、时序图(Sequence Diagram)、类图(Class Diagram)、状态图(State Diagram)、用户行程图(User Journey)、甘特图(Gantt)、饼图(Pie Chart)等。推荐的学习方法是随用随学,Mermaid 语法并不难学,根据需要进行学习是比较实用的方法。
本文将重点介绍如何通过 Mermaid 绘制图,考虑到 Markdown 工具之间的不兼容,有的内容直接从页面复制粘贴到本地不会正常显示,有时还需要自己动手。本节所有实例代码及演示效果均使用 Typora 工具完成。Mermaid 为 Markdown 扩展语法,需要在 Typora 设置中开启对图表的语法支持。其方式为:「设置」->「Markdown」->「Markdown 扩展语法」-> 勾选「图表」,如下图:
Mermaid 官网:mermaid.js.org/
Mermaid 在线渲染编辑器:mermaid.live/
注意:需要注意的是,由于 Mermaid 本身还在发展,并非所有特性都能被所有 Markdown 编辑器支持。因此,某些效果展示我使用图片进行。
流程图可以用于展示某个过程中各个步骤的顺序和关系,例如软件开发过程中的各个阶段、某个业务流程中的各个环节等等。
一、基础语法
1.1 声明图像类型
告诉 Mermaid 下列语法是什么图像,可以用 flowchart 或 graph 声明流程图类型。在 Markdown 中添加 Mermaid 图形,需要声明 Mermaid 类型的代码块,关键字graph表示一个流程图的开始,同时需要指定该图的方向。代码如下:
```mermaid
<!-- 此处的内容会被渲染成 mermaid 图形 -->
```
- 至于 flowchart、graph 声明流程图类型的区别,参考 扩展 4.1
1.2 声明排列方向
声明完流程图图像类型后,还需要告诉 Mermaid 流程图的排列方向。其中:L代表Left左边、R代表Right右边、T代表Top上面、B代表Bottom下面,顺序为左边的字母到右边的字母:
| 顺序字母 | 代表意义 | 顺序字母 | 代表意义 |
|---|---|---|---|
| RL | 从右到左 | LR | 从左到右 |
| TB | 自上而下 | BT | 自下而上 |
| TD | 等同于 TB |
-
基本的竖向流程图:
```mermaid graph TD 开始 --> 结束 ```此部分代码将会渲染成如下效果:
graph TD 开始 --> 结束 -
基本的横向流程图:
```mermaid graph LR 开始 --> 结束 ```此部分代码将会渲染成如下效果:
graph LR 开始 --> 结束 -
展示一个复杂的方向流程图
```mermaid flowchart TB subgraph 从左到右 direction LR 声明图像类型1 --> 声明排列方向1 --> 声明图像内容1 end subgraph 从右到左 direction RL 声明图像类型2 --> 声明排列方向2 --> 声明图像内容2 end subgraph 上下分明 direction LR subgraph 从上到下 direction TB 声明图像类型3 --> 声明排列方向3 --> 声明图像内容3 end subgraph 从下到上 direction BT 声明图像类型4 --> 声明排列方向4 --> 声明图像内容4 end 从上到下 --> 从下到上 end 从左到右 --> 从右到左 --> 上下分明 ```此部分代码将会渲染成如下效果:
flowchart TB subgraph 从左到右 direction LR 声明图像类型1 --> 声明排列方向1 --> 声明图像内容1 end subgraph 从右到左 direction RL 声明图像类型2 --> 声明排列方向2 --> 声明图像内容2 end subgraph 上下分明 direction LR subgraph 从上到下 direction TB 声明图像类型3 --> 声明排列方向3 --> 声明图像内容3 end subgraph 从下到上 direction BT 声明图像类型4 --> 声明排列方向4 --> 声明图像内容4 end 从上到下 --> 从下到上 end 从左到右 --> 从右到左 --> 上下分明
1.3 声明节点
几何图形节点是流程图中的核心元素,在 Mermaid 语法中,有两种声明节点的方式:
直接声明:直接在连接声明区域声明节点,此时节点名字作为节点内容,节点样式采用默认样式(即[]样式)完整声明:使用节点名字[节点内容]声明节点,其中的[]代表节点样式,可以改变它以改变节点样式
```mermaid
graph LR
直接声明
M[完整声明]
```
此部分代码将会渲染成如下效果:
graph LR
直接声明
M[完整声明]
1.4 声明节点形状
形状可用于区分节点的不同属性,有利于丰富流程图的信息量,同时保持其简洁性。在 Mermaid 中可以使用一些基本符号定义节点的形状,例如:圆角形、跑道形、气缸形、非对称形状、菱形、六角形、平行四边形、梯形。节点形状常用语法以及使用见下表:
| 节点样式 | 节点语法 | 节点样式 | 节点语法 | 节点样式 | 节点语法 |
|---|---|---|---|---|---|
| 默认 | (文本) | 圆角矩形 | (文本) | 胶囊 | ([文本]) |
| 子程序 | [[文本]] | 圆柱 | [(文本)] | 圆形 | ((文本)) |
| 六边形 | {{文本}} | 棱形 | {文本} | 正四边形 | [/文本/] |
| 反四边形 | [\文本\] | 正梯形 | [/文本\] | 反梯形 | [\文本/] |
| 非对称的矩形 | >文本] | 双圆 | (((文本))) |
在 Mermaid 语法中,不加任何修饰的文字内容会被渲染成几何图形节点。这里需要特意说明下,”双圆“这个形状的节点支持的不算太好,个人建议是实际情况而定是否使用。其渲染结果如下:
graph TB
A
A1[默认]
A2(圆角矩形)
A3([胶囊])
A4[[子程序]]
A5[(圆柱)]
A6((圆形))
A7{{六边形}}
graph TB
A8{棱形}
A9[/正四边形/]
A10[\反四边形\]
A11[/正梯形\]
A12[\反梯形/]
A13>非对称的矩形]
1.5 声明节点间的连接
1.5.1 基本连接线
声明节点间的连接使得有关联的节点能被 Mermaid 识别并绘制连接线,在流程图中,不同节点之间需要通过连接线来描述其相关性。
- 声明单个连接语法
A --> B能够声明一条 A 到 B 链接 - 声明多个连接语法
A --> B --> C能够声明A 到 B、B 到 C 共两条链接 - 多个节点聚合声明语法
A & B --> C能够对多个节点进行操作声明 A 到 C、B 到 C 共两条链接
```mermaid
graph LR
A --> B
B --> C --> D
D --> E & F --> A
```
此部分代码将会渲染成如下效果:
graph LR
A --> B
B --> C --> D
D --> E & F --> A
1.5.2 调整链接的长度
在某些情况下,可以大致定义链接的长度而改善 Mermaid 画出的图形。Mermaid 内可以定义链接跨越的级数以调整链接长度,想要跨越多少级数,只需要在正常的连接符号上加入对应数量的-、.、=等符号即可。
graph LR
subgraph 没调整链接长度之前
direction TB
%% A --> B 的链接声明是正常的
A --> B --> D
D --> E
E --> B
end
subgraph 调整了链接长度之后
direction TB
%% A ---> B 的链接声明多了一个 - 符号
%% 代表着跨1个级别
A1 ---> B1 --> D1
D1 --> E1
E1 --> B1
end
```mermaid
graph LR
subgraph 没调整链接长度之前
direction TB
%% A --> B 的链接声明是正常的
A --> B --> D
D --> E
E --> B
end
subgraph 调整了链接长度之后
direction TB
%% A ---> B 的链接声明多了一个 - 符号
%% 代表着跨1个级别
A1 ---> B1 --> D1
D1 --> E1
E1 --> B1
end
```
1.5.3 调整链接的样式
不同种类的连接线可以表示不同类型的关系,例如,无方向的连接线可用来表示相关性、有方向的连接线可以表示数据流向或者节点间的依赖关系;用实线表示强关联、用虚线表示弱关联等待。常见连接线类型如下所示:
| 样式语法 | 样式效果 | 样式语法 | 样式效果 | 样式语法 | 样式效果 |
|---|---|---|---|---|---|
A1-->B1 | 箭头连接 | A2---B2 | 开放连接 | A3--text---B3 | 标签连接 |
A4--text-->B4 | 箭头标签连接 | A5-.-B5 | 虚线开放连接 | A6-.->B6 | 虚线箭头连接 |
A7-.text.-B7 | 标签虚线连接 | A8-.text.->B8 | 标签虚线箭头连接 | A9===B9 | 粗线开放连接 |
A10==>B10 | 粗线箭头连接 | A11==text===B11 | 标签粗线开放连接 | A12==text==>B12 | 标签粗线箭头连接 |
- 使用 graph 将会渲染成如下效果:
graph TD
A1-->B1
A2---B2
A3--text---B3
A4--text-->B4
A5-.-B5
A6-.->B6
A7-.text.-B7
A8-.text.->B8
A9===B9
A10==>B10
A11==text===B11
A12==text==>B12
- 使用 flowchart 将会渲染成如下效果:
flowchart TD
A1-->B1
A2---B2
A3--text---B3
A4--text-->B4
A5-.-B5
A6-.->B6
A7-.text.-B7
A8-.text.->B8
A9===B9
A10==>B10
A11==text===B11
A12==text==>B12
二、流程图-进阶使用
2.1 自定义节点样式
Mermaid 方流程图不仅支持多种节点形状、连接线种类,而且还支持节点自定义样式。由于节点有独一无二的节点名字,当要修改节点样式时,可以根据节点名字定位节点位置,定义节点样式语法如下:
style 节点名字 fill:#000, stroke:#000, stroke-width:0px, color:#000
| 属性 | 说明 |
|---|---|
| style | 定义形状的样式 |
| fill | 设置形状的填充颜色,可以是具体的颜色值(如"#FF0000"表示红色)或预定义的颜色名称(如"red"表示红色)。 |
| stroke | 设置形状的边框颜色 |
| stroke-width | 设置边框宽度,可以是具体的像素值(如"2px"表示2像素宽度)。 |
| stroke-dasharray | 设置虚线样式等 |
下面是一个示例,演示如何为形状设置样式和颜色:
```mermaid
graph LR
A --> B --> C --> D
style A fill:#F0F0F0,stroke:#333,stroke-width:2px;
style B fill:#FFF,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5;
style C fill:#FFA500,stroke:#333,stroke-width:2px;
style D fill:#FFF,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5;
```
渲染效果如下:
graph LR
A --> B --> C --> D
style A fill:#F0F0F0,stroke:#333,stroke-width:2px;
style B fill:#FFF,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5;
style C fill:#FFA500,stroke:#333,stroke-width:2px;
style D fill:#FFF,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5;
除了上述示例中的样式属性,Mermaid 还支持许多其他的样式属性,例如 font-size、font-weight、font-family、text-align、text-decoration 等,可以根据需要进行设置。使用 style 关键字可以将形状的样式和颜色与具体的业务逻辑和需求相匹配,使图表更加清晰和易于理解。
2.2 自定义形状大小
在 Mermaid 中,可以使用 style 关键字为形状设置大小。要设置形状的大小,可以使用 width 和 height 样式属性。width 样式属性用于设置形状的宽度,height 样式属性用于设置形状的高度。下面是一个示例,演示如何为形状设置大小:
```mermaid
graph LR;
A[Square] --> B((Circle));
C(Rectangle) --> D{Diamond};
style A fill:#f9c, width:80px, height:60px;
style B stroke:#333,stroke-width:4px, width:60px, height:60px;
style C fill:#f96,stroke:#333,stroke-width:2px, width:100px, height:80px;
style D fill:#fc9,stroke:#f63,stroke-width:4px,stroke-dasharray: 5 5, width:80px, height:80px;
```
graph LR;
A[Square] --> B((Circle));
C(Rectangle) --> D{Diamond};
style A fill:#f9c, width:80px, height:60px;
style B stroke:#333,stroke-width:4px, width:60px, height:60px;
style C fill:#f96,stroke:#333,stroke-width:2px, width:100px, height:80px;
style D fill:#fc9,stroke:#f63,stroke-width:4px,stroke-dasharray: 5 5, width:80px, height:80px;
在上面的示例中,我们为四个形状 A、B、C 和 D 设置了不同的大小。例如,我们使用 width 和 height 样式属性对形状的大小进行设置,使它们具有不同的宽度和高度。需要注意的是,形状的大小可以随需求进行调整,但过大或过小的形状可能会影响图表的可读性和美观性。因此,在设置形状的大小时需要根据具体的业务需求和图表设计进行合理的调整。
2.3 自定义链接样式
由于链接没有像节点一样的节点名字,所以如果要定义单个链接的样式,那么需要使用它的被声明顺序号(从0开始)。如我声明了三条链接,当我想要为第二条链接添加一个独特的样式时,应该这样做
linkStyle 1 stroke:#000, stroke-width:0px, color:#000
其中的
1就是该链接的被声明顺序号,假如要对全部连接进行改变,去掉顺序号即可
2.4 视图分组
对于相对庞大的流程图,可以通过对视图分组,以区分体系内的不同模块,以及不同模块间的关联关系。
```mermaid
graph LR
A --> B --> C --> D
subgraph Subgraph A
B1 --> C1 --> D1
end
subgraph Subgraph B
B2 --> C2 --> D2
end
```
此部分代码将会渲染成如下效果:
graph LR
A --> B --> C --> D
subgraph Subgraph A
B1 --> C1 --> D1
end
subgraph Subgraph B
B2 --> C2 --> D2
end
注意:在子图表中定义的形状只能在该子图表中使用,不能在其他子图表或图表中使用。
三、使用场景及实例
流程图常用于项目的需求分析和设计阶段,也较常出现于程序使用手册中。
3.1 竖向流程图
```mermaid
graph TD
A31-->B
A-->C
B-->D
C-->D
```
此部分代码将会渲染成如下效果:
graph TD
A31-->B;
A-->C;
B-->D;
C-->D;
3.2 冒泡排序流程图
```mermaid
graph LR
执行1[i = 1]
执行2[j = 0]
执行3[i ++]
执行4["a = arr[j], b = arr[j + 1]"]
执行5[交换 a, b]
执行6[j ++]
判断1["i < n"]
判断2["j < n - i"]
判断3["a > b"]
开始 --> 执行1
执行1 --> 判断1
判断1 --Y--> 执行2
执行2 --> 判断2
判断2 --Y--> 执行4
判断2 --N--> 执行3
执行3 --> 判断1
执行4 --> 判断3
判断3 --N--> 判断2
判断3 --Y--> 执行5
执行5 --> 执行6
执行6 --> 判断2
判断1 --N--> 结束
```
此部分代码将会渲染成如下效果:
graph LR
执行1[i = 1]
执行2[j = 0]
执行3[i ++]
执行4["a = arr[j], b = arr[j + 1]"]
执行5[交换 a, b]
执行6[j ++]
判断1["i < n"]
判断2["j < n - i"]
判断3["a > b"]
开始 --> 执行1
执行1 --> 判断1
判断1 --Y--> 执行2
执行2 --> 判断2
判断2 --Y--> 执行4
判断2 --N--> 执行3
执行3 --> 判断1
执行4 --> 判断3
判断3 --N--> 判断2
判断3 --Y--> 执行5
执行5 --> 执行6
执行6 --> 判断2
判断1 --N--> 结束
3.3 横向流程图
```mermaid
graph LR
start[开始] --> input[输入A,B,C]
input --> conditionA{A是否大于B}
conditionA -- YES --> conditionC{A是否大于C}
conditionA -- NO --> conditionB{B是否大于C}
conditionC -- YES --> printA[输出A]
conditionC -- NO --> printC[输出C]
conditionB -- YES --> printB[输出B]
conditionB -- NO --> printC[输出C]
printA --> stop[结束]
printC --> stop
printB --> stop
```
此部分代码将会渲染成如下效果:
graph LR
start[开始] --> input[输入A,B,C]
input --> conditionA{A是否大于B}
conditionA -- YES --> conditionC{A是否大于C}
conditionA -- NO --> conditionB{B是否大于C}
conditionC -- YES --> printA[输出A]
conditionC -- NO --> printC[输出C]
conditionB -- YES --> printB[输出B]
conditionB -- NO --> printC[输出C]
printA --> stop[结束]
printC --> stop
printB --> stop
四、扩展
4.1 flowchart VS graph
在绘制流程图的时候,将 graph 替换成 flowchart,可以呈现节点之间的曲线连接。比之前生硬的折线段美观很多。同时,flowchart还可以实现不同子图(subgraph)之间的连通,并且允许箭头逆向。相比之下,graph就只能在节点和节点之间按照既定方向相连。不过官网上显示flowchart仍然是测试版本,功能上可能会有一些欠缺。
- flowchart 效果
flowchart TB
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1
end
subgraph three
c1-->c2
end
one --> two
three --> two
two --> c2
```mermaid
flowchart TB
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1
end
subgraph three
c1-->c2
end
one --> two
three --> two
two --> c2
- graph 效果
graph TD
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1
end
subgraph three
c1-->c2
end
```mermaid
graph TB
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1
end
subgraph three
c1-->c2
end
```
4.2 字符转义
当你要输入特殊字符(与语法相冲突的字符)时,可以使用" "包裹住你的文本,这样就没有关系了。此外 Mermaid 还支持 HTML 的实体(以&表示的字符)。
五、结语
把今天最好的表现当作明天最新的起点…...~
投身于天地这熔炉,一个人可以被毁灭,但绝不会被打败!一旦决定了心中所想,便绝无动摇。迈向光明之路,注定荆棘丛生,自己选择的路,即使再荒谬、再艰难,跪着也要走下去!放弃,曾令人想要逃离,但绝境重生方为宿命。若结果并非所愿,那就在尘埃落定前奋力一搏!