在 Mermaid 12 中,layout 配置项决定使用哪个布局引擎:大多数图结构类图表默认使用 ELK。如果想恢复之前的引擎,可以在 front matter 或 mermaid.initialize() 中设置 layout: dagre。
你升级了版本,重新构建了文档站点,结果一张没人动过的流程图不仅形状变了,颜色也变了。旧版答案里给出的 flowchart: { defaultRenderer: ... } 这类图表类型配置段,已经无法解决这个问题。
本文介绍具体有哪些变化、在哪里设置布局、哪个设置优先级更高、如何调优 ELK,以及为什么回退设置看起来毫无效果。流程图基础知识请参阅使用流程图优化工作流。
核心要点
- 从 Mermaid 12.0.0 开始,未设置布局的流程图、状态图、类图、实体关系图、需求图、用例图和 agentflow 图改由 ELK 而非 dagre 进行排布。
layout: dagre只能恢复旧的排布,无法恢复旧的外观。要完整还原 12 之前的渲染效果,需要同时设置layout: dagre、theme: default和look: classic。- 单个图表中的 front matter 或指令(directive)会覆盖
mermaid.initialize(),因此对于自行指定布局的图表,站点级的 dagre 设置不会生效。 - Mermaid 12 已从 flowchart、class 和 state 配置段中移除
defaultRenderer,请改用顶层的layout配置项。 - tiny 构建版本不包含 ELK,除非添加
@mermaid-js/layout-elk,否则会回退到 dagre。
Mermaid 12 有哪些变化?
从 Mermaid 12 开始,未指定布局的图表改由 ELK 而非 dagre 进行排布。这意味着,即使图表内容没有任何改动,升级后其形状也可能发生变化。布局配置页面列出了现在默认使用 ELK 的七种图表类型:流程图、状态图、类图、实体关系图、需求图、用例图和 agentflow 图。ELK 随主包一起发布,并会自动完成注册。思维导图(mindmap)仍默认使用 cose-bilkent,而 tidy-tree 则来自独立的 @mermaid-js/layout-tidy-tree 包。
mermaid@12.0.0 发布说明还提到了第二项变化:对于主题页面中按图表列出的默认值所涵盖的更多图表类型,默认主题现为 redux-color,默认外观(look)现为 neo。因此,v12 图表看起来不同可能出于两个独立的原因:一是布局引擎变了,二是主题和外观变了。
在哪里设置布局:front matter、initialize() 还是按类型配置?
Mermaid 布局既可以针对单个图表设置,也可以针对站点上的所有图表统一设置。你还可以将主题和外观的作用范围限定到某一种图表类型。当设置发生冲突时,作用范围最具体的设置胜出。
| 作用范围 | 位置 | 语法 | 优先于 |
|---|---|---|---|
| 单个图表 | front matter 或指令 | config: layout: dagre | 下方所有项 |
| 所有图表 | mermaid.initialize() 顶层 | { layout: 'dagre' } | 类型默认值和全局默认值 |
| 单一图表类型 | 内置类型默认值 | (由 Mermaid 设置) | 全局默认值 |
| 全部 | 全局默认值 | (由 Mermaid 设置) | 无 |
12.0.0 发布说明给出的解析顺序为:首先是 front matter 或指令,其次是 initialize(),然后是图表类型默认值,最后是全局默认值。
以下示例展示如何将单个图表完整回退:
---
config:
layout: dagre
theme: default
look: classic
---
flowchart LR
Request --> Auth{Valid token?}
Auth -->|yes| Handler
Auth -->|no| Reject
在站点级别,下面第一个调用只更改布局引擎,其他均保持不变,因此新配色仍会保留;第二个调用则会恢复 12 之前的完整渲染效果:
mermaid.initialize({ layout: 'dagre' });
mermaid.initialize({ layout: 'dagre', theme: 'default', look: 'classic' });
Mermaid 12 还允许在某一图表类型的配置段中,将 theme、look 和 layout 的作用范围限定到该类型。在同一位置设置时,限定范围的值优先于全局值。如果想让所有图表都切换到 dagre,但仅为类图恢复旧外观,可以将 layout 保留在顶层,并把 theme 和 look 放入 class 配置段中,正如类图页面所示:
mermaid.initialize({
layout: 'dagre',
class: { theme: 'default', look: 'classic' },
});
front matter 的优先级始终高于 mermaid.initialize()。假设某个站点在全局设置了 layout: 'dagre',而某个图表在其 front matter 中声明了 layout: elk,那么该图表将使用 ELK 渲染。
Mermaid ELK 布局何时有用?如何调优?
对于规模较大或较为拥挤的图表,建议使用 ELK;如果小型图表本来就显示良好,则可以继续使用 dagre。Mermaid 文档将 ELK 定位为适用于大型复杂图表的布局引擎,而 dagre 作为历史悠久的分层布局引擎依然可用。如果你的图表在升级前渲染效果良好,回退到 dagre 是一个合理的选择。
语法参考中的布局章节记录了多个 ELK 调优配置项,其中包括:mergeEdges 用于合并平行边;nodePlacementStrategy 可选值为 SIMPLE、NETWORK_SIMPLEX、LINEAR_SEGMENTS 或 BRANDES_KOEPF,在 default 预设下默认值为 BRANDES_KOEPF;nodePlacementAlignment 用于设置 Brandes-Koepf 的对齐方式(例如 BALANCED 或 NONE),省略时对齐方式由预设决定。
---
config:
layout: elk
elk:
mergeEdges: true
nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart TD
Build --> Test --> Deploy
Build --> Lint --> Deploy
在 v12 之前就已使用 ELK 的图表同样可能发生变化,因为现在默认采用平衡式 Brandes-Koepf 节点放置。ELK 预设 schema 列出了四个 preset 取值:legacy、default、modelOrder 和 depthFirst。其中,depthFirst 是之前的默认值,而 legacy 会还原预设机制引入之前 ELK 的渲染方式。
在 12.x 版本内部,ELK 的输出也发生过变化:
- Mermaid 12.1.0 新增了默认开启的
orientFeedbackEdges。当某条边从子图所指向的节点出发、又回连到该子图时,现在会沿下游方向布线,而不再绕过子图。 - Mermaid 12.2.0 起,如果拉直边的端点会导致标签覆盖到其他边上,ELK 将不再执行拉直操作。
config:
layout: elk
elk:
preset: legacy
orientFeedbackEdges: false
可以使用哪些 ELK 变体和子图级算法?
除了 layout: elk 之外,Mermaid 布局页面还列出了六种可用作 layout 取值的 ELK 变体:elk.stress、elk.force、elk.mrtree、elk.sporeOverlap、elk.box 和 elk.rectpacking。
---
config:
layout: elk.mrtree
---
flowchart TD
Root --> API
Root --> Web
API --> Workers
根据 12.0.0 发布说明,elk.box 和 elk.rectpacking 只负责放置节点,不负责边的布线,因此其边会以中心到中心的直线绘制。
单个子图可以通过 @{ algorithm: ... } 选择自己的算法。同一份发布说明列出的可接受取值为上述六种变体,外加 elk.layered 和 elk.radial。关于这一覆盖机制,发布说明还指出两点:Mermaid 会忽略不受支持的取值并给出警告;当有边跨越子图边界时,会改用继承而来的算法。
为什么我的布局修复没有生效?
大多数回退失败都源于以下五个原因之一,请按顺序逐一排查:
- 仍在设置
defaultRenderer。 流程图语法页面指出,v12 已将其从 flowchart、class 和 state 配置段中移除,请改用layout。 - 只设置了
layout: dagre。 redux-color 主题和 neo 外观仍然生效,需要同时设置这三个配置项。 - front matter 覆盖了
initialize()。 请将该图表 front matter 中的layout删除。 - 布局名称拼写错误或未注册。 发布说明指出,这种情况下 Mermaid 会回退到 dagre 并给出警告,而不会抛出错误。请检查控制台输出。
- 正在使用 tiny 构建版本。 请参阅下一节。
从 defaultRenderer 迁移只需修改一行:
// Before (removed in v12)
mermaid.initialize({ flowchart: { defaultRenderer: 'elk' } });
// After
mermaid.initialize({ layout: 'elk' });
如果你使用的文档平台尚未升级到 v12,这些配置项的行为可能仍与旧版一致,请查阅该平台自身的文档。
为什么 tiny 构建版本会回退到 dagre?
Mermaid 的 tiny 构建版本不包含 ELK,因此在该版本中,任何请求 ELK 的图表都会以 dagre 渲染。针对这种情况,@mermaid-js/layout-elk 包仍在持续发布。请按照使用文档中 ELK 与 tiny 构建版本一节的注册步骤操作。在常规构建版本中,现有的 registerLayoutLoaders 调用仍可正常工作,但已不再必要,可以删除。
结语
升级到 Mermaid 12 后图表发生变化,几乎都源于两个原因:ELK 布局引擎,以及新的主题和外观。先确定你想恢复的内容:如果只想恢复旧的形状,设置 layout: dagre 即可;如果想完整还原 12 之前的渲染效果,则需设置 layout: dagre、theme: default 和 look: classic。之后,再在配置中搜索是否残留 defaultRenderer 设置,以及是否有 front matter 覆盖了你的站点级设置。
常见问题
在 Mermaid 12 中,flowchart-elk 图表关键字还能用吗?
可以。Mermaid 12.0.0 发布说明指出,flowchart-elk 作为显式图表关键字仍然有效。发生变化的是 defaultRenderer 选项:Mermaid 会忽略它而非拒绝它,因此仍设置该选项的配置不会报错,但也不会产生任何效果。如果某个图表依赖将 flowchart 的 defaultRenderer 设为 'elk' 来获得 ELK 布局,应改为设置 layout: elk。
内置 ELK 会让 Mermaid 12 的加载体积变大吗?
只有单文件构建版本会明显变大。在 ESM 构建版本中,ELK 是一个独立的 chunk,仅在图表用到时才会加载。12.0.0 发布说明指出,IIFE 构建版本 mermaid.min.js 会内联 ELK,gzip 压缩后体积约增加 500 kB。tiny 构建版本不包含 ELK,体积保持不变,并会使用 dagre 处理 ELK 布局请求。
能否在站点级别统一设置 ELK 调优选项,而不必在每个图表的 front matter 中设置?
可以。elk 是 Mermaid 配置 schema 中的顶层属性,因此可以将其与 layout 一起传给 mermaid.initialize(),例如设置 layout: 'elk',并传入一个包含 mergeEdges: true 和 nodePlacementStrategy: 'NETWORK_SIMPLEX' 的 elk 对象。%%{init}%% 指令也可以为单个图表接受相同的 elk 对象。单个图表中的 front matter 仍会覆盖站点级的设置值。
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k