@retikz/core 0.1.0 → 0.2.0-alpha.2

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.
Files changed (117) hide show
  1. package/dist/es/compile/anchor-cache.d.ts +12 -0
  2. package/dist/es/compile/anchor-cache.d.ts.map +1 -0
  3. package/dist/es/compile/anchor-cache.js +41 -0
  4. package/dist/es/compile/compile.d.ts +2 -2
  5. package/dist/es/compile/compile.d.ts.map +1 -1
  6. package/dist/es/compile/compile.js +150 -40
  7. package/dist/es/compile/index.d.ts +1 -0
  8. package/dist/es/compile/index.d.ts.map +1 -1
  9. package/dist/es/compile/name-stack.d.ts +81 -0
  10. package/dist/es/compile/name-stack.d.ts.map +1 -0
  11. package/dist/es/compile/name-stack.js +104 -0
  12. package/dist/es/compile/node.d.ts +9 -5
  13. package/dist/es/compile/node.d.ts.map +1 -1
  14. package/dist/es/compile/node.js +19 -11
  15. package/dist/es/compile/path/anchor.d.ts +11 -5
  16. package/dist/es/compile/path/anchor.d.ts.map +1 -1
  17. package/dist/es/compile/path/anchor.js +24 -13
  18. package/dist/es/compile/path/index.d.ts +9 -3
  19. package/dist/es/compile/path/index.d.ts.map +1 -1
  20. package/dist/es/compile/path/index.js +18 -17
  21. package/dist/es/compile/path/label.d.ts +1 -1
  22. package/dist/es/compile/path/label.d.ts.map +1 -1
  23. package/dist/es/compile/path/label.js +17 -4
  24. package/dist/es/compile/path/relative.d.ts +10 -4
  25. package/dist/es/compile/path/relative.d.ts.map +1 -1
  26. package/dist/es/compile/path/relative.js +16 -8
  27. package/dist/es/compile/position.d.ts +19 -3
  28. package/dist/es/compile/position.d.ts.map +1 -1
  29. package/dist/es/compile/position.js +28 -8
  30. package/dist/es/compile/scope.d.ts +66 -0
  31. package/dist/es/compile/scope.d.ts.map +1 -0
  32. package/dist/es/compile/scope.js +256 -0
  33. package/dist/es/compile/style.d.ts +46 -0
  34. package/dist/es/compile/style.d.ts.map +1 -0
  35. package/dist/es/compile/style.js +259 -0
  36. package/dist/es/index.d.ts +2 -2
  37. package/dist/es/index.d.ts.map +1 -1
  38. package/dist/es/index.js +3 -1
  39. package/dist/es/ir/index.d.ts +2 -0
  40. package/dist/es/ir/index.d.ts.map +1 -1
  41. package/dist/es/ir/node.d.ts +5 -2
  42. package/dist/es/ir/node.d.ts.map +1 -1
  43. package/dist/es/ir/node.js +1 -0
  44. package/dist/es/ir/path/path.d.ts +531 -0
  45. package/dist/es/ir/path/path.d.ts.map +1 -1
  46. package/dist/es/ir/path/path.js +1 -0
  47. package/dist/es/ir/path/step.d.ts +834 -0
  48. package/dist/es/ir/path/step.d.ts.map +1 -1
  49. package/dist/es/ir/path/step.js +5 -1
  50. package/dist/es/ir/scene.d.ts +18 -3542
  51. package/dist/es/ir/scene.d.ts.map +1 -1
  52. package/dist/es/ir/scene.js +11 -3
  53. package/dist/es/ir/scope.d.ts +3690 -0
  54. package/dist/es/ir/scope.d.ts.map +1 -0
  55. package/dist/es/ir/scope.js +89 -0
  56. package/dist/es/ir/transform.d.ts +204 -0
  57. package/dist/es/ir/transform.d.ts.map +1 -0
  58. package/dist/es/ir/transform.js +56 -0
  59. package/dist/lib/compile/anchor-cache.cjs +41 -0
  60. package/dist/lib/compile/anchor-cache.d.ts +12 -0
  61. package/dist/lib/compile/anchor-cache.d.ts.map +1 -0
  62. package/dist/lib/compile/compile.cjs +150 -40
  63. package/dist/lib/compile/compile.d.ts +2 -2
  64. package/dist/lib/compile/compile.d.ts.map +1 -1
  65. package/dist/lib/compile/index.d.ts +1 -0
  66. package/dist/lib/compile/index.d.ts.map +1 -1
  67. package/dist/lib/compile/name-stack.cjs +104 -0
  68. package/dist/lib/compile/name-stack.d.ts +81 -0
  69. package/dist/lib/compile/name-stack.d.ts.map +1 -0
  70. package/dist/lib/compile/node.cjs +19 -11
  71. package/dist/lib/compile/node.d.ts +9 -5
  72. package/dist/lib/compile/node.d.ts.map +1 -1
  73. package/dist/lib/compile/path/anchor.cjs +23 -12
  74. package/dist/lib/compile/path/anchor.d.ts +11 -5
  75. package/dist/lib/compile/path/anchor.d.ts.map +1 -1
  76. package/dist/lib/compile/path/index.cjs +18 -17
  77. package/dist/lib/compile/path/index.d.ts +9 -3
  78. package/dist/lib/compile/path/index.d.ts.map +1 -1
  79. package/dist/lib/compile/path/label.cjs +17 -4
  80. package/dist/lib/compile/path/label.d.ts +1 -1
  81. package/dist/lib/compile/path/label.d.ts.map +1 -1
  82. package/dist/lib/compile/path/relative.cjs +16 -8
  83. package/dist/lib/compile/path/relative.d.ts +10 -4
  84. package/dist/lib/compile/path/relative.d.ts.map +1 -1
  85. package/dist/lib/compile/position.cjs +28 -8
  86. package/dist/lib/compile/position.d.ts +19 -3
  87. package/dist/lib/compile/position.d.ts.map +1 -1
  88. package/dist/lib/compile/scope.cjs +261 -0
  89. package/dist/lib/compile/scope.d.ts +66 -0
  90. package/dist/lib/compile/scope.d.ts.map +1 -0
  91. package/dist/lib/compile/style.cjs +262 -0
  92. package/dist/lib/compile/style.d.ts +46 -0
  93. package/dist/lib/compile/style.d.ts.map +1 -0
  94. package/dist/lib/index.cjs +8 -0
  95. package/dist/lib/index.d.ts +2 -2
  96. package/dist/lib/index.d.ts.map +1 -1
  97. package/dist/lib/ir/index.d.ts +2 -0
  98. package/dist/lib/ir/index.d.ts.map +1 -1
  99. package/dist/lib/ir/node.cjs +1 -0
  100. package/dist/lib/ir/node.d.ts +5 -2
  101. package/dist/lib/ir/node.d.ts.map +1 -1
  102. package/dist/lib/ir/path/path.cjs +1 -0
  103. package/dist/lib/ir/path/path.d.ts +531 -0
  104. package/dist/lib/ir/path/path.d.ts.map +1 -1
  105. package/dist/lib/ir/path/step.cjs +5 -1
  106. package/dist/lib/ir/path/step.d.ts +834 -0
  107. package/dist/lib/ir/path/step.d.ts.map +1 -1
  108. package/dist/lib/ir/scene.cjs +11 -3
  109. package/dist/lib/ir/scene.d.ts +18 -3542
  110. package/dist/lib/ir/scene.d.ts.map +1 -1
  111. package/dist/lib/ir/scope.cjs +94 -0
  112. package/dist/lib/ir/scope.d.ts +3690 -0
  113. package/dist/lib/ir/scope.d.ts.map +1 -0
  114. package/dist/lib/ir/transform.cjs +56 -0
  115. package/dist/lib/ir/transform.d.ts +204 -0
  116. package/dist/lib/ir/transform.d.ts.map +1 -0
  117. package/package.json +1 -1
