Mermaid Treemap(矩形树图)语法与配置完整指南:从缩进层级到 D3 数值格式化
Treemap(矩形树图)是 Mermaid 内置的一种层次化数据可视化图,它把层级结构映射为一组嵌套矩形,每个分支对应一个矩形,再用更小的矩形在其内部“平铺”出子分支,矩形面积正比于其所代表的数值,适合在有限空间内比较同一层级的占比与大小。本文以仓库内 treemap 语法文档 为骨架,结合其解析器、数据库与渲染器的真实实现,完整讲解从语法编写、样式定制、主题与配置参数到值格式化、自动字号收缩与面积布局原理的全部细节。读完本文,你将能直接写出可运行的分层/扁平 Treemap 图,并精确控制配色、内边距、数值显示格式与适配缩放行为。
Treemap 是什么,适合展示什么
官方定义:Treemap 图把层次化数据展示为一组嵌套矩形。树中的每个分支由矩形表示,随后在该矩形内部用更小的矩形铺满表示其子分支。
packages/mermaid/src/diagrams/treemap/types.ts 中的数据模型也印证了这一结构:TreemapNode 同时具备 value(叶子数值)与 children(子节点数组),并带有用于类样式选择的 classSelector 与编译后的 cssCompiledStyles。
Treemap 尤其适用于:
- 可视化树状/层次化数据结构;
- 比较不同类别之间的占比关系(面积即比例);
- 在有限画布中展示大量层级数据;
- 快速识别层级数据中的模式与离群点。
仓库根目录 demos/treemap.html 就是可直接在浏览器中加载的运行示例,docs/syntax/ 下还维护了一份面向站点的同步文档 treemap.md,可作为验证语法与效果的第一手环境。
语法入门与基础结构
Treemap 图以 treemap-beta 关键字开头(解析器同样接受 treemap),随后以“缩进”表达父子关系。最简单的入门示例:
treemap-beta
"Section 1"
"Leaf 1.1": 12
"Section 1.2"
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20
"Leaf 2.2": 25
节点定义规则
节点可归纳为两种角色、三类写法:
- Section / 父节点:用带引号的文本定义,如
"Section Name",本身可有值也可无值,起分组与嵌套作用; - 带值的 Leaf 叶子节点:带引号文本后跟冒号和数值,如
"Leaf Name": value; - 层级:完全靠缩进建立——空格或制表符均可,同一节点的子节点缩进越深,层级越深(每层一级缩进即可,无需统一为固定空格数)。
需要注意,从语法的实际定义看(见下文 Langium 文法一节),叶子节点的数值分隔符既可以是冒号 : 也可以是逗号 ,,分隔符两侧允许有空格。缩进层级本身由顶层解析后转换为数字 level 记录,再在 parser.ts 中通过 buildHierarchy 把“扁平行数组”装配成嵌套树。
从三个完整示例快速上手
以下三个示例可直接复制到 demos/treemap.html 或任意 Mermaid 渲染器(Mermaid Live Editor、支持 Mermaid 的 Markdown 预览等)中运行。
基础 Treemap(单层分类对比)
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
这是最简单的“分类-明细”两层结构:Category A/B 是顶层 Section,每个 Item 是带值的叶子;矩形面积即随 Item 数值等比放大,肉眼即可比较 A、B 两个类别内部及之间的相对大小。
层次化 Treemap(多层嵌套)
treemap-beta
"Products"
"Electronics"
"Phones": 50
"Computers": 30
"Accessories": 20
"Clothing"
"Men's": 40
"Women's": 40
这里嵌套了三级:顶层 Products → 中层品类 → 底层商品明细。渲染器对每一层“分支节点”都会绘制带标题栏的区域(Section 头),从而把“分组→子分组→明细”的归属关系清晰地表达出来。
带样式(class)的 Treemap
treemap-beta
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12
classDef class1 fill:red,color:blue,stroke:#FFD600;
样式语法与 Mermaid 其他图类型一致:节点名后用 :::className 追加类名,文件末尾用 classDef className style1,style2; 声明类的视觉属性(本节中的 fill、color、stroke 均为 CSS 属性值)。Section 与 Leaf 节点都可以挂类,也可以把同一个类同时挂到多个节点上。
Styling 与 Configuration:样式定制
用 classDef 精细控制外观
classDef 是 Mermaid 多图共享的标准样式机制,Treemap 完整支持:
treemap-beta
"Main"
"A": 20
"B":::important
"B1": 10
"B2": 15
"C": 5
classDef important fill:#f96,stroke:#333,stroke-width:2px;
从实现看,TreeMapDB.addClass 会在 db.ts 中把 classDef 的样式字符串先做一次关键转换——用占位符保护 \,(转义逗号),然后把普通逗号 , 替换为 ; 再按 ; 拆分,逐个入列并区分 textStyles(文字类样式,如 color、font-size)与节点 styles(如 fill、stroke)。渲染阶段(renderer.ts)会调用 styles2String 把编译后的样式合并进对应矩形的 style 属性,并把 color: 改写为 fill: 以适配 SVG 文本着色。
主题配置
Treemap 的颜色体系全部走 Mermaid 主题变量,因此切换内置主题即可整体换肤。用文档头(frontmatter)配置主题是最直接的方式:
---
config:
theme: 'forest'
---
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
theme 的可选值与 Mermaid 全局一致(如 default、neutral、dark、forest 等)。从渲染器源码可以看到主题是如何参与配色的:颜色来自 themeVariables.cScale0~cScale11(Section 填充色)、cScalePeer0~cScalePeer11(描边色)与 cScaleLabel0~cScaleLabel11(文字色)三组有序色标,采用 scaleOrdinal 依名称映射到不同分块,从而让同层相邻区块自动分色。叶子节点遵循“继承最近父 Section 的颜色”规则(见渲染器中 d.parent ? colorScale(d.parent.data.name) : colorScale(d.data.name)),保证同一分组下的叶子观感一致。
外边距 diagramPadding
可通过 diagramPadding 调整整个图四周留白:
---
config:
treemap:
diagramPadding: 200
---
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
这里 diagramPadding 作用于整幅图的 viewport 留白(在渲染结尾由 setupViewPortForSVG(svg, diagramPadding, ...) 消费),与下文将介绍的内部 padding(节点间的内间距)作用域不同,注意区分。
配置参数全表与源码默认值
Treemap 图支持以下配置项(均需放在 config.treemap 命名空间下,或经 frontmatter 直接配置):
| Option | 说明 | 默认值 |
|---|---|---|
| useMaxWidth | 为 true 时图宽设为 100%,随容器可用宽度缩放 | true |
| padding | 节点(矩形块)之间的内部间距 | 10 |
| diagramPadding | 整幅图四周的外边距 | 8 |
| showValues | 是否在节点上显示数值 | true |
| nodeWidth | 节点宽度 | 100 |
| nodeHeight | 节点高度 | 40 |
| borderWidth | 边框宽度 | 1 |
| valueFontSize | 数值字号 | 12 |
| labelFontSize | 标签字号 | 14 |
| valueFormat | 数值显示格式,详见下文“值格式化” | ',' |
这些默认值并不是文档里凭空写的——defaultConfig.ts 中 treemap 段的默认值与上表完全一一对应,TreemapDB.getConfig() 使用 cleanAndMerge 将默认配置与用户传入的 config.treemap 做深合并后返回(合并实现见 db.ts)。配置接口 TreemapDiagramConfig 亦在 types.ts 中定义,参数类型均为数值或布尔/字符串。
上述表中部分参数在渲染器中还有“兜底常量”作为第二道防线,例如内部间距若未配置会落到 DEFAULT_INNER_PADDING = 10;Section 标题栏固定高度为 SECTION_HEADER_HEIGHT = 25,Section 区域四周的 SECTION_INNER_PADDING 默认也取 10。
渲染管线:从文本到嵌套矩形
了解语法与配置后,再看 Treemap 的实现链路会更有把握调优:
- 类型探测:加载入口 detector.ts 用正则
/^\s*treemap/判断文本块是否属于该图类型,命中后异步加载diagram.js,这也是 Treemap 作为可延迟加载图类型的体现。 - 语法解析:文本交给
@mermaid-js/parser包的 Langium 文法解析成 AST。文法文件在 treemap.langium,关键点包括:开始关键字 terminalTREEMAP_KEYWORD: 'treemap-beta' | 'treemap';节点名 terminalSTRING2支持双引号或单引号包裹的字符串;叶子行规则为name=STRING2 INDENTATION? (SEPARATOR|COMMA) INDENTATION? value=MyNumber (STYLE_SEPARATOR classSelector=ID2)?,即分隔符支持:与,;classDef与:::class分别由CLASS_DEF与STYLE_SEPARATORterminal 处理;缩进由INDENTATION(一或多个空格/制表符)捕获,%%注释、换行等作为隐藏 token 被忽略。文法头部注释也注明其由 mindmap 文法改造而来。 - 数据装配:parser.ts 先遍历 AST 提取
ClassDefStatement注册到类表,再把每行(含缩进层级、名称、值、类选择器)拍平为items,随后调用buildHierarchy依据缩进层级关系把它们组织成嵌套树,递归db.addNode入库;level === 0的顶层节点会同时登记为outerNodes与首个 root。 - 布局与绘制:renderer.ts 中,数据先经
hierarchy(root).sum(value).sort(降序)计算每个子树聚合值并按值降序排序,再交给 D3 的treemap()布局:size取画布宽高,paddingTop对含子节点的 Section 额外加上标题栏高度与内间距,paddingInner取配置的padding。随后分支节点(有 children 者)被画成带标题栏的 Section 块,叶子节点被画成填充矩形,最后统一叠加标题、标签与数值文本。 - 标题与可访问性:
title、accTitle、accDescr指令同样受支持(文法中的TitleAndAccessibilities规则),与 Mermaid 其他图一致。
Advanced:值格式化(valueFormat)
valueFormat 主要使用 D3 的格式说明符(d3-format)控制数字显示,并对常见货币格式做了额外的特殊兼容处理。渲染器中的格式化函数构造逻辑为:当 formatStr === '$0,0' 时走“美元符号 + 千分位”分支;以 $ 开头且含逗号时提取小数精度后拼接 D3 的 ',' + precision 格式;仅以 $ 开头则剥掉前缀再把余下部分交给 D3;否则全部按标准 D3 format() 处理;一旦 format() 抛错(非法格式串)会回退到默认千分位格式 ','。
常用格式速查:
,— 千分位分隔(默认);$— 加美元符号前缀;.1f— 保留 1 位小数;.1%— 以百分比显示并保留 1 位小数;$0,0— 美元符号 + 千分位;$.2f— 美元符号 + 2 位小数;$,.2f— 美元符号 + 千分位 + 2 位小数。
货币格式示例(适合预算类数据):
---
config:
treemap:
valueFormat: '$0,0'
---
treemap-beta
"Budget"
"Operations"
"Salaries": 700000
"Equipment": 200000
"Supplies": 100000
"Marketing"
"Advertising": 400000
"Events": 100000
百分比格式示例(适合市场份额类数据,值写小数即可):
---
config:
treemap:
valueFormat: '$.1%'
---
treemap-beta
"Market Share"
"Company A": 0.35
"Company B": 0.25
"Company C": 0.15
"Others": 0.25
面积、字号与标签的自动适配细节
Treemap 的矩形面积本身由 D3 布局依据数值自动分配,但文案是否完整可读还取决于单元格大小。源码对叶子文本的处理值得注意(这也是影响体验的隐藏逻辑):
- 当叶子数量超过 20(
leafNodes.length > 20)时判定为“复杂图”,标签/数值的基础字号与最小字号会整体下调(例如标签基础字号由 38px 降为 16px),反之使用更大字号,确保小格子里不互相遮挡; - 每个叶子都会创建
clipPath防止文字溢出; - 渲染后会对每个标签做动态字号收缩:先按可用宽度逐步减小字号直到放得下,再把“标签 + 数值”的预估组合高度与单元格高度比较,必要时继续缩减并同步缩放数值字号(数值字号默认取标签字号的 0.6 倍);
- 当单元格太小(可用宽/高低于阈值)或字号已缩到下限仍放不下时,标签与数值文本会被
display: none隐藏,保证图形本身不被挤坏; - 数值文本只有在标签可见时才会尝试绘制,其纵坐标动态定位在标签下方,并校验是否超出单元格底部(底部留 4px)。
因此当看到极小的格子“没有文字”时,通常不是数据缺失,而是自动适配机制的合理取舍。
典型使用场景
结合矩形面积编码的特性,Treemap 常见于以下五类数据:
- 财务数据:预算分配、市场份额、投资组合构成的可视化;
- 文件系统分析:按文件夹与文件展示磁盘占用分布;
- 人口统计:跨地区及子地区展示人口分布;
- 产品层级:展示产品品类及其销量规模;
- 组织结构:表示公司部门与团队人数规模。
从仓库自带的测试集也能看到官方对其应用形态的覆盖,例如 e2e/diagrams/treemap/ 下包含带样式的叶子、Section 边框描边、超长名称省略号、隐藏数值、大数值千分位格式化等回归用例,可作为进一步查阅“该特性到底长什么样”的实证素材。
局限与注意事项
- Treemap 最适合具有自然层级结构的数据,扁平无层级的数据表现力较弱;
- 极小数值对应的矩形会很难看清或放不下标签;
- 过深的多层层级难以在有限面积内表达清楚;
- Treemap 不适合展示含负值的数据(面积无法表达负数,布局与聚合逻辑会受影响)。
备选图型参考
若 Treemap 不贴合你的需求,可考虑 Mermaid 中的相近替代(相关文档均位于 docs/syntax):
- Pie Chart(饼图):无层级、仅做简单占比比较时更直观;
- Sunburst(旭日图):径向布局的层级数据(Mermaid 尚未正式发布);
- Sankey(桑基图):适合表达基于“流量/流向”的层级数据。
Notes:关于 beta 状态
Mermaid 官方在文档中明确提示,Treemap 是较新的图类型,语法可能在未来版本中演进。其实现设计目标是“上手简单但能力完整”,若在使用中发现语法或渲染问题,欢迎通过 Mermaid 的 issue 反馈。如果你想在自己的项目里即时体验,直接打开 demos/treemap.html 即可在浏览器中边改边看。
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