首页
/ Mermaid Venn 图完全指南:用 `venn-beta` 语法绘制集合关系图(v11.12.3+)

Mermaid Venn 图完全指南:用 `venn-beta` 语法绘制集合关系图(v11.12.3+)

2026-09-06 19:01:05作者:晏闻田Solitary

Venn 图用相互交叠的圆来表达集合之间的包含、相交与互斥关系。本指南以 Mermaid 仓库中 packages/mermaid/src/docs/syntax/venn.md 为骨架,结合 parser/venn.jisonvennDB.tsvennRenderer.ts 等源码实现,帮助你从零掌握 Mermaid Venn 图的声明式语法——从集合、并集、尺寸标注到自由文本节点与精细样式控制,并理解其底层渲染原理。读完本文,你能够直接编写可运行的 Venn 图定义,并知道在什么样的情况下如何排错与调优。

警告 Venn 是 Mermaid 中较新的图类型(v11.12.3 起提供),当前语法以 venn-beta 开头,属于先行体验特性,其语法在后续版本中可能演进。

Venn 图能表达什么:基础语法速览

Venn 图展示集合之间的关系,Mermaid 通过圆形交叠直观呈现"谁和谁有交集、交集里又放了什么"。它的声明式定义由四种核心语句构成:

关键字 作用 示例
venn-beta 声明图类型(必须作为首行) venn-beta
set 定义一个单独的集合 set Frontend
union 定义两个及以上集合的交叠区域 union Frontend,Backend
text 在集合/交叠区域内部放置标签节点 text A1["React"]
style 为集合、并集与文本节点应用视觉样式 style A fill:#ff6b6b
title 为整张图设置标题 title "Team overlap"

一组最小可运行的示例(图中团队交集被命名为 APIs):

venn-beta
  title "Team overlap"
  set Frontend
  set Backend
  union Frontend,Backend["APIs"]

语法要点如下:

  • 标识符规则:集合标识符既可以是裸词(如 ASet_1),也可以是带引号的字符串(如 "Foo Bar")。从语法解析器 parser/venn.jison 可以看到,标识符令牌(IDENTIFIER)匹配 [A-Za-z_][A-Za-z0-9\-_]*,字符串令牌(STRING)匹配 "[^"]*",二者都可用作标识符。
  • 必须先定义后引用union 中出现的每个集合名都必须在更早的 set 行中定义过。解析时 vennDB.tsvalidateUnionIdentifiers 会把并集中未注册的名字过滤出来,直接抛出 unknown set identifier: ... 异常。
  • union 至少需要两个集合:语法中只有两个以上标识符才能构成 union,否则抛出 union requires multiple identifiers(见 venn.jison)。
  • 解析器在 %options case-insensitive 模式下工作,因此关键字大小写不敏感。

["..."] 括号标签让显示名与短标识分离

当你希望图中显示可读的名字(例如 AlphaTeam overlap),又想让标识符保持简短(例如 A),可以为 setunion 甚至 text 节点统一使用括号标签语法:

venn-beta
  set A["Alpha"]
  set B["Beta"]
  union A,B["AB"]

