技术拆解-Mermaid

运行

1
npm run dev:vite

然后访问:http://localhost:9000/

绘图

饼图

D3.js
可以参考饼图的代码:
mermaid/packages/mermaid/src/diagrams/pie/pieRenderer.ts

flowchart

D3.js + Dagre

mindmap

Cytoscape + D3.js
布局用的 Cytoscape
画图用的 D3.js

草图风格 Rough

代码结构

  • spec.ts:使用 Jest 框架编写的单元测试文件,主要用于测试 pie 模块的功能
  • Db.ts:数据管理,各种 add、set、get 方法
  • Detector.ts:识别 pie 的文本,并 import pieDiagram.js
  • Diagram.ts:对外的 Facade,包含了 Db、Renderer、Parser、Styles 等
  • Parser.ts:AST 解析文本为 Pie 对象
  • Renderer.ts:绘图
  • Styles.ts:样式 Token
  • Types.ts:类型定义

数据结构

图表

基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Generic Diagram DB that may apply to any diagram type.
*/
export interface DiagramDB {
// config
getConfig?: () => BaseDiagramConfig | undefined;

// db
clear?: () => void;
setDiagramTitle?: (title: string) => void;
getDiagramTitle?: () => string;
setAccTitle?: (title: string) => void;
getAccTitle?: () => string;
setAccDescription?: (description: string) => void;
getAccDescription?: () => string;

setDisplayMode?: (title: string) => void;
bindFunctions?: (element: Element) => void;
}

Pie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export interface PieDB extends DiagramDB {
// config
getConfig: () => Required<PieDiagramConfig>;

// common db
clear: () => void;
setDiagramTitle: (title: string) => void;
getDiagramTitle: () => string;
setAccTitle: (title: string) => void;
getAccTitle: () => string;
setAccDescription: (description: string) => void;
getAccDescription: () => string;

// diagram db
addSection: ({ label, value }: D3Section) => void;
getSections: () => Sections;
setShowData: (toggle: boolean) => void;
getShowData: () => boolean;
}

draw()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Type for function draws diagram in the tag with id: id based on the graph definition in text.
*
* @param text - The text of the diagram.
* @param id - The id of the diagram which will be used as a DOM element id.
* @param version - MermaidJS version from package.json.
* @param diagramObject - A standard diagram containing the DB and the text and type etc of the diagram.
*/
export type DrawDefinition = (
text: string,
id: string,
version: string,
diagramObject: Diagram
) => void | Promise<void>;

布局 Layout

协议

flowchart

样式是在末尾定义的,给每个节点定义的样式,通过节点的 ID(比如 A、B、C)进行绑定。
感觉这样定义,表现力并不强?而且一些复杂的效果估计不好描述。
动画怎么描述?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
flowchart LR
subgraph subgraph_zv2q8ucnp["Shape descriptions"]
customer(("Customer"))
Support["Support"]
Technician{{"Technician"}}
Decision{"Decision"}
end
A(("Reported issue")) --> B["Ticket is created"]
B --> C{"Working hours?"}
C -- Yes --> E{{"Tickets are sent to day team for response"}}
C -- No --> F["Tickets are sent to on-call staff for response"]
E --> Worked{"Ticket being worked on?"}
F --> Worked
Worked -- Yes --> G["Work on the tickets based on priority"]
Worked -- No --> Reminder["Reminder is sent"]
Reminder --> Worked
G --> H["Team fixes the issue"]
H --> I{"Is the issue resolved?"}
I -- Yes --> Done["Ticket is closed and follow-up email is sent"]
I -- No --> H

customer:::redNode
Support:::pinkNode
Technician:::yellowNode
Decision:::blackNode
A:::redNode
C:::blackNode
E:::yellowNode
F:::pinkNode
Worked:::reminderNode
G:::pinkNode
H:::pinkNode
I:::reminderNode
Done:::greenNode
classDef redNode fill:#D50000,color:#000000
classDef pinkNode fill:#E1BEE7,color:#000000
classDef yellowNode fill:#FFF9C4,color:#000000
classDef blackNode fill:#000000,stroke:#FFD600,stroke-width:4px,stroke-dasharray: 0,color:#FFFFFF
classDef greenNode fill:#00F840,color:#000000
classDef reminderNode stroke:#FFD600,stroke-width:4px,stroke-dasharray: 0,fill:#000000,color:#FFFFFF
classDef blueSubgraph fill:#BBDEFB
style A stroke:#2962FF,fill:#AA00FF
style C fill:#00C853
linkStyle 2 stroke:#00C853,fill:none
linkStyle 3 stroke:#D50000,fill:none
linkStyle 6 stroke:#00C853,fill:none
linkStyle 7 stroke:#D50000,fill:none
linkStyle 11 stroke:#00C853,fill:none
linkStyle 12 stroke:#D50000,fill:none

Takeaways

为什么节点要展平成平铺的 g 结构:增加可编辑性

类似 Photoshop,层的概念,可以任意移动布局。
因此带有编辑概念的(Mermaid、Napkin),都是这样的平铺结构。

日志

1
log.info('REF0:');

不足

缺少动画

缺少 timeline 播放

资料

github:
https://github.com/mermaid-js/mermaid

在线编辑器:
https://github.com/mermaid-js/mermaid-live-editor

mermaidchart:
https://www.mermaidchart.com/
这个是企业版,支持了拖拽布局、AI、画布、节点样式编辑等功能。
其中画布、节点样式编辑目前仅支持 Flowchart 和 Sequence Diagram。