主题
容易误解的地方
把机制按章节拆开之后,最容易出问题的不是复杂算法,而是几个边界。下面这些点值得在设计 自定义形状和宿主时先看一遍。
1. 注册表不是一个默认全量的全局表
createRegistry() 从空表开始。想保留矩形、椭圆、路径和内置 marker,必须显式写:
ts
const registry = createRegistry({ base: builtinRegistry });漏掉 base 不会让所有东西立刻崩溃,但图会少掉内置形状或箭头,随后出现回落和诊断。
2. measure 和 render 可能各说各话
布局只看 measure,不会调用 render。如果 render 画出了超过盒子的内容,布局不知道, 父容器、连线、viewBox 都可能对不上。反过来,render 也不能通过改坐标修正布局。
一句话:大小和位置在 measure/layout 决定,render 只负责画。
3. 自定义边要自己处理标签
边注册项的 render 拿到 ctx.labelOut,但库不会自动替所有自定义边画标签。只在文档里写 label,却没有在边注册项里输出标签,标签就不会出现。
这是当前 API 最容易让人意外的一点。以后可以加一个明确的“自动标签”选项,但现在应把 标签当成边画法的一部分。
4. pins 是坐标,但它仍然是文档字段
设计上文档表达意图,而 pins 又确实是绝对坐标。它只服务于 explicit 引擎,其他引擎不会 自动消费它。看到 pins 时,把它理解成“显式布局的参数”,而不是每个节点都有的位置属性。
5. 注册同名 type 会直接覆盖
registerShape("card", a) 之后再注册 "card",后一个会替换前一个。注册表不认为这是错误, 也不会发诊断。组合多个来源时,最好在应用层维护一份自己的 type 清单。
6. 场景 key 不是调试信息
key 决定增量更新是否能复用旧零件。随手改名、用随机值或数组下标,会让宿主把正常修改当成 整棵子树重建。ctx.out.key 生成的 key 是契约的一部分,不只是给人看的标签。
值得继续改的地方
这些是写文档时暴露出来的 API 反思,不代表当前用法有错:
| 现象 | 可以考虑的方向 |
|---|---|
| 自定义边容易忘记画标签 | 给 EdgeSpec 增加显式的自动标签约定 |
| 同名 type 覆盖没有提示 | 注册时返回冲突诊断,或在开发模式下警告 |
| 空注册表与内置注册表差异大 | 提供更直白的 extendBuiltinRegistry() 入口 |
| schema 在 layout 和 build 各解析一次 | 抽出共享的归一化入口,并为自定义形状补检查器 |
这些改动只有在能保持“文档 → 几何 → 场景 → 介质”的边界时才值得做。否则只是把一个问题 藏到另一层。