D2 0.6.3 版本技术解析:主题自定义、特殊形状图标与关键缺陷修复
【免费下载链接】d2D2 is a modern diagram scripting language that turns text to diagrams.项目地址: https://gitcode.com/GitHub_Trending/d2/d2
本文基于 D2 仓库 v0.6.3 变更日志 展开。该版本为 D2(一款将文本描述转换为图表的现代图表脚本语言)带来了一项核心能力——通过
d2-config变量自定义或完全重制主题;同时为 sql_table、class、code、markdown、latex 等特殊形状补充了图标支持,并修复了导入覆盖、sketch 箭头、渲染目标判定、ELK/dagre 布局等五个关键缺陷。读完本文,你将掌握 D2 主题覆盖(theme overrides)的完整配置语法与底层实现原理,理解特殊形状图标的加载机制,并能针对这些修复点进行验证与升级评估。
版本总览
D2 0.6.3 变更日志给出的完整变更清单如下:
- Features:主题可通过
d2-config变量进行自定义(对应 PR #1777)。 - Improvements:可以为特殊对象(sql_table、class、code、markdown、latex)添加图标(对应 PR #1774)。
- Bugfixes:
- 修复导入文件时以数组覆盖已有值的问题(#1762)。
- 修复 sketch 标志开启时缺少未填充三角形箭头的问题(#1763)。
- 修复目标路径包含
index时渲染目标可能错误的问题(#1764)。 - 修复 ELK 布局下外部标签/图标的问题(#1776)。
- 修复 dagre 布局且 direction 为 right 时边可能断开的问题(#1778)。
其中,主题自定义是该版本最具分量的功能变更,它让用户不再局限于内置主题,而是可以在 D2 源文件中直接覆写主题色板。
通过 d2-config 自定义主题
d2-config 变量是什么
在 0.6.3 之前,D2 的主题只能通过命令行参数或内置主题 ID 选择;而 0.6.3 引入的d2-config是一个特殊的vars变量,允许你在 D2 脚本内部直接声明与主题相关的配置。它必须声明在根级vars中,这也是编译器强制校验的规则。
从源码校验逻辑(d2ir/compile.go 的validateConfigs)可以看到:
if NodeBoardKind(ParentMap(ParentMap(configs))) == "" { c.errorf(configs.LastRef().AST(), `"%s" can only appear at root vars`, configs.Name.ScalarString()) return }也就是说,d2-config只能出现在根级 vars,出现在其他层级会直接报错。校验函数还逐项检查了每个配置字段的类型:
switch f.Name.ScalarString() { case "sketch", "center": _, err := strconv.ParseBool(val) // 布尔值 case "theme-overrides", "dark-theme-overrides", "data": if f.Map() == nil { ... } // 必须为 map case "theme-id", "dark-theme-id": valInt, err := strconv.Atoi(val) // 整数,且必须在主题目录中有效 if d2themescatalog.Find(int64(valInt)) == (d2themes.Theme{}) { c.errorf(..., `%d is not a valid theme ID`, valInt) } case "pad": _, err := strconv.Atoi(val) // 整数 case "layout-engine": default: c.errorf(..., `"%s" is not a valid config`, ...) }d2-config 支持的完整配置项
结合 d2target/d2target.go 中的Config结构体,d2-config支持以下字段:
| 配置字段 | 类型 | 说明 |
|---|---|---|
sketch | 布尔 | 是否开启手绘草图风格 |
center | 布尔 | 是否居中渲染 |
theme-id | 整数 | 选择主题,值必须在主题目录中有效(见 d2themescatalog) |
dark-theme-id | 整数 | 深色模式主题 ID |
theme-overrides | map | 对主题颜色的覆盖(本版本核心) |
dark-theme-overrides | map | 深色模式下的主题颜色覆盖 |
data | map | 供插件使用的用户自定义数据 |
pad | 整数 | 画布内边距 |
layout-engine | 字符串 | 指定布局引擎 |
theme-overrides 的颜色键
覆盖的主题颜色通过一组语义化键声明,对应 d2target/d2target.go 的ThemeOverrides结构体与 d2themes/d2themes.go 中的Neutral、ColorPalette定义:
- N1–N7:中性色(文本、边框等基础色),N1 最深(如
#0A0F25),N7 最浅(如#FFFFFF); - B1–B6:基色,用于容器(container)填充与描边;
- AA2、AA4、AA5:备选色 A 系列;
- AB4、AB5:备选色 B 系列。
变更日志中“随机颜色码”的示例即指通过theme-overrides声明上述任一键的自定义十六进制颜色,例如:
vars: { d2-config: { theme-overrides: { B1: "#0D32B2" N1: "#111111" N2: "#676C7E" AA4: "#ED695E" AB4: "#0A0F25" } } } a -> b底层实现:ApplyOverrides 如何生效
覆盖不是概念性的,而是由 d2themes/d2themes.go 的Theme.ApplyOverrides方法逐键完成:
func (t *Theme) ApplyOverrides(overrides *d2target.ThemeOverrides) { if overrides == nil { return } if overrides.B1 != nil { t.Colors.B1 = *overrides.B1 } if overrides.B2 != nil { t.Colors.B2 = *overrides.B2 } // ... B3–B6、AA2、AA4、AA5、AB4、AB5 依此类推 if overrides.N1 != nil { t.Colors.Neutrals.N1 = *overrides.N1 } // ... N2–N7 依此类推 }每个字段都是指针类型,只有显式声明的键才会被覆盖,未声明的键保留主题默认值。这种设计意味着你既可以微调现有主题的个别颜色(只需声明想改的键),也可以完全重制一个主题(声明全部 18 个键),正如变更日志所说 "make your own and customize existing D2 themes"。
深色主题覆盖
dark-theme-overrides与theme-overrides结构完全相同(同为ThemeOverrides类型),仅作用于深色模式。这与dark-theme-id的设计对称,方便同一份脚本在明暗两种模式下呈现不同的品牌色。
为特殊形状添加图标
0.6.3 的改进项让sql_table、class、code、markdown、latex这些特殊形状支持了图标。图标通过每个形状的icon字段指定,指向图片 URL(典型如https://icons.terrastruct.com/...的图标库资源)。
从源码看,icon是编译器的标准字段之一:d2ir/compile.go 中icon、tooltip、link作为可通过过滤器重置的属性处理;而在 d2ir/compile.go 中,导入文件时会对其内部的图标链接做路径扩展处理:
if f.Name.ScalarString() == "icon" && f.Name.IsUnquoted() && f.Primary() != nil { // 扩展 icon 链接以反映新路径 }这保证了通过@import引入的子图(board)中的图标在新路径下仍能正确解析。e2e 测试基线(如 e2etests/testdata/stable/cycle-order/dagre/board.exp.json)中可以看到icons.terrastruct.com作为图标 Host 被记录,说明图标资源是随图导出的。
一个带图标的特殊形状示例:
class: Person { icon: https://icons.terrastruct.com/essentials%2F073-add.svg name: "Alice" }此外,模式解析测试 d2ir/pattern_test.go 验证了图标字段的级联与置空语义:子对象可以通过icon: null覆盖继承自父级的图标,这保证了"特殊形状图标"能力与 D2 既有的样式继承体系完全兼容。
五个关键缺陷修复详解
修复:导入文件时以数组覆盖已有值(#1762)
此前,当通过@import导入的文件中对某个已有字段赋数组值时,会引发错误或行为异常。本次修复让数组值的覆盖行为符合预期,与 d2ir/import.go 的导入合并逻辑联动,保证"后导入者覆盖先声明者"的语义在各种值类型(标量、数组、map)下保持一致。
修复:sketch 标志下缺少未填充三角形箭头(#1763)
开启sketch(手绘)风格后,未填充(空心)的三角形箭头会丢失。该修复补齐了 sketch 模式下 open/empty 三角形箭头的渲染路径,属于渲染层修复,涉及 d2scenebuild 与草图渲染 d2sketch 相关实现。
修复:目标路径包含 "index" 时渲染目标错误(#1764)
当输出目标路径(如文件名或目录名)恰好包含子串index时,渲染目标判定可能被误判为索引文件,导致输出位置错误。该修复调整了目标路径判定逻辑,避免字符串包含匹配带来的误判,属于 CLI 导出路径处理层修复(相关代码位于 d2cli/export.go)。
修复:ELK 布局下外部标签/图标(#1776)
ELK 布局引擎(d2layouts/d2elklayout)在处理带外部(outside)标签或图标的节点时可能出现布局异常。该修复修正了 ELK 布局对标签/图标附加对象(label、icon 等附属节点)的尺寸与位置计算,使outside标签与图标在 ELK 引擎下正常排布。
修复:dagre 布局 direction 为 right 时边断开(#1778)
dagre 布局引擎(d2layouts/d2dagrelayout)在direction: right(从左到右)方向下,某些边可能发生"断连"(edge 未正确连接到两端节点)。该修复校正了 dagre 输出在水平方向下边的端点映射,恢复边的连通性。
升级与验证
若你正在使用 D2 并考虑升级到 0.6.3 或以上版本:
- 主题能力:升级后即可在脚本根级
vars.d2-config中编写theme-overrides,无需任何命令行参数;注意d2-config必须位于根vars,否则编译报错。 - 图标功能:
sql_table、class、code、markdown、latex形状可直接设置icon字段,子对象可用icon: null取消继承。 - 验证方式:可在仓库根目录运行
go test ./d2ir/...与go test ./e2etests/...复现相关解析与端到端测试;针对主题覆盖,可构造含theme-overrides的最小 D2 脚本,配合d2 --theme检查输出 SVG 中对应颜色是否被替换。
从 Makefile 与 d2cli/main.go 可以看出,D2 以 Go 实现核心编译渲染管线,主题目录位于 d2themes/d2themescatalog,包含 default、dark_mauve、grape_soda 等内置主题——0.6.3 的theme-overrides正是在这套主题体系之上开放的定制入口,为团队品牌色、公司配色等场景提供了纯脚本化的解决方案。
【免费下载链接】d2D2 is a modern diagram scripting language that turns text to diagrams.项目地址: https://gitcode.com/GitHub_Trending/d2/d2
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考