需要留意的解析细节:

  • 带引号写法 ["..."]BRACKET_LABEL 令牌支持(\[\"[^\"]*\"\]),不带引号的 [Alpha] 同样可用(见 venn.jison),仓库的解析器测试 venn.spec.ts 对两种写法均做了断言。
  • 标签与标识符是分离存储的:数据库层 vennDB.ts 把标签统一经过 normalizeText(去掉首尾空白与成对引号)后保存,而布局与渲染始终以标识符组合定位。因此对 style 或后续 union 的引用仍使用原始标识符,不受标签影响。

高元并集:三个及以上集合的自动补全

union 允许一次接收三个或更多集合名:

venn-beta
  set Desirable
  set Feasible
  set Viable
  union Desirable,Feasible,Viable["Innovation"]

从代码层面看,这里有一个非常关键的自动处理:底层绘图依赖 @upsetjs/venn.js 的布局算法,该算法要求两两交叠条目(pairwise intersections)必须显式存在,才能把三个及以上圆的重叠中心正确摆出。因此渲染器 vennRenderer.ts 中的 ensurePairwiseSubsets 会对每个 N 元(N≥3)并集枚举所有二元组合,自动补齐缺失的两两交叠数据。文档注释指出:这些补齐条目只用于渲染,存储在数据层的 subsets 不会被修改,因此解析测试中基于 getSubsetData() 的断言不受影响。

其中被补齐的交叠区尺寸遵循启发式规则:若参与的两个集合都定义了尺寸,则取较小者的 1/4,保证重叠区可见但小于任一集合;否则回退到 2.5(即二元并集的默认尺寸)。这正是"高元并集标签有可见区域可坐"的实现保证。

:N 后缀控制集合与并集的相对大小

Venn 图中圆的相对大小由尺寸数字驱动。在 setunion 的标识符/标签之后追加 :数字 即可:

venn-beta
  set A["Alpha"]:20
  set B["Beta"]:12
  union A,B["AB"]:3

默认尺寸的规则可以在 vennDB.ts 找到精确公式:

  • 未指定尺寸时按 size = 10 / identifierList.length² 计算;
  • 于是单个 set 的默认尺寸为 10 / 1 = 10,二元 union 默认尺寸为 10 / 4 = 2.5,三元并集默认约 1.11,以此类推;
  • 解析器测试 venn.spec.ts 验证了 set A:20set B:12union A,B:3 会被分别解析为 size 20、12、3。

尺寸数字与视觉半径成正比,用于在集合较多时大致还原"哪个集合元素更多、交集占多大比重"的直觉关系。v11.x 目前并不保证像素级精确的几何缩放,更适合表达相对量级。

文本节点:在集合内部放置说明文字

text 用于在集合或并集内部放置标签,适合填充成员/要素清单。它有两种书写方式:

方式一:缩进式。缩进的 text 行会自动挂载到"最近"的一个 setunion 上。语法规则中的 indentedTextTail(见 venn.jison)会读取 yy.getCurrentSets() 得到归属区域;如果当前没有 set/union 上下文却出现缩进 text,将抛出 text requires set。缩进时同样可以使用 ["..."] 设置显示标签:

venn-beta
  set A["Frontend"]
    text A1["React"]
    text A2["Design Systems"]
  set B["Backend"]
    text B1["API"]
  union A,B["Shared"]
    text AB1["OpenAPI"]

方式二:显式区域式。不缩进时,text 也可以带一个显式标识符列表来指定归属,即文法 TEXT identifierList ...。无论是哪种方式,文本节点的标识符(如 A1)都会进入独立的 textNodes 列表,供后续 style 精准引用。

渲染细节(源于 vennRenderer.ts):文本节点按归属区域分组后,会以区域中心为基准计算内切安全半径,并将文本排布成自动网格;每个文本通过 foreignObject + HTML span 渲染,从而支持自动换行与居中。若某文本节点恰好位于高元并集中心这类"视觉上不存在"的位置,渲染器会基于 min circle radius 推导兜底内半径,确保文本仍能得到合理摆放。

样式系统:fill / color / stroke 全解析

style 语句可为集合、并集与文本节点应用视觉样式。支持的目标与属性如下:

属性 作用
fill 改变填充颜色
color 改变文字颜色
stroke 改变描边颜色
stroke-width 改变描边宽度
fill-opacity 改变填充透明度

示例(同时演示对多个目标批量上色):

venn-beta
  set A["Alpha"]:20
    text A1["React"]
    text A2["Design Systems"]
  set B["Beta"]:12
  union A,B["AB"]:3
  style A fill:#ff6b6b
  style A,B color:#333
  style A1 color:red

关于样式,值得理解几个实现级事实:

  • 目标可为列表style A,B ...identifierList 允许多个标识符(文法见 venn.jison),对应解析测试 venn.spec.ts 中 targets 为 ['A','B'] 的用例。
  • 颜色取值宽泛:样式值支持十六进制颜色 #ff6b6brgb(...)rgba(...)(词法规则 HEXCOLOR/RGBCOLOR/RGBACOLORvenn.jison),也支持 color:red 这类命名色;带空格的复合值会被逐令牌拼接。解析测试对 fill:rgb(255, 0, 128)fill:rgba(255, 0, 128, 0.5) 均有断言(venn.spec.ts)。
  • 样式如何落到画布:渲染阶段 vennRenderer.ts 先把样式条目按键(排序后的目标集合串)合并为查找表;随后对每个圆形路径应用 fillfill-opacitystrokestroke-width 并取 color 覆盖默认文字色。未指定 fill 时使用主题色板 themeVariables.venn1..venn8 自动轮换;fill-opacity 默认 0.1,描边默认宽度为 5 * scale
  • 文字对比度自适应:当未显式指定 color 时,渲染器依据当前背景明暗将基准填充色 lighten/darken 后作为文字色,保证标签在浅色/深色主题下均清晰可读(vennRenderer.ts)。
  • 多条指向同一目标的 style 语句会合并而非覆盖:buildStyleByKey 对重复 key 使用 Object.assign 追加属性(vennRenderer.ts),多条 style 可分别补全不同属性。

通过配置项调整画布与调试布局

Venn 图的默认配置定义在 packages/mermaid/src/schemas/config.schema.yamlVennDiagramConfig 中,运行时合并逻辑见 vennDB.ts。各配置项如下:

配置项 默认值 说明
width 800 Venn 图渲染宽度
height 450 Venn 图渲染高度
padding 8 布局内边距(渲染器布局调用 config?.padding ?? 15
useDebugLayout false 调试开关:为 true 时绘制紫色虚线"文本内半径参考圆"与青绿色"网格单元格"辅助框,便于排查文本节点排布问题

一种典型用法是配合前端初始化全局配置(也可通过 %%{init: {...}}%% 指令按图覆盖):

mermaid.initialize({
  venn: {
    width: 1000,
    height: 600,
    useDebugLayout: true, // 开发期打开,定位文本溢出
  },
});

此外,主题侧还提供 venn1~venn8 系列色板变量(圆填充用)、vennTitleTextColorvennSetTextColorvennTitleTextColor 等变量(渲染器引用见 vennRenderer.ts),在自定义主题或通过 %%{init: { 'themeVariables': {...} }}%% 时可直接覆盖这些颜色变量以改变默认配色。

无障碍与标题支持

Venn 图的数据层完整集成了 Mermaid 通用的无障碍与标题能力(见 vennDB.ts 暴露的 DB 接口):

  • setDiagramTitle / getDiagramTitle:图中 title 语句的文本会渲染为 SVG 顶部的居中标题文本;
  • setAccTitle / setAccDescription:支持无障碍标题与无障碍描述,配合 accTitle/accDescr 等指令为读屏工具提供语义化说明。

架构速览:从文本到圆圈的完整链路

如果希望对 Venn 图有源码级认知,可以顺着这条调用链阅读:

  1. 图类型探测vennDetector.ts 通过正则 /^\s*venn-beta/ 判断文本是否为 Venn 图,并懒加载对应模块。
  2. 语法解析parser/venn.jison 是 Jison 文法,负责把 set/union/text/style/title 语句转换为对 DB 的逐条调用;解析阶段即完成 union 标识符合法性校验。
  3. 数据层vennDB.tssubsetstextNodesstyleEntriesknownSets 四个内部结构保存集合/并集数据、文本节点、样式条目与已注册集合名,并实现"未定义即报错"的引用检查与默认尺寸计算。
  4. 渲染层vennRenderer.ts 交由 @upsetjs/venn.js 完成圆交叠布局,随后叠加主题色、ensurePairwiseSubsets 合成的二元子集、文本节点网格与 hand-drawn 支持(look: 'handDrawn' 时以 rough.js 绘制手绘风格圆形与交叉影线交集,见 vennRenderer.ts)。
  5. 测试佐证parser/venn.spec.ts 覆盖了基本解析、括号标签、引号标识符、尺寸后缀、缩进文本节点、样式多属性/rgb/rgba 以及多类错误分支;vennRenderer.spec.ts 则验证渲染产物的 SVG 结构(标题、圆、交叠区域标签与调试布局等)。

常见错误与排查

错误现象 根因与对策
unknown set identifier: ... union 引用了未在更早 set 行声明的集合;把所有涉及集合先 set 一遍即可。
union requires multiple identifiers union 后只跟了一个集合;至少传入两个集合名。
text requires set 出现了缩进的 text,但当前没有最近的 set/union 上下文;在 text 前先定义归属区域,或改为显式区域写法。
高元并集中心"空洞" 已由 ensurePairwiseSubsets 自动补齐两两交叠条目解决;若仍异常,检查是否为版本过旧(该特性 v11.12.3+ 引入)且以 venn-beta 开头。
文本节点重叠/溢出 临时打开 useDebugLayout: true 观察紫色安全圆与青色网格边界,据此调整尺寸与文本数量。
整图未渲染 确认文本以 venn-beta 开头(图类型探测正则硬性要求),且未混入其他图类型声明。

小结

Mermaid 的 Venn 图把"集合交叠关系"沉淀为一套高度表意的 DSL:set 定义集合、union 表达交叠、["..."] 管理显示名、:N 表达相对量级、缩进式 text 填充成员、style 完成精细化视觉定制。结合 v11.12.3+ 的 venn-beta 图类型,你可以在不引入任何外部工具的情况下,用纯文本在 Markdown、Mermaid Live Editor 或任意支持 Mermaid 渲染的平台上直接产出清晰的集合关系图。

更多实践素材可以参考仓库中的 docs/syntax/venn.md(本指南同源的官方文档)、图类型实现目录 packages/mermaid/src/diagrams/venn 以及图配置类型定义 config.type.ts 中的 VennDiagramConfig

登录后查看全文
热门项目推荐
相关项目推荐