@@ -0,0 +1,261 @@
1
+ const require_rect = require("../geometry/rect.cjs");
2
+ const require_position = require("./position.cjs");
3
+ //#region src/compile/scope.ts
4
+ /**
5
+ * 把 IR 6 变体 transforms 展平为 Scene 3 变体(Cartesian translate / rotate / scale)
6
+ * @description 4 个 translate 变体(translate / polar-translate / at-translate / offset-translate)
7
+ * 各自构造对应 Position 字面量并调用 `resolvePosition` 拿到 Cartesian (x, y),再写成 Cartesian translate;
8
+ * rotate / scale 直接透传。referent 未解析时返回 null(上游负责发 warn / throw)
9
+ */
10
+ var lowerScopeTransforms = (transforms, nameStack, nodeDistance) => {
11
+ const out = [];
12
+ for (const t of transforms) switch (t.kind) {
13
+ case "translate":
14
+ out.push({
15
+ kind: "translate",
16
+ x: t.x,
17
+ y: t.y
18
+ });
19
+ break;
20
+ case "polar-translate": {
21
+ const polar = {
22
+ angle: t.angle,
23
+ radius: t.radius
24
+ };
25
+ if (t.origin !== void 0) polar.origin = t.origin;
26
+ const resolved = require_position.resolvePosition(polar, nameStack, nodeDistance);
27
+ if (!resolved) return null;
28
+ out.push({
29
+ kind: "translate",
30
+ x: resolved[0],
31
+ y: resolved[1]
32
+ });
33
+ break;
34
+ }
35
+ case "at-translate": {
36
+ const at = {
37
+ direction: t.direction,
38
+ of: t.of
39
+ };
40
+ if (t.distance !== void 0) at.distance = t.distance;
41
+ const resolved = require_position.resolvePosition(at, nameStack, nodeDistance);
42
+ if (!resolved) return null;
43
+ out.push({
44
+ kind: "translate",
45
+ x: resolved[0],
46
+ y: resolved[1]
47
+ });
48
+ break;
49
+ }
50
+ case "offset-translate": {
51
+ const resolved = require_position.resolvePosition({
52
+ of: t.of,
53
+ offset: t.offset ?? [0, 0]
54
+ }, nameStack, nodeDistance);
55
+ if (!resolved) return null;
56
+ out.push({
57
+ kind: "translate",
58
+ x: resolved[0],
59
+ y: resolved[1]
60
+ });
61
+ break;
62
+ }
63
+ case "rotate": {
64
+ const r = {
65
+ kind: "rotate",
66
+ degrees: t.degrees
67
+ };
68
+ if (t.cx !== void 0) r.cx = t.cx;
69
+ if (t.cy !== void 0) r.cy = t.cy;
70
+ out.push(r);
71
+ break;
72
+ }
73
+ case "scale": {
74
+ const s = {
75
+ kind: "scale",
76
+ x: t.x
77
+ };
78
+ if (t.y !== void 0) s.y = t.y;
79
+ out.push(s);
80
+ break;
81
+ }
82
+ }
83
+ return out;
84
+ };
85
+ /**
86
+ * 把局部坐标点 (x, y) 按 Cartesian-only transform 链 apply 到全局坐标
87
+ * @description 数组语义与 SVG `transform="t0 t1 t2"` / TikZ scope option 顺序一致:
88
+ * array[0] 是最外层(最后 apply 到 local),array[last] 是最内层(最先 apply);
89
+ * 即对局部点 P,结果 = t0(t1(t2(P)))。实现上从数组尾部往头部迭代依次 apply。
90
+ * 只接受已被 `lowerScopeTransforms` 展平后的 3 变体(translate / rotate / scale)
91
+ */
92
+ var applyTransformChain = (local, chain) => {
93
+ let x = local[0];
94
+ let y = local[1];
95
+ for (let i = chain.length - 1; i >= 0; i--) {
96
+ const t = chain[i];
97
+ if (t.kind === "translate") {
98
+ x += t.x;
99
+ y += t.y;
100
+ } else if (t.kind === "rotate") {
101
+ const cx = t.cx ?? 0;
102
+ const cy = t.cy ?? 0;
103
+ const rad = t.degrees * Math.PI / 180;
104
+ const cos = Math.cos(rad);
105
+ const sin = Math.sin(rad);
106
+ const dx = x - cx;
107
+ const dy = y - cy;
108
+ x = cx + dx * cos - dy * sin;
109
+ y = cy + dx * sin + dy * cos;
110
+ } else {
111
+ const sy = t.y ?? t.x;
112
+ x *= t.x;
113
+ y *= sy;
114
+ }
115
+ }
116
+ return [x, y];
117
+ };
118
+ /**
119
+ * 把全局坐标点反向投影回 scope 局部坐标系(`applyTransformChain` 的逆)
120
+ * @description chain = [t0, t1, t2](array[0] 最外层、最后 apply)的逆 =
121
+ * 按数组正序应用每个 transform 的逆:t0^-1 / t1^-1 / t2^-1。
122
+ * translate(-x, -y) / rotate(-deg, cx, cy) / scale(1/x, 1/y)。
123
+ * scale 分量为 0 时反向投影未定义——退化为返回原点 (0, 0) 当前层,避免 NaN 污染下游。
124
+ * 作用:referent 全局点 → 当前 scope 局部坐标系,配合 `applyTransformChain` 实现
125
+ * "referent 全局 + relative 部分在当前 scope 局部度量 + 末端正向投影回全局" 的语义。
126
+ */
127
+ var inverseTransformChain = (global, chain) => {
128
+ let x = global[0];
129
+ let y = global[1];
130
+ for (const t of chain) if (t.kind === "translate") {
131
+ x -= t.x;
132
+ y -= t.y;
133
+ } else if (t.kind === "rotate") {
134
+ const cx = t.cx ?? 0;
135
+ const cy = t.cy ?? 0;
136
+ const rad = -t.degrees * Math.PI / 180;
137
+ const cos = Math.cos(rad);
138
+ const sin = Math.sin(rad);
139
+ const dx = x - cx;
140
+ const dy = y - cy;
141
+ x = cx + dx * cos - dy * sin;
142
+ y = cy + dx * sin + dy * cos;
143
+ } else {
144
+ const sy = t.y ?? t.x;
145
+ if (t.x === 0 || sy === 0) {
146
+ x = 0;
147
+ y = 0;
148
+ continue;
149
+ }
150
+ x /= t.x;
151
+ y /= sy;
152
+ }
153
+ return [x, y];
154
+ };
155
+ /**
156
+ * 复制 NodeLayout 并把 rect 中心点 + rotate + 尺寸全部按 scope transform chain 投到全局
157
+ * @description rect 中心走 `applyTransformChain`;chain 里的 rotate 累加到 `rect.rotate`(弧度)、
158
+ * scale 乘进 rect.width / height / margin——这样 path 端点的 boundary clip 取的是与 SVG `<g>`
159
+ * 实际渲染一致的视觉尺寸 / 朝向,跨 / 入 / 出 rotate / scale scope 的 path 都贴节点视觉边界。
160
+ * 非均匀 scale 与 rotate 在 chain 中混合时,按"累加 rotate + 分量相乘 scale"近似(uniform scale 精确,
161
+ * anisotropic + rotate 的剪切耦合不展开——alpha 阶段限制)。
162
+ */
163
+ var projectLayoutToGlobal = (layout, chain) => {
164
+ const [gx, gy] = applyTransformChain([layout.rect.x, layout.rect.y], chain);
165
+ let rotateAccumRad = 0;
166
+ let scaleX = 1;
167
+ let scaleY = 1;
168
+ for (const t of chain) if (t.kind === "rotate") rotateAccumRad += t.degrees * Math.PI / 180;
169
+ else if (t.kind === "scale") {
170
+ scaleX *= t.x;
171
+ scaleY *= t.y ?? t.x;
172
+ }
173
+ const globalRect = {
174
+ ...layout.rect,
175
+ x: gx,
176
+ y: gy,
177
+ rotate: (layout.rect.rotate ?? 0) + rotateAccumRad,
178
+ width: layout.rect.width * scaleX,
179
+ height: layout.rect.height * scaleY
180
+ };
181
+ const marginScale = Math.max(Math.abs(scaleX), Math.abs(scaleY));
182
+ return {
183
+ ...layout,
184
+ rect: globalRect,
185
+ margin: layout.margin * marginScale
186
+ };
187
+ };
188
+ /**
189
+ * 收集一组 NodeLayout 的全局 axis-aligned bounding box
190
+ * @description 每个 layout 的 4 角点已是全局坐标系(Pass 1 累积 chain apply 后),
191
+ * 取每个 layout 的 rotate-aware `north-west` / `north-east` / `south-west` / `south-east`
192
+ * 4 角点(rect.anchor 已含 layout.rect.rotate 处理)并求 AABB;
193
+ * layout 是 0×0(coordinate / 空 scope 占位)时退化为单点也合法;
194
+ * 空 layouts 数组返回 null(调用方按"empty scope + fallback origin"退化为 0×0 占位)
195
+ */
196
+ var computeScopeBoundingBox = (layouts) => {
197
+ if (layouts.length === 0) return null;
198
+ let minX = Infinity;
199
+ let minY = Infinity;
200
+ let maxX = -Infinity;
201
+ let maxY = -Infinity;
202
+ for (const layout of layouts) {
203
+ const corners = [
204
+ require_rect.rect.anchor(layout.rect, "north-west"),
205
+ require_rect.rect.anchor(layout.rect, "north-east"),
206
+ require_rect.rect.anchor(layout.rect, "south-west"),
207
+ require_rect.rect.anchor(layout.rect, "south-east")
208
+ ];
209
+ for (const [cx, cy] of corners) {
210
+ if (cx < minX) minX = cx;
211
+ if (cy < minY) minY = cy;
212
+ if (cx > maxX) maxX = cx;
213
+ if (cy > maxY) maxY = cy;
214
+ }
215
+ }
216
+ return {
217
+ x: (minX + maxX) / 2,
218
+ y: (minY + maxY) / 2,
219
+ width: maxX - minX,
220
+ height: maxY - minY
221
+ };
222
+ };
223
+ /**
224
+ * 用 scope id + bbox 构造 synthetic rectangle NodeLayout
225
+ * @description bbox 为 null 时退化为 fallbackOrigin 的 0×0 占位(空 scope 仍要有可引用句柄)。
226
+ * synthetic layout 完全复用 rectangle 路径:`scope.id.<keyword>` / `scope.id.<deg>` / `scope.id` 作为 referent
227
+ * 走与普通 rectangle Node 完全一致的 anchorOf / boundaryPointOf / 中心点取值
228
+ */
229
+ var registerScopeAsLayout = (id, bbox, fallbackOrigin) => {
230
+ const box = bbox ?? {
231
+ x: fallbackOrigin[0],
232
+ y: fallbackOrigin[1],
233
+ width: 0,
234
+ height: 0
235
+ };
236
+ return {
237
+ id,
238
+ shape: "rectangle",
239
+ rect: {
240
+ x: box.x,
241
+ y: box.y,
242
+ width: box.width,
243
+ height: box.height,
244
+ rotate: 0
245
+ },
246
+ rotateDeg: 0,
247
+ margin: 0,
248
+ textWidth: box.width,
249
+ textHeight: box.height,
250
+ align: "middle",
251
+ lineHeight: 0,
252
+ fontSize: 0
253
+ };
254
+ };
255
+ //#endregion
256
+ exports.applyTransformChain = applyTransformChain;
257
+ exports.computeScopeBoundingBox = computeScopeBoundingBox;
258
+ exports.inverseTransformChain = inverseTransformChain;
259
+ exports.lowerScopeTransforms = lowerScopeTransforms;
260
+ exports.projectLayoutToGlobal = projectLayoutToGlobal;
261
+ exports.registerScopeAsLayout = registerScopeAsLayout;
@@ -0,0 +1,66 @@
1
+ import { IRPosition, IRTransform } from '../ir';
2
+ import { Transform } from '../primitive';
3
+ import { NameStack } from './name-stack';
4
+ import { NodeLayout } from './node';
5
+ /**
6
+ * 把 IR 6 变体 transforms 展平为 Scene 3 变体(Cartesian translate / rotate / scale)
7
+ * @description 4 个 translate 变体(translate / polar-translate / at-translate / offset-translate)
8
+ * 各自构造对应 Position 字面量并调用 `resolvePosition` 拿到 Cartesian (x, y),再写成 Cartesian translate;
9
+ * rotate / scale 直接透传。referent 未解析时返回 null(上游负责发 warn / throw)
10
+ */
11
+ export declare const lowerScopeTransforms: (transforms: ReadonlyArray<IRTransform>, nameStack: NameStack, nodeDistance?: number) => Array<Transform> | null;
12
+ /**
13
+ * 把局部坐标点 (x, y) 按 Cartesian-only transform 链 apply 到全局坐标
14
+ * @description 数组语义与 SVG `transform="t0 t1 t2"` / TikZ scope option 顺序一致:
15
+ * array[0] 是最外层(最后 apply 到 local),array[last] 是最内层(最先 apply);
16
+ * 即对局部点 P,结果 = t0(t1(t2(P)))。实现上从数组尾部往头部迭代依次 apply。
17
+ * 只接受已被 `lowerScopeTransforms` 展平后的 3 变体(translate / rotate / scale)
18
+ */
19
+ export declare const applyTransformChain: (local: IRPosition, chain: ReadonlyArray<Transform>) => IRPosition;
20
+ /**
21
+ * 把全局坐标点反向投影回 scope 局部坐标系(`applyTransformChain` 的逆)
22
+ * @description chain = [t0, t1, t2](array[0] 最外层、最后 apply)的逆 =
23
+ * 按数组正序应用每个 transform 的逆:t0^-1 / t1^-1 / t2^-1。
24
+ * translate(-x, -y) / rotate(-deg, cx, cy) / scale(1/x, 1/y)。
25
+ * scale 分量为 0 时反向投影未定义——退化为返回原点 (0, 0) 当前层,避免 NaN 污染下游。
26
+ * 作用:referent 全局点 → 当前 scope 局部坐标系,配合 `applyTransformChain` 实现
27
+ * "referent 全局 + relative 部分在当前 scope 局部度量 + 末端正向投影回全局" 的语义。
28
+ */
29
+ export declare const inverseTransformChain: (global: IRPosition, chain: ReadonlyArray<Transform>) => IRPosition;
30
+ /**
31
+ * 复制 NodeLayout 并把 rect 中心点 + rotate + 尺寸全部按 scope transform chain 投到全局
32
+ * @description rect 中心走 `applyTransformChain`;chain 里的 rotate 累加到 `rect.rotate`(弧度)、
33
+ * scale 乘进 rect.width / height / margin——这样 path 端点的 boundary clip 取的是与 SVG `<g>`
34
+ * 实际渲染一致的视觉尺寸 / 朝向,跨 / 入 / 出 rotate / scale scope 的 path 都贴节点视觉边界。
35
+ * 非均匀 scale 与 rotate 在 chain 中混合时,按"累加 rotate + 分量相乘 scale"近似(uniform scale 精确,
36
+ * anisotropic + rotate 的剪切耦合不展开——alpha 阶段限制)。
37
+ */
38
+ export declare const projectLayoutToGlobal: (layout: NodeLayout, chain: ReadonlyArray<Transform>) => NodeLayout;
39
+ /** scope bbox 计算结果:bbox 几何中心 + 尺寸(width/height ≥ 0;空 scope 退化为 0×0 占位时仍合法) */
40
+ export type ScopeBoundingBox = {
41
+ /** bbox 几何中心 x(全局坐标) */
42
+ x: number;
43
+ /** bbox 几何中心 y(全局坐标) */
44
+ y: number;
45
+ /** bbox 宽度(≥ 0;空 scope / 单点退化为 0) */
46
+ width: number;
47
+ /** bbox 高度(≥ 0;空 scope / 单点退化为 0) */
48
+ height: number;
49
+ };
50
+ /**
51
+ * 收集一组 NodeLayout 的全局 axis-aligned bounding box
52
+ * @description 每个 layout 的 4 角点已是全局坐标系(Pass 1 累积 chain apply 后),
53
+ * 取每个 layout 的 rotate-aware `north-west` / `north-east` / `south-west` / `south-east`
54
+ * 4 角点(rect.anchor 已含 layout.rect.rotate 处理)并求 AABB;
55
+ * layout 是 0×0(coordinate / 空 scope 占位)时退化为单点也合法;
56
+ * 空 layouts 数组返回 null(调用方按"empty scope + fallback origin"退化为 0×0 占位)
57
+ */
58
+ export declare const computeScopeBoundingBox: (layouts: ReadonlyArray<NodeLayout>) => ScopeBoundingBox | null;
59
+ /**
60
+ * 用 scope id + bbox 构造 synthetic rectangle NodeLayout
61
+ * @description bbox 为 null 时退化为 fallbackOrigin 的 0×0 占位(空 scope 仍要有可引用句柄)。
62
+ * synthetic layout 完全复用 rectangle 路径:`scope.id.<keyword>` / `scope.id.<deg>` / `scope.id` 作为 referent
63
+ * 走与普通 rectangle Node 完全一致的 anchorOf / boundaryPointOf / 中心点取值
64
+ */
65
+ export declare const registerScopeAsLayout: (id: string, bbox: ScopeBoundingBox | null, fallbackOrigin: IRPosition) => NodeLayout;
66
+ //# sourceMappingURL=scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../../src/compile/scope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,UAAU,EACV,WAAW,EAEZ,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGzC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,YAAY,aAAa,CAAC,WAAW,CAAC,EACtC,WAAW,SAAS,EACpB,eAAe,MAAM,KACpB,KAAK,CAAC,SAAS,CAAC,GAAG,IAiDrB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,UAAU,EACjB,OAAO,aAAa,CAAC,SAAS,CAAC,KAC9B,UAyBF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,UAAU,EAClB,OAAO,aAAa,CAAC,SAAS,CAAC,KAC9B,UAgCF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,UAAU,EAClB,OAAO,aAAa,CAAC,SAAS,CAAC,KAC9B,UAuBF,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wBAAwB;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,wBAAwB;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAClC,SAAS,aAAa,CAAC,UAAU,CAAC,KACjC,gBAAgB,GAAG,IA2BrB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAChC,IAAI,MAAM,EACV,MAAM,gBAAgB,GAAG,IAAI,EAC7B,gBAAgB,UAAU,KACzB,UAeF,CAAC"}
@@ -0,0 +1,262 @@
1
+ //#region src/compile/style.ts
2
+ /** 拷贝源对象中 `!== undefined` 的字段(per-field 合并按存在性,不按真假值) */
3
+ var pickDefinedKeys = (src) => {
4
+ const out = {};
5
+ for (const key of Object.keys(src)) {
6
+ const value = src[key];
7
+ if (value !== void 0) out[key] = value;
8
+ }
9
+ return out;
10
+ };
11
+ /**
12
+ * 从 IRScope 抽取样式 frame
13
+ * @description 只摘样式相关字段(级联 graphic state + 四通道 + resetStyle);transforms / id / localNamespace 与样式正交,不进 frame
14
+ */
15
+ var buildStyleFrame = (scope) => {
16
+ const cascade = {};
17
+ if (scope.color !== void 0) cascade.color = scope.color;
18
+ if (scope.stroke !== void 0) cascade.stroke = scope.stroke;
19
+ if (scope.fill !== void 0) cascade.fill = scope.fill;
20
+ if (scope.strokeWidth !== void 0) cascade.strokeWidth = scope.strokeWidth;
21
+ if (scope.opacity !== void 0) cascade.opacity = scope.opacity;
22
+ if (scope.fillOpacity !== void 0) cascade.fillOpacity = scope.fillOpacity;
23
+ if (scope.drawOpacity !== void 0) cascade.drawOpacity = scope.drawOpacity;
24
+ const frame = { cascade };
25
+ if (scope.nodeDefault) frame.nodeDefault = scope.nodeDefault;
26
+ if (scope.pathDefault) frame.pathDefault = scope.pathDefault;
27
+ if (scope.labelDefault) frame.labelDefault = scope.labelDefault;
28
+ if (scope.arrowDefault) frame.arrowDefault = scope.arrowDefault;
29
+ if (scope.resetStyle !== void 0) frame.resetStyle = scope.resetStyle;
30
+ return frame;
31
+ };
32
+ /** resetStyle 是否切某通道 */
33
+ var cuts = (reset, channel) => {
34
+ if (reset === void 0 || reset === false) return false;
35
+ if (reset === true) return true;
36
+ return reset.includes(channel);
37
+ };
38
+ /** 级联 graphic state 投影到 node 样式字段(主色展开:stroke / fill / textColor 默认随 color) */
39
+ var cascadeToNode = (c) => {
40
+ const out = {};
41
+ const master = c.color;
42
+ const stroke = c.stroke ?? master;
43
+ if (stroke !== void 0) out.stroke = stroke;
44
+ const fill = c.fill ?? master;
45
+ if (fill !== void 0) out.fill = fill;
46
+ if (master !== void 0) out.textColor = master;
47
+ if (c.strokeWidth !== void 0) out.strokeWidth = c.strokeWidth;
48
+ if (c.opacity !== void 0) out.opacity = c.opacity;
49
+ if (c.fillOpacity !== void 0) out.fillOpacity = c.fillOpacity;
50
+ if (c.drawOpacity !== void 0) out.drawOpacity = c.drawOpacity;
51
+ return out;
52
+ };
53
+ /** 级联 graphic state 投影到 path 样式字段(主色展开 stroke;path fill 不随主色——与 TikZ 一致) */
54
+ var cascadeToPath = (c) => {
55
+ const out = {};
56
+ const stroke = c.stroke ?? c.color;
57
+ if (stroke !== void 0) out.stroke = stroke;
58
+ if (c.fill !== void 0) out.fill = c.fill;
59
+ if (c.strokeWidth !== void 0) out.strokeWidth = c.strokeWidth;
60
+ if (c.opacity !== void 0) out.opacity = c.opacity;
61
+ if (c.fillOpacity !== void 0) out.fillOpacity = c.fillOpacity;
62
+ if (c.drawOpacity !== void 0) out.drawOpacity = c.drawOpacity;
63
+ return out;
64
+ };
65
+ /** node 源同源主色展开:未显式给的 stroke / fill / textColor 取该源 color */
66
+ var expandNodeColor = (src) => {
67
+ const out = { ...src };
68
+ const master = src.color;
69
+ if (master !== void 0) {
70
+ if (out.stroke === void 0) out.stroke = master;
71
+ if (out.fill === void 0) out.fill = master;
72
+ if (out.textColor === void 0) out.textColor = master;
73
+ }
74
+ return out;
75
+ };
76
+ /** path 源同源主色展开:未显式给的 stroke 取该源 color(fill 不随主色) */
77
+ var expandPathColor = (src) => {
78
+ const out = { ...src };
79
+ if (src.color !== void 0 && out.stroke === void 0) out.stroke = src.color;
80
+ return out;
81
+ };
82
+ /**
83
+ * 解析 node 最终样式——fold 外→内 frame 栈 + 元素显式
84
+ * @description 优先级链(每分项就近 model A):元素显式分项 > 元素 color > nodeDefault 分项 > nodeDefault color
85
+ * > scope 级联分项 > scope color > 内置(layoutNode 兜底)。同 frame 内 nodeDefault 优先于级联。
86
+ * resetStyle('node') 丢外层累积;position / id / text / label 取元素自身(不参与继承)。
87
+ */
88
+ var resolveNodeStyle = (node, stack) => {
89
+ let acc = {};
90
+ for (const frame of stack) {
91
+ if (cuts(frame.resetStyle, "node")) acc = {};
92
+ acc = {
93
+ ...acc,
94
+ ...pickDefinedKeys(cascadeToNode(frame.cascade))
95
+ };
96
+ if (frame.nodeDefault) acc = {
97
+ ...acc,
98
+ ...pickDefinedKeys(expandNodeColor(frame.nodeDefault))
99
+ };
100
+ }
101
+ acc = {
102
+ ...acc,
103
+ ...pickDefinedKeys(expandNodeColor(node))
104
+ };
105
+ return acc;
106
+ };
107
+ /** fold labelDefault 通道(node label + step label 共享);resetStyle('label') 丢外层 */
108
+ var resolveLabelDefault = (stack) => {
109
+ let acc = {};
110
+ for (const frame of stack) {
111
+ if (cuts(frame.resetStyle, "label")) acc = {};
112
+ if (frame.labelDefault) acc = {
113
+ ...acc,
114
+ ...pickDefinedKeys(frame.labelDefault)
115
+ };
116
+ }
117
+ return acc;
118
+ };
119
+ /** 逐字段合并字体(a 优先,缺字段回退 b);都空返回 undefined */
120
+ var mergeFont = (a, b) => {
121
+ if (a === void 0) return b;
122
+ if (b === void 0) return a;
123
+ const out = {};
124
+ const family = a.family ?? b.family;
125
+ if (family !== void 0) out.family = family;
126
+ const size = a.size ?? b.size;
127
+ if (size !== void 0) out.size = size;
128
+ const weight = a.weight ?? b.weight;
129
+ if (weight !== void 0) out.weight = weight;
130
+ const style = a.style ?? b.style;
131
+ if (style !== void 0) out.style = style;
132
+ return out;
133
+ };
134
+ /**
135
+ * 解析 step label 最终样式——消费 scope labelDefault + 宿主 path 已解析主色
136
+ * @description 继承顺序:label 显式 > scope.labelDefault (textColor → color) > 宿主 path 主色 > currentColor(emit 兜底)。
137
+ * 跟随的是宿主 path 主色(不是 stroke);font 逐字段回退 labelDefault;opacity 与 path opacity 相乘在 emit 阶段。
138
+ * masterColor 是 host 轴(结构关系),不受 resetStyle('label') 影响——label 仍跟所属线,不成孤岛。
139
+ */
140
+ var resolveStepLabel = (label, labelDefault, masterColor) => {
141
+ const out = { ...label };
142
+ const textColor = label.textColor ?? labelDefault.textColor ?? labelDefault.color ?? masterColor;
143
+ if (textColor !== void 0) out.textColor = textColor;
144
+ else delete out.textColor;
145
+ const font = mergeFont(label.font, labelDefault.font);
146
+ if (font !== void 0) out.font = font;
147
+ const opacity = label.opacity ?? labelDefault.opacity;
148
+ if (opacity !== void 0) out.opacity = opacity;
149
+ return out;
150
+ };
151
+ /** per-field 合并 arrow 端点 spec(b 覆盖 a 的 defined 字段;返回新对象,不共享引用) */
152
+ var mergeArrowEnd = (a, b) => {
153
+ if (a === void 0) return b === void 0 ? void 0 : { ...b };
154
+ if (b === void 0) return { ...a };
155
+ return {
156
+ ...a,
157
+ ...pickDefinedKeys(b)
158
+ };
159
+ };
160
+ /** per-field 合并 arrow detail:顶层 + start / end 各自 nested per-field merge(返回新对象,不共享引用) */
161
+ var mergeArrowDetail = (a, b) => {
162
+ const { start: aStart, end: aEnd, ...aTop } = a;
163
+ const { start: bStart, end: bEnd, ...bTop } = b;
164
+ const out = {
165
+ ...aTop,
166
+ ...pickDefinedKeys(bTop)
167
+ };
168
+ const start = mergeArrowEnd(aStart, bStart);
169
+ if (start !== void 0) out.start = start;
170
+ const end = mergeArrowEnd(aEnd, bEnd);
171
+ if (end !== void 0) out.end = end;
172
+ return out;
173
+ };
174
+ /** 去掉端点 spec 的 color(让端点 color 回退到顶层主色);返回新对象 */
175
+ var dropArrowEndColor = (end) => {
176
+ const next = { ...end };
177
+ delete next.color;
178
+ return next;
179
+ };
180
+ /**
181
+ * 解析 arrow detail——fold arrowDefault 通道 + 跟宿主 path 主色 + 元素 arrowDetail
182
+ * @description color 优先级(顶层与 start / end 端点同理):元素显式 arrowDetail(含 start / end.color)> 宿主 path 已解析主色 > arrowDefault(含 start / end.color)> 内置。
183
+ * 宿主主色(host 轴,决策 13)会清掉 arrowDefault 带来的端点 color,让 start / end 回退到顶层主色;元素自身 arrowDetail(含 start / end.color)仍最高。
184
+ * masterColor 不受 resetStyle('arrow') 影响(host 轴非 scope 继承)。lineWidth / fill 的主色映射推迟(render 端仍按现有兜底继承 path stroke)。
185
+ */
186
+ var resolveArrowDetail = (explicit, stack, masterColor) => {
187
+ let acc = {};
188
+ let touched = false;
189
+ for (const frame of stack) {
190
+ if (cuts(frame.resetStyle, "arrow")) {
191
+ acc = {};
192
+ touched = false;
193
+ }
194
+ if (frame.arrowDefault) {
195
+ acc = mergeArrowDetail(acc, frame.arrowDefault);
196
+ touched = true;
197
+ }
198
+ }
199
+ if (masterColor !== void 0) {
200
+ acc.color = masterColor;
201
+ if (acc.start !== void 0) acc.start = dropArrowEndColor(acc.start);
202
+ if (acc.end !== void 0) acc.end = dropArrowEndColor(acc.end);
203
+ touched = true;
204
+ }
205
+ if (explicit) {
206
+ acc = mergeArrowDetail(acc, explicit);
207
+ touched = true;
208
+ }
209
+ return touched ? acc : void 0;
210
+ };
211
+ /** 替换 path children 中各 step 的 label 为已解析 effective label */
212
+ var resolveStepLabels = (children, labelDefault, masterColor) => children.map((step) => {
213
+ if ("label" in step && step.label !== void 0) return {
214
+ ...step,
215
+ label: resolveStepLabel(step.label, labelDefault, masterColor)
216
+ };
217
+ return step;
218
+ });
219
+ /**
220
+ * 解析 path 最终样式——fold frame 栈 + 元素显式 + arrow / step-label 跟宿主主色
221
+ * @description 返回 effective IRPath:base 样式 fold(优先级链同 node);arrowDetail 消费 arrowDefault 通道 + 跟主色;
222
+ * 每个 step.label 消费 labelDefault 通道 + 跟主色。masterColor = path 已解析主色(就近 color),arrow / step-label 跟它(不跟 stroke)。
223
+ */
224
+ var resolveEffectivePath = (path, stack) => {
225
+ let acc = {};
226
+ let masterColor;
227
+ for (const frame of stack) {
228
+ if (cuts(frame.resetStyle, "path")) {
229
+ acc = {};
230
+ masterColor = void 0;
231
+ }
232
+ if (frame.cascade.color !== void 0) masterColor = frame.cascade.color;
233
+ acc = {
234
+ ...acc,
235
+ ...pickDefinedKeys(cascadeToPath(frame.cascade))
236
+ };
237
+ if (frame.pathDefault) {
238
+ if (frame.pathDefault.color !== void 0) masterColor = frame.pathDefault.color;
239
+ acc = {
240
+ ...acc,
241
+ ...pickDefinedKeys(expandPathColor(frame.pathDefault))
242
+ };
243
+ }
244
+ }
245
+ if (path.color !== void 0) masterColor = path.color;
246
+ acc = {
247
+ ...acc,
248
+ ...pickDefinedKeys(expandPathColor(path))
249
+ };
250
+ const effective = acc;
251
+ const arrowDetail = resolveArrowDetail(path.arrowDetail, stack, masterColor);
252
+ if (arrowDetail !== void 0) effective.arrowDetail = arrowDetail;
253
+ else delete effective.arrowDetail;
254
+ const labelDefault = resolveLabelDefault(stack);
255
+ effective.children = resolveStepLabels(path.children, labelDefault, masterColor);
256
+ return effective;
257
+ };
258
+ //#endregion
259
+ exports.buildStyleFrame = buildStyleFrame;
260
+ exports.resolveEffectivePath = resolveEffectivePath;
261
+ exports.resolveLabelDefault = resolveLabelDefault;
262
+ exports.resolveNodeStyle = resolveNodeStyle;
@@ -0,0 +1,46 @@
1
+ import { IRArrowDetail, IRLabelDefault, IRNode, IRPath, IRScope } from '../ir';
2
+ /**
3
+ * scope 级联 graphic state——主色 color + 跨类共享分项
4
+ * @description 级联到 scope 内全部元素(= TikZ scope option / current color)
5
+ */
6
+ type CascadeState = Pick<IRScope, 'color' | 'stroke' | 'fill' | 'strokeWidth' | 'opacity' | 'fillOpacity' | 'drawOpacity'>;
7
+ /**
8
+ * 单层 scope 的样式 frame——compile 维护 frame 栈做 inside-out per-field 解析
9
+ * @description 级联 graphic state + 四通道 every-X 默认 + resetStyle 屏障;从 IRScope 抽取(buildStyleFrame)
10
+ */
11
+ export type StyleFrame = {
12
+ /** 级联 graphic state(主色 + 跨类共享分项) */
13
+ cascade: CascadeState;
14
+ /** every node 默认 */
15
+ nodeDefault?: IRScope['nodeDefault'];
16
+ /** every path 默认 */
17
+ pathDefault?: IRScope['pathDefault'];
18
+ /** every label 默认(node label + step label 共享) */
19
+ labelDefault?: IRLabelDefault;
20
+ /** every arrow 默认 */
21
+ arrowDefault?: IRArrowDetail;
22
+ /** 朝外的继承屏障:切外层对应通道 */
23
+ resetStyle?: IRScope['resetStyle'];
24
+ };
25
+ /**
26
+ * 从 IRScope 抽取样式 frame
27
+ * @description 只摘样式相关字段(级联 graphic state + 四通道 + resetStyle);transforms / id / localNamespace 与样式正交,不进 frame
28
+ */
29
+ export declare const buildStyleFrame: (scope: IRScope) => StyleFrame;
30
+ /**
31
+ * 解析 node 最终样式——fold 外→内 frame 栈 + 元素显式
32
+ * @description 优先级链(每分项就近 model A):元素显式分项 > 元素 color > nodeDefault 分项 > nodeDefault color
33
+ * > scope 级联分项 > scope color > 内置(layoutNode 兜底)。同 frame 内 nodeDefault 优先于级联。
34
+ * resetStyle('node') 丢外层累积;position / id / text / label 取元素自身(不参与继承)。
35
+ */
36
+ export declare const resolveNodeStyle: (node: IRNode, stack: ReadonlyArray<StyleFrame>) => IRNode;
37
+ /** fold labelDefault 通道(node label + step label 共享);resetStyle('label') 丢外层 */
38
+ export declare const resolveLabelDefault: (stack: ReadonlyArray<StyleFrame>) => IRLabelDefault;
39
+ /**
40
+ * 解析 path 最终样式——fold frame 栈 + 元素显式 + arrow / step-label 跟宿主主色
41
+ * @description 返回 effective IRPath:base 样式 fold(优先级链同 node);arrowDetail 消费 arrowDefault 通道 + 跟主色;
42
+ * 每个 step.label 消费 labelDefault 通道 + 跟主色。masterColor = path 已解析主色(就近 color),arrow / step-label 跟它(不跟 stroke)。
43
+ */
44
+ export declare const resolveEffectivePath: (path: IRPath, stack: ReadonlyArray<StyleFrame>) => IRPath;
45
+ export {};
46
+ //# sourceMappingURL=style.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../../src/compile/style.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAGb,cAAc,EACd,MAAM,EACN,MAAM,EACN,OAAO,EAIR,MAAM,OAAO,CAAC;AAEf;;;GAGG;AACH,KAAK,YAAY,GAAG,IAAI,CACtB,OAAO,EACP,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,aAAa,GAAG,SAAS,GAAG,aAAa,GAAG,aAAa,CACxF,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,oCAAoC;IACpC,OAAO,EAAE,YAAY,CAAC;IACtB,oBAAoB;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACrC,oBAAoB;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACrC,iDAAiD;IACjD,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,qBAAqB;IACrB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,sBAAsB;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACpC,CAAC;AAYF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,OAAO,KAAG,UAgBhD,CAAC;AAiEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,MAAM,EACZ,OAAO,aAAa,CAAC,UAAU,CAAC,KAC/B,MAYF,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,GAC9B,OAAO,aAAa,CAAC,UAAU,CAAC,KAC/B,cAOF,CAAC;AAyHF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,EACZ,OAAO,aAAa,CAAC,UAAU,CAAC,KAC/B,MA2BF,CAAC"}