主题
layout · 几何
把 BoundDocument 变成盒子、端口落点、路由与标签落点。全库只有这一段产生最终坐标。
导出
measureDocument、placeDocument、attachEndpoints、routeEdges、layoutDocument, 以及内置引擎、路由和相关类型。
签名
ts
function measureDocument(bound: BoundDocument, options: MeasureOptions): Result<Measured>;
function placeDocument(bound: BoundDocument, measured: Measured, options?: PlaceOptions): Result<Placement>;
function placeDocumentAsync(bound: BoundDocument, measured: Measured, options?: PlaceOptions): Promise<Result<Placement>>;
function attachEndpoints(bound: BoundDocument, placement: Placement, options?: AttachOptions): Result<Attached>;
function routeEdges(bound: BoundDocument, attached: Attached, options?: RouteOptions): Result<LayoutResult>;
function layoutDocument(
input: DrawDocument | BoundDocument,
options: LayoutOptions,
): Result<LayoutResult>;
function layoutDocumentAsync(
input: DrawDocument | BoundDocument,
options: LayoutOptions,
): Promise<Result<LayoutResult>>;传入原始文档时,layoutDocument 会先调用 bindDocument;传入 BoundDocument 时复用已有结论。
四段
measure
产出 Measured:
- 每个节点的
Size; - 容器标题带高度;
- 节点与边标签的折行结果和尺寸。
标签的 maxWidth / overflow 在这里完成,build 只画已经量过的行。
place
把 Measured 交给 LayoutEngine。内置:
| 引擎 | 适合什么 |
|---|---|
layered | 有方向关系的图,默认引擎 |
grid | 网格铺开 |
explicit | pins 已给出位置 |
v2 引擎实现 layout(input): PlaceOutput | Promise<PlaceOutput>,输入是树形 PlaceNode[],可回传 ports 与 routes。同步入口遇到 Promise 返回 ENGINE_ASYNC; Pipeline 使用 runAsync,layout 使用 layoutDocumentAsync。
旧引擎仍可直接传入,或用 fromV1Engine(engine) 适配。
attach
把 port 声明变成 Attached.ports[portKey]:
ts
interface PortPlacement {
point: Point;
side: Side;
}fixed:side 与 offset 固定;side:side 固定,同侧槽位自动分配;free:先按对端方向选 side,再分配槽位。
同侧自动端口按对端位置排序,最小间距默认 12px;空间不足时发出 PORT_CROWDED。 Attached.anchors 是 v1 兼容视图,内容与 ports.point 相同。
route
给每条边产出 Route,并计算 LayoutResult.labels。
ts
interface Route {
start: Point;
end: Point;
bends: Point[];
routing?: "orthogonal" | "straight" | "spline";
}边标签优先放在最长折段中点;label.position 可以覆盖为路径比例。无法避开节点时发出 LABEL_COLLISION 警告。
LayoutResult
ts
interface LayoutResult {
boxes: Record<string, Rect>;
anchors: Record<string, Point>;
routes: Record<string, Route>;
labels: Record<string, LabelPlacement>;
/** 内容紧包围盒 */
extents: Rect;
/** 文档显式画布 */
camera?: Rect;
diagnostics: Diagnostic[];
}注入点
LayoutEngine:决定盒子位置;Router:决定折点;TextMeasurer:决定文字尺寸;LayoutOptions.registry:让原始文档在入口处完成 bind。
未注册类型的回落已经在 bind 完成,layout 不再重复发 UNKNOWN_*。