Mermaid Venn 图完全指南:用 `venn-beta` 语法绘制集合关系图(v11.12.3+)
Venn 图用相互交叠的圆来表达集合之间的包含、相交与互斥关系。本指南以 Mermaid 仓库中 packages/mermaid/src/docs/syntax/venn.md 为骨架,结合 parser/venn.jison、vennDB.ts、vennRenderer.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"]
语法要点如下:
- 标识符规则:集合标识符既可以是裸词(如
A、Set_1),也可以是带引号的字符串(如"Foo Bar")。从语法解析器 parser/venn.jison 可以看到,标识符令牌(IDENTIFIER)匹配[A-Za-z_][A-Za-z0-9\-_]*,字符串令牌(STRING)匹配"[^"]*",二者都可用作标识符。 - 必须先定义后引用:
union中出现的每个集合名都必须在更早的set行中定义过。解析时 vennDB.ts 的validateUnionIdentifiers会把并集中未注册的名字过滤出来,直接抛出unknown set identifier: ...异常。 union至少需要两个集合:语法中只有两个以上标识符才能构成 union,否则抛出union requires multiple identifiers(见 venn.jison)。- 解析器在
%options case-insensitive模式下工作,因此关键字大小写不敏感。
用 ["..."] 括号标签让显示名与短标识分离
当你希望图中显示可读的名字(例如 Alpha、Team overlap),又想让标识符保持简短(例如 A),可以为 set、union 甚至 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 图中圆的相对大小由尺寸数字驱动。在 set 或 union 的标识符/标签之后追加 :数字 即可:
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:20、set B:12、union A,B:3会被分别解析为 size 20、12、3。
尺寸数字与视觉半径成正比,用于在集合较多时大致还原"哪个集合元素更多、交集占多大比重"的直觉关系。v11.x 目前并不保证像素级精确的几何缩放,更适合表达相对量级。
文本节点:在集合内部放置说明文字
text 用于在集合或并集内部放置标签,适合填充成员/要素清单。它有两种书写方式:
方式一:缩进式。缩进的 text 行会自动挂载到"最近"的一个 set 或 union 上。语法规则中的 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']的用例。 - 颜色取值宽泛:样式值支持十六进制颜色
#ff6b6b、rgb(...)与rgba(...)(词法规则HEXCOLOR/RGBCOLOR/RGBACOLOR见 venn.jison),也支持color:red这类命名色;带空格的复合值会被逐令牌拼接。解析测试对fill:rgb(255, 0, 128)与fill:rgba(255, 0, 128, 0.5)均有断言(venn.spec.ts)。 - 样式如何落到画布:渲染阶段 vennRenderer.ts 先把样式条目按键(排序后的目标集合串)合并为查找表;随后对每个圆形路径应用
fill、fill-opacity、stroke、stroke-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.yaml 的 VennDiagramConfig 中,运行时合并逻辑见 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 系列色板变量(圆填充用)、vennTitleTextColor、vennSetTextColor、vennTitleTextColor 等变量(渲染器引用见 vennRenderer.ts),在自定义主题或通过 %%{init: { 'themeVariables': {...} }}%% 时可直接覆盖这些颜色变量以改变默认配色。
无障碍与标题支持
Venn 图的数据层完整集成了 Mermaid 通用的无障碍与标题能力(见 vennDB.ts 暴露的 DB 接口):
setDiagramTitle/getDiagramTitle:图中title语句的文本会渲染为 SVG 顶部的居中标题文本;setAccTitle/setAccDescription:支持无障碍标题与无障碍描述,配合accTitle/accDescr等指令为读屏工具提供语义化说明。
架构速览:从文本到圆圈的完整链路
如果希望对 Venn 图有源码级认知,可以顺着这条调用链阅读:
- 图类型探测:vennDetector.ts 通过正则
/^\s*venn-beta/判断文本是否为 Venn 图,并懒加载对应模块。 - 语法解析:parser/venn.jison 是 Jison 文法,负责把
set/union/text/style/title语句转换为对 DB 的逐条调用;解析阶段即完成 union 标识符合法性校验。 - 数据层:vennDB.ts 用
subsets、textNodes、styleEntries、knownSets四个内部结构保存集合/并集数据、文本节点、样式条目与已注册集合名,并实现"未定义即报错"的引用检查与默认尺寸计算。 - 渲染层:vennRenderer.ts 交由
@upsetjs/venn.js完成圆交叠布局,随后叠加主题色、ensurePairwiseSubsets合成的二元子集、文本节点网格与 hand-drawn 支持(look: 'handDrawn'时以 rough.js 绘制手绘风格圆形与交叉影线交集,见 vennRenderer.ts)。 - 测试佐证: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。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00