@retikz/core 0.2.0-alpha.3 → 0.2.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/compile/compile.d.ts.map +1 -1
- package/dist/es/compile/compile.js +74 -12
- package/dist/es/compile/node.d.ts +4 -0
- package/dist/es/compile/node.d.ts.map +1 -1
- package/dist/es/compile/node.js +83 -32
- package/dist/es/compile/path/index.d.ts.map +1 -1
- package/dist/es/compile/path/index.js +91 -12
- package/dist/es/compile/path/relative.d.ts.map +1 -1
- package/dist/es/compile/path/relative.js +5 -1
- package/dist/es/geometry/arc.d.ts +11 -0
- package/dist/es/geometry/arc.d.ts.map +1 -1
- package/dist/es/geometry/arc.js +27 -1
- package/dist/es/geometry/rect.d.ts +23 -0
- package/dist/es/geometry/rect.d.ts.map +1 -1
- package/dist/es/geometry/rect.js +84 -1
- package/dist/es/geometry/segment.d.ts +2 -0
- package/dist/es/geometry/segment.d.ts.map +1 -1
- package/dist/es/geometry/segment.js +12 -1
- package/dist/es/index.d.ts +2 -2
- package/dist/es/index.d.ts.map +1 -1
- package/dist/es/index.js +2 -2
- package/dist/es/ir/node.d.ts +33 -4
- package/dist/es/ir/node.d.ts.map +1 -1
- package/dist/es/ir/node.js +9 -2
- package/dist/es/ir/path/path.d.ts +230 -5
- package/dist/es/ir/path/path.d.ts.map +1 -1
- package/dist/es/ir/path/path.js +1 -0
- package/dist/es/ir/path/step.d.ts +311 -8
- package/dist/es/ir/path/step.d.ts.map +1 -1
- package/dist/es/ir/path/step.js +36 -11
- package/dist/es/ir/scope.d.ts +348 -16
- package/dist/es/ir/scope.d.ts.map +1 -1
- package/dist/es/ir/scope.js +5 -2
- package/dist/lib/compile/compile.cjs +74 -12
- package/dist/lib/compile/compile.d.ts.map +1 -1
- package/dist/lib/compile/node.cjs +83 -32
- package/dist/lib/compile/node.d.ts +4 -0
- package/dist/lib/compile/node.d.ts.map +1 -1
- package/dist/lib/compile/path/index.cjs +89 -10
- package/dist/lib/compile/path/index.d.ts.map +1 -1
- package/dist/lib/compile/path/relative.cjs +5 -1
- package/dist/lib/compile/path/relative.d.ts.map +1 -1
- package/dist/lib/geometry/arc.cjs +28 -0
- package/dist/lib/geometry/arc.d.ts +11 -0
- package/dist/lib/geometry/arc.d.ts.map +1 -1
- package/dist/lib/geometry/rect.cjs +84 -0
- package/dist/lib/geometry/rect.d.ts +23 -0
- package/dist/lib/geometry/rect.d.ts.map +1 -1
- package/dist/lib/geometry/segment.cjs +12 -0
- package/dist/lib/geometry/segment.d.ts +2 -0
- package/dist/lib/geometry/segment.d.ts.map +1 -1
- package/dist/lib/index.cjs +1 -0
- package/dist/lib/index.d.ts +2 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/ir/node.cjs +9 -2
- package/dist/lib/ir/node.d.ts +33 -4
- package/dist/lib/ir/node.d.ts.map +1 -1
- package/dist/lib/ir/path/path.cjs +1 -0
- package/dist/lib/ir/path/path.d.ts +230 -5
- package/dist/lib/ir/path/path.d.ts.map +1 -1
- package/dist/lib/ir/path/step.cjs +36 -10
- package/dist/lib/ir/path/step.d.ts +311 -8
- package/dist/lib/ir/path/step.d.ts.map +1 -1
- package/dist/lib/ir/scope.cjs +5 -2
- package/dist/lib/ir/scope.d.ts +348 -16
- package/dist/lib/ir/scope.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/compile/compile.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAwC,MAAM,OAAO,CAAC;AACtE,OAAO,KAAK,EAAa,KAAK,EAA6B,MAAM,cAAc,CAAC;AAEhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAoBjD,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AA4CrE,uEAAuE;AACvE,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,IAAI,EACA,2BAA2B,GAC3B,gBAAgB,GAChB,0BAA0B,GAC1B,wBAAwB,GACxB,yBAAyB,GACzB,sBAAsB,GACtB,8BAA8B,GAC9B,oBAAoB,GACpB,mBAAmB,GACnB,yBAAyB,GACzB,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAClB,iBAAiB;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,2BAA2B;AAC3B,MAAM,MAAM,cAAc,GAAG;IAC3B,oCAAoC;IACpC,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3C;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC1C,CAAC;
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/compile/compile.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAwC,MAAM,OAAO,CAAC;AACtE,OAAO,KAAK,EAAa,KAAK,EAA6B,MAAM,cAAc,CAAC;AAEhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAoBjD,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AA4CrE,uEAAuE;AACvE,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,IAAI,EACA,2BAA2B,GAC3B,gBAAgB,GAChB,0BAA0B,GAC1B,wBAAwB,GACxB,yBAAyB,GACzB,sBAAsB,GACtB,8BAA8B,GAC9B,oBAAoB,GACpB,mBAAmB,GACnB,yBAAyB,GACzB,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAClB,iBAAiB;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,2BAA2B;AAC3B,MAAM,MAAM,cAAc,GAAG;IAC3B,oCAAoC;IACpC,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3C;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC1C,CAAC;AA6FF;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,IAAI,EAAE,EAAE,UAAS,cAAmB,KAAG,KA4RrE,CAAC"}
|
|
@@ -56,6 +56,18 @@ var defaultWarnDispatcher = (warning) => {
|
|
|
56
56
|
if (typeof process !== "undefined" && process.env.NODE_ENV === "production") return;
|
|
57
57
|
console.warn(`[retikz] ${warning.code} at ${warning.path}: ${warning.message}`);
|
|
58
58
|
};
|
|
59
|
+
var makePathPlaceholder = () => ({ type: "path-placeholder" });
|
|
60
|
+
/** 把内部 sink 收窄回公开 ScenePrimitive[]:占位已全部回填(compileToScene 末端 placeholderBalance 无条件校验兜底) */
|
|
61
|
+
var sealSink = (sink) => sink;
|
|
62
|
+
/** dev 诊断:递归找出残留占位的 index 路径,供末端无条件校验报错时定位 */
|
|
63
|
+
var collectPlaceholderLocators = (prims, prefix = "primitives") => {
|
|
64
|
+
const locators = [];
|
|
65
|
+
prims.forEach((prim, idx) => {
|
|
66
|
+
if (prim.type === "path-placeholder") locators.push(`${prefix}[${idx}]`);
|
|
67
|
+
else if (prim.type === "group") locators.push(...collectPlaceholderLocators(prim.children, `${prefix}[${idx}].children`));
|
|
68
|
+
});
|
|
69
|
+
return locators;
|
|
70
|
+
};
|
|
59
71
|
/** scope.transforms 解析失败时根据失败成因映射的 warn code */
|
|
60
72
|
var scopeTransformWarnCode = (scope) => {
|
|
61
73
|
for (const t of scope.transforms ?? []) {
|
|
@@ -98,11 +110,32 @@ var compileToScene = (ir, options = {}) => {
|
|
|
98
110
|
});
|
|
99
111
|
}
|
|
100
112
|
const primitives = [];
|
|
113
|
+
/** 已 push 但未回填的占位计数;compileToScene 返回前必须归零(无条件守 Scene 公开契约) */
|
|
114
|
+
let placeholderBalance = 0;
|
|
115
|
+
/**
|
|
116
|
+
* primitive → 显式 zIndex 旁路记录(缺省视为 0);sealSink 后按它稳定排序,不写进 primitive 本体(保 Scene 输出纯净)。
|
|
117
|
+
* key 只会是 real ScenePrimitive——占位 PathPlaceholder 永不进此 Map(占位即将被回填替换)。
|
|
118
|
+
*/
|
|
119
|
+
const zIndexOf = /* @__PURE__ */ new Map();
|
|
120
|
+
/**
|
|
121
|
+
* 按 zIndex 升序原地稳定排序:同 zIndex 保持原 IR 顺序(decorate-sort 带原始下标)。全 0 键 = 恒等。
|
|
122
|
+
* 仅在 sealSink(占位已回填、类型已收窄回 ScenePrimitive)之后调用。
|
|
123
|
+
*/
|
|
124
|
+
const stableSortByZIndex = (arr) => {
|
|
125
|
+
const decorated = arr.map((prim, index) => ({
|
|
126
|
+
prim,
|
|
127
|
+
index,
|
|
128
|
+
z: zIndexOf.get(prim) ?? 0
|
|
129
|
+
}));
|
|
130
|
+
decorated.sort((a, b) => a.z - b.z || a.index - b.index);
|
|
131
|
+
for (let i = 0; i < arr.length; i++) arr[i] = decorated[i].prim;
|
|
132
|
+
return arr;
|
|
133
|
+
};
|
|
101
134
|
const nameStack = new NameStack({ onDuplicate: (info) => onWarn(formatDuplicateWarning(info)) });
|
|
102
135
|
const allPoints = [];
|
|
103
136
|
/**
|
|
104
137
|
* 解析一批本层收集的 pending paths(lookup-only 阶段)
|
|
105
|
-
* @description path
|
|
138
|
+
* @description 两种落点:有 `slot`(scopeChain 为空)→ 原位 splice 回填该 path 在本层 sink 占的位(按引用定位免索引漂移),保住与同层 node 的 IR 声明序;无 `slot`(scopeChain 非空)→ hoist 到顶层 `primitives`,因端点已是全局坐标、进 transformed GroupPrim 会被 scope.transform 二次 apply。NameStack 切到 pass2 守门:path 解析中误调 register 抛 internal error;解析完切回 pass1 让上层 scope 子树继续 register 子节点。
|
|
106
139
|
* `item.scopeChain` 记录该 path 所属 scope 累积 transform 链——传给 emitPathPrimitive,
|
|
107
140
|
* 让 step.to 内的 polar/at/offset 字面量按"当前 scope 局部度量 + 末端 apply chain"投影回全局。
|
|
108
141
|
*/
|
|
@@ -116,10 +149,18 @@ var compileToScene = (ir, options = {}) => {
|
|
|
116
149
|
irPath: item.irPath,
|
|
117
150
|
scopeChain: item.scopeChain
|
|
118
151
|
});
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
152
|
+
if (item.slot) {
|
|
153
|
+
const idx = item.slot.sink.indexOf(item.slot.placeholder);
|
|
154
|
+
if (idx === -1) throw new Error("internal: path placeholder missing from its sink");
|
|
155
|
+
const real = result?.primitives ?? [];
|
|
156
|
+
item.slot.sink.splice(idx, 1, ...real);
|
|
157
|
+
if (item.zIndex !== void 0) for (const prim of real) zIndexOf.set(prim, item.zIndex);
|
|
158
|
+
placeholderBalance--;
|
|
159
|
+
} else if (result) for (const prim of result.primitives) {
|
|
160
|
+
primitives.push(prim);
|
|
161
|
+
if (item.zIndex !== void 0) zIndexOf.set(prim, item.zIndex);
|
|
122
162
|
}
|
|
163
|
+
if (result) for (const p of result.points) allPoints.push(p);
|
|
123
164
|
}
|
|
124
165
|
} finally {
|
|
125
166
|
nameStack.exitLookupPhase();
|
|
@@ -143,7 +184,10 @@ var compileToScene = (ir, options = {}) => {
|
|
|
143
184
|
const layout = layoutNode(resolveNodeStyle(child, styleStack), measureText, nameStack, nodeDistance, chain, resolveLabelDefault(styleStack), effectiveShapes);
|
|
144
185
|
const globalLayout = chain.length === 0 ? layout : projectLayoutToGlobal(layout, chain);
|
|
145
186
|
if (child.id) nameStack.register(child.id, globalLayout, `${locatorPrefix}children[${i}].node.id`);
|
|
146
|
-
for (const prim of emitNodePrimitives(layout, round))
|
|
187
|
+
for (const prim of emitNodePrimitives(layout, round)) {
|
|
188
|
+
sink.push(prim);
|
|
189
|
+
if (child.zIndex !== void 0) zIndexOf.set(prim, child.zIndex);
|
|
190
|
+
}
|
|
147
191
|
allPoints.push(rect.anchor(globalLayout.rect, "north-west"), rect.anchor(globalLayout.rect, "north-east"), rect.anchor(globalLayout.rect, "south-west"), rect.anchor(globalLayout.rect, "south-east"));
|
|
148
192
|
layoutsAccumulator.push(globalLayout);
|
|
149
193
|
} else if (child.type === "coordinate") {
|
|
@@ -196,22 +240,40 @@ var compileToScene = (ir, options = {}) => {
|
|
|
196
240
|
if (innerSink.length === 0 && !hasOwnTransforms && child.id === void 0) continue;
|
|
197
241
|
const group = {
|
|
198
242
|
type: "group",
|
|
199
|
-
children: innerSink
|
|
243
|
+
children: stableSortByZIndex(sealSink(innerSink))
|
|
200
244
|
};
|
|
201
245
|
if (hasOwnTransforms) group.transforms = [...ownTransforms];
|
|
202
246
|
sink.push(group);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
247
|
+
if (child.zIndex !== void 0) zIndexOf.set(group, child.zIndex);
|
|
248
|
+
} else {
|
|
249
|
+
const pending = {
|
|
250
|
+
path: resolveEffectivePath(child, styleStack),
|
|
251
|
+
irPath: `${locatorPrefix}children[${i}].path`,
|
|
252
|
+
scopeChain: chain,
|
|
253
|
+
zIndex: child.zIndex
|
|
254
|
+
};
|
|
255
|
+
if (chain.length === 0) {
|
|
256
|
+
const placeholder = makePathPlaceholder();
|
|
257
|
+
sink.push(placeholder);
|
|
258
|
+
pending.slot = {
|
|
259
|
+
sink,
|
|
260
|
+
placeholder
|
|
261
|
+
};
|
|
262
|
+
placeholderBalance++;
|
|
263
|
+
}
|
|
264
|
+
pathsAccumulator.push(pending);
|
|
265
|
+
}
|
|
208
266
|
}
|
|
209
267
|
};
|
|
210
268
|
const rootPaths = [];
|
|
211
269
|
processChildren(ir.children, [], primitives, "", [], rootPaths, []);
|
|
212
270
|
resolvePendingPaths(rootPaths);
|
|
271
|
+
if (placeholderBalance !== 0) {
|
|
272
|
+
const detail = typeof process !== "undefined" && process.env.NODE_ENV !== "production" ? ` at ${collectPlaceholderLocators(primitives).join(", ")}` : "";
|
|
273
|
+
throw new Error(`internal: ${placeholderBalance} unresolved path placeholder(s) leaked into Scene output${detail}`);
|
|
274
|
+
}
|
|
213
275
|
return {
|
|
214
|
-
primitives,
|
|
276
|
+
primitives: stableSortByZIndex(sealSink(primitives)),
|
|
215
277
|
layout: computeLayout(allPoints, layoutPadding, round)
|
|
216
278
|
};
|
|
217
279
|
};
|
|
@@ -79,6 +79,10 @@ export type NodeLabelLayout = {
|
|
|
79
79
|
fontFamily?: string;
|
|
80
80
|
fontWeight?: string | number;
|
|
81
81
|
fontStyle?: 'normal' | 'italic' | 'oblique';
|
|
82
|
+
/** label 文本自旋模式(none / radial / tangent / 数字角度);缺省 = 不旋转 */
|
|
83
|
+
rotate?: 'none' | 'radial' | 'tangent' | number;
|
|
84
|
+
/** 自旋后若文字倒置则翻 180°;缺省 false */
|
|
85
|
+
keepUpright?: boolean;
|
|
82
86
|
};
|
|
83
87
|
/**
|
|
84
88
|
* 取节点 shape 在 toward 方向的附着点(path 端点贴边用)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAc,MAAM,EAAe,MAAM,OAAO,CAAC;AAC1F,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAc,MAAM,EAAe,MAAM,OAAO,CAAC;AAC1F,OAAO,KAAK,EAAa,cAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEnF,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,WAAW,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA+BnD,MAAM,MAAM,UAAU,GAAG;IACvB,qBAAqB;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,QAAQ,EAAE,eAAe,CAAC;IAC1B;;;OAGG;IACH,IAAI,EAAE,IAAI,CAAC;IACX,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAClC,iBAAiB;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS;IACT,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,SAAS;IACT,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC5C,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5B,sCAAsC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;CACjC,CAAC;AAEF,4CAA4C;AAC5C,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,QAAQ,EAAE,WAAW,GAAG,MAAM,CAAC;IAC/B,aAAa;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC5C,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;IAChD,+BAA+B;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAQF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,UAAU,EAAE,QAAQ,QAAQ,KAAG,QACS,CAAC;AAEjF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,UAAU,EAAE,MAAM,MAAM,KAAG,QAM3D,CAAC;AAmEF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,UAAU,EAAE,UAAU,MAAM,KAAG,QActE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EACZ,aAAa,YAAY,EACzB,WAAW,SAAS,EACpB,eAAe,MAAM,EACrB,aAAY,aAAa,CAAC,SAAS,CAAM,EACzC,eAAe,cAAc,EAC7B,SAAQ,MAAM,CAAC,MAAM,EAAE,eAAe,CAAkB,KACvD,UA6JF,CAAC;AAcF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,UAAU,EAClB,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,KAC3B,KAAK,CAAC,cAAc,CAiFtB,CAAC"}
|
package/dist/es/compile/node.js
CHANGED
|
@@ -78,19 +78,51 @@ var LABEL_DIRECTION_MAP = {
|
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
80
|
/**
|
|
81
|
-
* 算 label
|
|
82
|
-
* @description 8 方向:节点对应 anchor 出发按单位向量 × distance 外推;数字角度:先取 angleBoundary 边界点再沿 (cos,sin) × distance
|
|
81
|
+
* 算 label 中心点(节点局部坐标系,未旋转)
|
|
82
|
+
* @description 8 方向:节点对应 anchor 出发按单位向量 × distance 外推;数字角度:先取 angleBoundary 边界点再沿 (cos,sin) × distance 外推。
|
|
83
|
+
* 两个分支都在 **axis-aligned rect(rotate=0)** 上算——node 自身 rotate 由外层 GroupPrim 统一施加;
|
|
84
|
+
* 若用带 rotate 的 rect,label 位置会被 anchorOf / angleBoundaryOf 旋转一次、再被外层 group 旋转一次(双重旋转)。
|
|
85
|
+
* anchorOf / angleBoundaryOf 本身不改(path anchor `'A.north'` / `'A.30'` 仍需带 rotate 的 rect)。
|
|
83
86
|
*/
|
|
84
87
|
var labelCenter = (layout, label) => {
|
|
88
|
+
const aaLayout = {
|
|
89
|
+
...layout,
|
|
90
|
+
rect: {
|
|
91
|
+
...layout.rect,
|
|
92
|
+
rotate: 0
|
|
93
|
+
}
|
|
94
|
+
};
|
|
85
95
|
if (typeof label.position === "number") {
|
|
86
96
|
const rad = label.position * Math.PI / 180;
|
|
87
|
-
const [bx, by] = angleBoundaryOf(
|
|
97
|
+
const [bx, by] = angleBoundaryOf(aaLayout, label.position);
|
|
88
98
|
return [bx + Math.cos(rad) * label.distance, by + Math.sin(rad) * label.distance];
|
|
89
99
|
}
|
|
90
100
|
const { anchor, vec } = LABEL_DIRECTION_MAP[label.position];
|
|
91
|
-
const [bx, by] = anchorOf(
|
|
101
|
+
const [bx, by] = anchorOf(aaLayout, anchor);
|
|
92
102
|
return [bx + vec[0] * label.distance, by + vec[1] * label.distance];
|
|
93
103
|
};
|
|
104
|
+
/** 角度换算常量(弧度 → 度) */
|
|
105
|
+
var RAD_TO_DEG = 180 / Math.PI;
|
|
106
|
+
/**
|
|
107
|
+
* 算 label 文本自旋角度(度,屏幕 y-down,节点局部系)
|
|
108
|
+
* @description radial = atan2(label中心 − node中心);tangent = radial + 90;number = 原值;none / 缺省 = 0。
|
|
109
|
+
* keepUpright 时把"偏离正立 > 90°"的角度翻 180° 保阅读方向。方向向量在局部坐标算,node 自身 rotate 由外层 group 叠加。
|
|
110
|
+
*/
|
|
111
|
+
var resolveLabelRotateDeg = (label, lx, ly, cx, cy) => {
|
|
112
|
+
const mode = label.rotate;
|
|
113
|
+
if (mode === void 0 || mode === "none") return 0;
|
|
114
|
+
let deg;
|
|
115
|
+
if (typeof mode === "number") deg = mode;
|
|
116
|
+
else {
|
|
117
|
+
const radial = Math.atan2(ly - cy, lx - cx) * RAD_TO_DEG;
|
|
118
|
+
deg = mode === "tangent" ? radial + 90 : radial;
|
|
119
|
+
}
|
|
120
|
+
if (label.keepUpright) {
|
|
121
|
+
const norm = (deg % 360 + 360) % 360;
|
|
122
|
+
if (norm > 90 && norm < 270) deg += 180;
|
|
123
|
+
}
|
|
124
|
+
return deg;
|
|
125
|
+
};
|
|
94
126
|
/**
|
|
95
127
|
* 取节点 shape 在指定角度方向的边界点
|
|
96
128
|
* @description 角度是节点**局部坐标系**下的极角(度数:0°=局部 +x,90°=局部 +y)。layout.rect.rotate 把局部基绕中心旋转,得到世界系下的视觉方向;shape boundaryPoint 内部用 rotate-aware 投影,所以这里把局部 (cos, sin) 经 rect.rotate 旋转后加到中心当作世界系 toward 传入。不应用 margin(同 anchorOf);用于 `'A.30'` 落点
|
|
@@ -177,7 +209,9 @@ var layoutNode = (node, measureText, nameStack, nodeDistance, scopeChain = [], l
|
|
|
177
209
|
fontSize: (labFont?.size ?? labelDefault?.font?.size ?? baseFontSize) * fontScale,
|
|
178
210
|
fontFamily: labFont?.family ?? labelDefault?.font?.family ?? fontFamily,
|
|
179
211
|
fontWeight: labFont?.weight ?? labelDefault?.font?.weight ?? fontWeight,
|
|
180
|
-
fontStyle: labFont?.style ?? labelDefault?.font?.style ?? fontStyle
|
|
212
|
+
fontStyle: labFont?.style ?? labelDefault?.font?.style ?? fontStyle,
|
|
213
|
+
rotate: lab.rotate,
|
|
214
|
+
keepUpright: lab.keepUpright
|
|
181
215
|
};
|
|
182
216
|
});
|
|
183
217
|
return {
|
|
@@ -257,37 +291,54 @@ var emitNodePrimitives = (layout, round) => {
|
|
|
257
291
|
measuredHeight: round(layout.textHeight)
|
|
258
292
|
});
|
|
259
293
|
}
|
|
260
|
-
if (layout.labels)
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
294
|
+
if (layout.labels) {
|
|
295
|
+
const cx = layout.rect.x;
|
|
296
|
+
const cy = layout.rect.y;
|
|
297
|
+
for (const lab of layout.labels) {
|
|
298
|
+
const [lx, ly] = labelCenter(layout, lab);
|
|
299
|
+
const textPrim = {
|
|
300
|
+
type: "text",
|
|
301
|
+
x: round(lx),
|
|
302
|
+
y: round(ly),
|
|
303
|
+
lines: [{ text: lab.text }],
|
|
304
|
+
fontSize: lab.fontSize,
|
|
305
|
+
fontFamily: lab.fontFamily,
|
|
306
|
+
fontWeight: lab.fontWeight,
|
|
307
|
+
fontStyle: lab.fontStyle,
|
|
308
|
+
align: "middle",
|
|
309
|
+
baseline: "middle",
|
|
310
|
+
lineHeight: round(lab.fontSize * DEFAULT_LINE_HEIGHT_FACTOR),
|
|
311
|
+
fill: lab.textColor ?? "currentColor",
|
|
312
|
+
opacity: lab.opacity ?? layout.opacity,
|
|
313
|
+
measuredWidth: 0,
|
|
314
|
+
measuredHeight: round(lab.fontSize)
|
|
315
|
+
};
|
|
316
|
+
const deg = resolveLabelRotateDeg(lab, lx, ly, cx, cy);
|
|
317
|
+
if (deg === 0) inner.push(textPrim);
|
|
318
|
+
else inner.push({
|
|
319
|
+
type: "group",
|
|
320
|
+
transforms: [{
|
|
321
|
+
kind: "rotate",
|
|
322
|
+
degrees: round(deg),
|
|
323
|
+
cx: round(lx),
|
|
324
|
+
cy: round(ly)
|
|
325
|
+
}],
|
|
326
|
+
children: [textPrim]
|
|
327
|
+
});
|
|
328
|
+
}
|
|
279
329
|
}
|
|
280
|
-
if (layout.rotateDeg
|
|
281
|
-
|
|
330
|
+
if (!(layout.rotateDeg !== 0 || layout.lines !== void 0)) return inner;
|
|
331
|
+
const group = {
|
|
282
332
|
type: "group",
|
|
283
|
-
transforms: [{
|
|
284
|
-
kind: "rotate",
|
|
285
|
-
degrees: round(layout.rotateDeg),
|
|
286
|
-
cx: round(layout.rect.x),
|
|
287
|
-
cy: round(layout.rect.y)
|
|
288
|
-
}],
|
|
289
333
|
children: inner
|
|
334
|
+
};
|
|
335
|
+
if (layout.rotateDeg !== 0) group.transforms = [{
|
|
336
|
+
kind: "rotate",
|
|
337
|
+
degrees: round(layout.rotateDeg),
|
|
338
|
+
cx: round(layout.rect.x),
|
|
339
|
+
cy: round(layout.rect.y)
|
|
290
340
|
}];
|
|
341
|
+
return [group];
|
|
291
342
|
};
|
|
292
343
|
//#endregion
|
|
293
344
|
export { anchorOf, angleBoundaryOf, boundaryPointOf, emitNodePrimitives, layoutNode };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/index.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACV,MAAM,EACN,UAAU,EAGX,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAEV,cAAc,EACd,SAAS,EACV,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,iBAAiB,CAAC;AA8BtE,mCAAmC;AACnC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iCAAiC;IACjC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,KAAK,IAAI,CAAC;IACX,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;CACvC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,WAAW,SAAS,EACpB,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAC5B,cAAa,YAA+B,EAC5C,WAAU,gBAAqB,KAC9B;IAAE,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;CAAE,GAAG,IA8gBrE,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { rectOutline } from "../../geometry/rect.js";
|
|
2
|
+
import { arcBoundingPoints, arcEndPoint, ellipseArcBoundingPoints, ellipseArcPoint } from "../../geometry/arc.js";
|
|
2
3
|
import { bendControlPoints } from "../../geometry/bend.js";
|
|
3
|
-
import { arcSegmentSample, circleSegmentSample, cubicSegmentSample, ellipseSegmentSample, foldSegmentSample, lineSegmentSample, quadSegmentSample } from "../../geometry/segment.js";
|
|
4
|
+
import { arcSegmentSample, circleSegmentSample, cubicSegmentSample, ellipseArcSegmentSample, ellipseSegmentSample, foldSegmentSample, lineSegmentSample, quadSegmentSample } from "../../geometry/segment.js";
|
|
4
5
|
import { fallbackMeasurer } from "../text-metrics.js";
|
|
5
6
|
import { clipForTarget, cornerOf, refPointOfTarget, samePoint } from "./anchor.js";
|
|
6
7
|
import { emitLabelPrimitive, tForLabelPosition } from "./label.js";
|
|
@@ -51,7 +52,7 @@ var emitPathPrimitive = (path, nameStack, round, measureText = fallbackMeasurer,
|
|
|
51
52
|
labelPrims.push(r.primitive);
|
|
52
53
|
for (const p of r.points) points.push(p);
|
|
53
54
|
};
|
|
54
|
-
const hasTo = (s) => s.kind !== "cycle" && s.kind !== "arc" && s.kind !== "circlePath" && s.kind !== "ellipsePath";
|
|
55
|
+
const hasTo = (s) => s.kind !== "cycle" && s.kind !== "arc" && s.kind !== "circlePath" && s.kind !== "ellipsePath" && s.kind !== "rectangle";
|
|
55
56
|
const anchors = steps.map((s, idx) => {
|
|
56
57
|
if (!hasTo(s)) return null;
|
|
57
58
|
const ref = refPointOfTarget(s.to, nameStack, scopeChain);
|
|
@@ -168,6 +169,12 @@ var emitPathPrimitive = (path, nameStack, round, measureText = fallbackMeasurer,
|
|
|
168
169
|
if (samePoint(p, lastEnd)) return;
|
|
169
170
|
emitMove(p);
|
|
170
171
|
};
|
|
172
|
+
/** 部分圆/椭圆的闭合模式:'open' 直接返回;缺省 / 误给 'closed' 回退 'chord' */
|
|
173
|
+
const resolvePartialClosed = (closed, idx) => {
|
|
174
|
+
if (closed === "open") return "open";
|
|
175
|
+
if (closed === "closed") warn("PARTIAL_ARC_CLOSED_INVALID", "Partial circle/ellipse (with angles) cannot use closed:'closed'; falling back to 'chord'", `children[${idx}]`);
|
|
176
|
+
return "chord";
|
|
177
|
+
};
|
|
171
178
|
for (let i = 0; i < steps.length; i++) {
|
|
172
179
|
if (i > 0) {
|
|
173
180
|
const prevStep = steps[i - 1];
|
|
@@ -193,22 +200,80 @@ var emitPathPrimitive = (path, nameStack, round, measureText = fallbackMeasurer,
|
|
|
193
200
|
emitLine(toClip);
|
|
194
201
|
continue;
|
|
195
202
|
}
|
|
203
|
+
if (step.kind === "rectangle") {
|
|
204
|
+
const fromPt = refPointOfTarget(step.from, nameStack, scopeChain);
|
|
205
|
+
const toPt = refPointOfTarget(step.to, nameStack, scopeChain);
|
|
206
|
+
if (!fromPt || !toPt) {
|
|
207
|
+
if (!fromPt && typeof step.from === "string") warn("UNRESOLVED_NODE_REFERENCE", `Rectangle from references undefined node id '${step.from}'; the entire path is skipped`, `children[${i}].from`);
|
|
208
|
+
if (!toPt && typeof step.to === "string") warn("UNRESOLVED_NODE_REFERENCE", `Rectangle to references undefined node id '${step.to}'; the entire path is skipped`, `children[${i}].to`);
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
let rectStart = null;
|
|
212
|
+
for (const op of rectOutline(fromPt, toPt, step.roundedCorners)) if (op.kind === "move") {
|
|
213
|
+
emitMove(op.to);
|
|
214
|
+
rectStart = op.to;
|
|
215
|
+
} else if (op.kind === "line") emitLine(op.to);
|
|
216
|
+
else if (op.kind === "arc") emitArc(op.center, op.radius, op.startAngle, op.endAngle);
|
|
217
|
+
else emitClose();
|
|
218
|
+
const rx0 = Math.min(fromPt[0], toPt[0]);
|
|
219
|
+
const rx1 = Math.max(fromPt[0], toPt[0]);
|
|
220
|
+
const ry0 = Math.min(fromPt[1], toPt[1]);
|
|
221
|
+
const ry1 = Math.max(fromPt[1], toPt[1]);
|
|
222
|
+
points.push([rx0, ry0], [rx1, ry0], [rx1, ry1], [rx0, ry1]);
|
|
223
|
+
if (rectStart) penOverride = rectStart;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
196
226
|
const prev = findPrev();
|
|
197
227
|
if (!prev) return null;
|
|
198
228
|
if (step.kind === "arc") {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
229
|
+
let center;
|
|
230
|
+
if (step.center !== void 0) {
|
|
231
|
+
const c = refPointOfTarget(step.center, nameStack, scopeChain);
|
|
232
|
+
if (!c) {
|
|
233
|
+
if (typeof step.center === "string") warn("UNRESOLVED_NODE_REFERENCE", `Arc step center references undefined node id '${step.center}'; the entire path is skipped`, `children[${i}].center`);
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
center = c;
|
|
237
|
+
} else center = prev.anchor;
|
|
238
|
+
if (step.radiusX !== void 0 && step.radiusY !== void 0) {
|
|
239
|
+
const rx = step.radiusX;
|
|
240
|
+
const ry = step.radiusY;
|
|
241
|
+
startSegment(ellipseArcPoint(center, rx, ry, step.startAngle));
|
|
242
|
+
emitEllipseArc(center, rx, ry, step.startAngle, step.endAngle);
|
|
243
|
+
for (const p of ellipseArcBoundingPoints(center, rx, ry, step.startAngle, step.endAngle)) points.push(p);
|
|
244
|
+
collectLabel(step, (t) => ellipseArcSegmentSample(center, rx, ry, step.startAngle, step.endAngle, t));
|
|
245
|
+
penOverride = ellipseArcPoint(center, rx, ry, step.endAngle);
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (step.radius !== void 0) {
|
|
249
|
+
const r = step.radius;
|
|
250
|
+
startSegment(arcEndPoint(center, r, step.startAngle));
|
|
251
|
+
emitArc(center, r, step.startAngle, step.endAngle);
|
|
252
|
+
for (const p of arcBoundingPoints(center, r, step.startAngle, step.endAngle)) points.push(p);
|
|
253
|
+
collectLabel(step, (t) => arcSegmentSample(center, r, step.startAngle, step.endAngle, t));
|
|
254
|
+
penOverride = arcEndPoint(center, r, step.endAngle);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
warn("ARC_MISSING_RADIUS", "Arc step requires radius (circular) or both radiusX and radiusY (elliptical); the entire path is skipped", `children[${i}]`);
|
|
258
|
+
return null;
|
|
208
259
|
}
|
|
209
260
|
if (step.kind === "circlePath") {
|
|
210
261
|
const center = prev.anchor;
|
|
211
262
|
const r = step.radius;
|
|
263
|
+
if (step.startAngle !== void 0 && step.endAngle !== void 0) {
|
|
264
|
+
const startA = step.startAngle;
|
|
265
|
+
const endA = step.endAngle;
|
|
266
|
+
startSegment(ellipseArcPoint(center, r, r, startA));
|
|
267
|
+
emitEllipseArc(center, r, r, startA, endA);
|
|
268
|
+
for (const p of ellipseArcBoundingPoints(center, r, r, startA, endA)) points.push(p);
|
|
269
|
+
collectLabel(step, (t) => ellipseArcSegmentSample(center, r, r, startA, endA, t));
|
|
270
|
+
if (resolvePartialClosed(step.closed, i) === "chord") {
|
|
271
|
+
emitClose();
|
|
272
|
+
penOverride = ellipseArcPoint(center, r, r, startA);
|
|
273
|
+
} else penOverride = ellipseArcPoint(center, r, r, endA);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (step.startAngle !== void 0 || step.endAngle !== void 0) warn("PARTIAL_ARC_NEEDS_BOTH_ANGLES", "circlePath needs both startAngle and endAngle for a partial circle; treated as a full circle", `children[${i}]`);
|
|
212
277
|
startSegment([center[0] + r, center[1]]);
|
|
213
278
|
emitEllipseArc(center, r, r, 0, 360);
|
|
214
279
|
points.push([center[0] + r, center[1]]);
|
|
@@ -223,6 +288,20 @@ var emitPathPrimitive = (path, nameStack, round, measureText = fallbackMeasurer,
|
|
|
223
288
|
const center = prev.anchor;
|
|
224
289
|
const rx = step.radiusX;
|
|
225
290
|
const ry = step.radiusY;
|
|
291
|
+
if (step.startAngle !== void 0 && step.endAngle !== void 0) {
|
|
292
|
+
const startA = step.startAngle;
|
|
293
|
+
const endA = step.endAngle;
|
|
294
|
+
startSegment(ellipseArcPoint(center, rx, ry, startA));
|
|
295
|
+
emitEllipseArc(center, rx, ry, startA, endA);
|
|
296
|
+
for (const p of ellipseArcBoundingPoints(center, rx, ry, startA, endA)) points.push(p);
|
|
297
|
+
collectLabel(step, (t) => ellipseArcSegmentSample(center, rx, ry, startA, endA, t));
|
|
298
|
+
if (resolvePartialClosed(step.closed, i) === "chord") {
|
|
299
|
+
emitClose();
|
|
300
|
+
penOverride = ellipseArcPoint(center, rx, ry, startA);
|
|
301
|
+
} else penOverride = ellipseArcPoint(center, rx, ry, endA);
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
if (step.startAngle !== void 0 || step.endAngle !== void 0) warn("PARTIAL_ARC_NEEDS_BOTH_ANGLES", "ellipsePath needs both startAngle and endAngle for a partial ellipse; treated as a full ellipse", `children[${i}]`);
|
|
226
305
|
startSegment([center[0] + rx, center[1]]);
|
|
227
306
|
emitEllipseArc(center, rx, ry, 0, 360);
|
|
228
307
|
points.push([center[0] + rx, center[1]]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relative.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/relative.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,MAAM,EAAY,MAAM,UAAU,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI/C;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GACnC,OAAO,aAAa,CAAC,MAAM,CAAC,EAC5B,WAAW,SAAS,EACpB,aAAY,aAAa,CAAC,SAAS,CAAM,KACxC,KAAK,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"relative.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/relative.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,MAAM,EAAY,MAAM,UAAU,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI/C;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GACnC,OAAO,aAAa,CAAC,MAAM,CAAC,EAC5B,WAAW,SAAS,EACpB,aAAY,aAAa,CAAC,SAAS,CAAM,KACxC,KAAK,CAAC,MAAM,CA6Ed,CAAC"}
|
|
@@ -25,7 +25,11 @@ var normalizeRelativeTargets = (steps, nameStack, scopeChain = []) => {
|
|
|
25
25
|
}
|
|
26
26
|
if (step.kind === "arc") {
|
|
27
27
|
out.push(step);
|
|
28
|
-
if (prevEnd) prevEnd = arcEndPoint(prevEnd, step.radius, step.endAngle);
|
|
28
|
+
if (prevEnd && step.radius !== void 0 && step.center === void 0) prevEnd = arcEndPoint(prevEnd, step.radius, step.endAngle);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (step.kind === "rectangle") {
|
|
32
|
+
out.push(step);
|
|
29
33
|
continue;
|
|
30
34
|
}
|
|
31
35
|
const original = step.to;
|
|
@@ -6,4 +6,15 @@ export declare const arcEndPoint: (center: Position, radius: number, angleDeg: n
|
|
|
6
6
|
* @description 弧投影到 x/y 轴的极值只可能在弧端点或圆周轴向四点出现。endAngle < startAngle 时按 min..max 扫描;跨 360°(270→450)按数值区间正确处理;不去重——端角恰在 90°·k 上时调用方处理
|
|
7
7
|
*/
|
|
8
8
|
export declare const arcBoundingPoints: (center: Position, radius: number, startAngleDeg: number, endAngleDeg: number) => Array<Position>;
|
|
9
|
+
/**
|
|
10
|
+
* 椭圆弧参数点:中心 + 半轴 rx/ry + 参数角(度)→ 椭圆周上点
|
|
11
|
+
* @description 与 arcEndPoint 同角度约定(SVG y-down);endpoint = [cx + rx·cosθ, cy + ry·sinθ]。
|
|
12
|
+
* θ 是参数角(非真实极角,rx≠ry 时两者不等)
|
|
13
|
+
*/
|
|
14
|
+
export declare const ellipseArcPoint: (center: Position, radiusX: number, radiusY: number, angleDeg: number) => Position;
|
|
15
|
+
/**
|
|
16
|
+
* 椭圆弧 bbox 极值候选:起点、终点,加 [start,end] 区间内所有 90°·k 参数角处的椭圆周点
|
|
17
|
+
* @description 轴对齐椭圆的 x 极值在 θ=0/180、y 极值在 θ=90/270,与正圆同结构(仅半轴用 rx/ry)
|
|
18
|
+
*/
|
|
19
|
+
export declare const ellipseArcBoundingPoints: (center: Position, radiusX: number, radiusY: number, startAngleDeg: number, endAngleDeg: number) => Array<Position>;
|
|
9
20
|
//# sourceMappingURL=arc.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arc.d.ts","sourceRoot":"","sources":["../../../src/geometry/arc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAWxC,iDAAiD;AACjD,eAAO,MAAM,WAAW,GACtB,QAAQ,QAAQ,EAChB,QAAQ,MAAM,EACd,UAAU,MAAM,KACf,QAMF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,QAAQ,EAChB,QAAQ,MAAM,EACd,eAAe,MAAM,EACrB,aAAa,MAAM,KAClB,KAAK,CAAC,QAAQ,CAiBhB,CAAC"}
|
|
1
|
+
{"version":3,"file":"arc.d.ts","sourceRoot":"","sources":["../../../src/geometry/arc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAWxC,iDAAiD;AACjD,eAAO,MAAM,WAAW,GACtB,QAAQ,QAAQ,EAChB,QAAQ,MAAM,EACd,UAAU,MAAM,KACf,QAMF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,QAAQ,EAChB,QAAQ,MAAM,EACd,eAAe,MAAM,EACrB,aAAa,MAAM,KAClB,KAAK,CAAC,QAAQ,CAiBhB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC1B,QAAQ,QAAQ,EAChB,SAAS,MAAM,EACf,SAAS,MAAM,EACf,UAAU,MAAM,KACf,QAMF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GACnC,QAAQ,QAAQ,EAChB,SAAS,MAAM,EACf,SAAS,MAAM,EACf,eAAe,MAAM,EACrB,aAAa,MAAM,KAClB,KAAK,CAAC,QAAQ,CAehB,CAAC"}
|
package/dist/es/geometry/arc.js
CHANGED
|
@@ -22,5 +22,31 @@ var arcBoundingPoints = (center, radius, startAngleDeg, endAngleDeg) => {
|
|
|
22
22
|
}
|
|
23
23
|
return points;
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* 椭圆弧参数点:中心 + 半轴 rx/ry + 参数角(度)→ 椭圆周上点
|
|
27
|
+
* @description 与 arcEndPoint 同角度约定(SVG y-down);endpoint = [cx + rx·cosθ, cy + ry·sinθ]。
|
|
28
|
+
* θ 是参数角(非真实极角,rx≠ry 时两者不等)
|
|
29
|
+
*/
|
|
30
|
+
var ellipseArcPoint = (center, radiusX, radiusY, angleDeg) => {
|
|
31
|
+
const rad = angleDeg * DEG_TO_RAD;
|
|
32
|
+
return [center[0] + Math.cos(rad) * radiusX, center[1] + Math.sin(rad) * radiusY];
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* 椭圆弧 bbox 极值候选:起点、终点,加 [start,end] 区间内所有 90°·k 参数角处的椭圆周点
|
|
36
|
+
* @description 轴对齐椭圆的 x 极值在 θ=0/180、y 极值在 θ=90/270,与正圆同结构(仅半轴用 rx/ry)
|
|
37
|
+
*/
|
|
38
|
+
var ellipseArcBoundingPoints = (center, radiusX, radiusY, startAngleDeg, endAngleDeg) => {
|
|
39
|
+
const points = [ellipseArcPoint(center, radiusX, radiusY, startAngleDeg), ellipseArcPoint(center, radiusX, radiusY, endAngleDeg)];
|
|
40
|
+
const lo = Math.min(startAngleDeg, endAngleDeg);
|
|
41
|
+
const hi = Math.max(startAngleDeg, endAngleDeg);
|
|
42
|
+
const kStart = Math.ceil(lo / 90);
|
|
43
|
+
const kEnd = Math.floor(hi / 90);
|
|
44
|
+
for (let k = kStart; k <= kEnd; k++) {
|
|
45
|
+
const angle = k * 90;
|
|
46
|
+
if (angle === startAngleDeg || angle === endAngleDeg) continue;
|
|
47
|
+
points.push(ellipseArcPoint(center, radiusX, radiusY, angle));
|
|
48
|
+
}
|
|
49
|
+
return points;
|
|
50
|
+
};
|
|
25
51
|
//#endregion
|
|
26
|
-
export { arcBoundingPoints, arcEndPoint };
|
|
52
|
+
export { arcBoundingPoints, arcEndPoint, ellipseArcBoundingPoints, ellipseArcPoint };
|
|
@@ -32,4 +32,27 @@ export declare const rect: {
|
|
|
32
32
|
/** 从中心向 toward 方向射线与矩形边界交点(含旋转),Path 端点贴 Node 边界用 */
|
|
33
33
|
boundaryPoint: (r: Rect, toward: Position) => Position;
|
|
34
34
|
};
|
|
35
|
+
/** rectOutline 的命令算子(供 compile 翻译为 PathCommand;几何在 core 下沉,便于未来 rectangle node shape 复用) */
|
|
36
|
+
export type RectOutlineOp = {
|
|
37
|
+
kind: 'move';
|
|
38
|
+
to: Position;
|
|
39
|
+
} | {
|
|
40
|
+
kind: 'line';
|
|
41
|
+
to: Position;
|
|
42
|
+
} | {
|
|
43
|
+
kind: 'arc';
|
|
44
|
+
center: Position;
|
|
45
|
+
radius: number;
|
|
46
|
+
startAngle: number;
|
|
47
|
+
endAngle: number;
|
|
48
|
+
} | {
|
|
49
|
+
kind: 'close';
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* 矩形 outline:两对角 → 顺时针 path 算子序列
|
|
53
|
+
* @description from/to 任意顺序,归一化 (x0,y0)=min、(x1,y1)=max。直角 = 4 line + close(起点左上 (x0,y0));
|
|
54
|
+
* 圆角 = 4 line + 4 quarter-arc + close(起点 (x0+r, y0))。roundedCorners clamp 到 min(w,h)/2。
|
|
55
|
+
* 角度约定同 geometry/arc(y-down:0=+x, 90=+y/下, 180=-x, 270=-y/上)。
|
|
56
|
+
*/
|
|
57
|
+
export declare const rectOutline: (from: Position, to: Position, roundedCorners?: number) => Array<RectOutlineOp>;
|
|
35
58
|
//# sourceMappingURL=rect.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/geometry/rect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,gCAAgC;AAChC,MAAM,MAAM,IAAI,GAAG;IACjB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,YAAY;;;;;;;;;;CAUf,CAAC;AAEX,+BAA+B;AAC/B,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE1E,eAAO,MAAM,IAAI;IACf,WAAW;gBACC,IAAI,KAAG,QAAQ;IAC3B,uBAAuB;kBACT,IAAI,KAAK,QAAQ,KAAG,OAAO;IAMzC,sCAAsC;gBAC1B,IAAI,QAAQ,UAAU,KAAG,QAAQ;IAuC7C,qDAAqD;uBAClC,IAAI,UAAU,QAAQ,KAAG,QAAQ;CAUrD,CAAC"}
|
|
1
|
+
{"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/geometry/rect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,gCAAgC;AAChC,MAAM,MAAM,IAAI,GAAG;IACjB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,YAAY;;;;;;;;;;CAUf,CAAC;AAEX,+BAA+B;AAC/B,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE1E,eAAO,MAAM,IAAI;IACf,WAAW;gBACC,IAAI,KAAG,QAAQ;IAC3B,uBAAuB;kBACT,IAAI,KAAK,QAAQ,KAAG,OAAO;IAMzC,sCAAsC;gBAC1B,IAAI,QAAQ,UAAU,KAAG,QAAQ;IAuC7C,qDAAqD;uBAClC,IAAI,UAAU,QAAQ,KAAG,QAAQ;CAUrD,CAAC;AAEF,4FAA4F;AAC5F,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,QAAQ,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,QAAQ,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvF;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtB;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GACtB,MAAM,QAAQ,EACd,IAAI,QAAQ,EACZ,iBAAiB,MAAM,KACtB,KAAK,CAAC,aAAa,CAgCrB,CAAC"}
|