@retikz/core 0.1.0-alpha.2 → 0.1.0-alpha.4

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 (119) hide show
  1. package/dist/es/compile/compile.d.ts +6 -0
  2. package/dist/es/compile/compile.d.ts.map +1 -1
  3. package/dist/es/compile/compile.js +33 -4
  4. package/dist/es/compile/node.d.ts +23 -2
  5. package/dist/es/compile/node.d.ts.map +1 -1
  6. package/dist/es/compile/node.js +94 -4
  7. package/dist/es/compile/path.d.ts +3 -2
  8. package/dist/es/compile/path.d.ts.map +1 -1
  9. package/dist/es/compile/path.js +333 -14
  10. package/dist/es/compile/position.d.ts +8 -5
  11. package/dist/es/compile/position.d.ts.map +1 -1
  12. package/dist/es/compile/position.js +32 -5
  13. package/dist/es/geometry/arc.d.ts +34 -0
  14. package/dist/es/geometry/arc.d.ts.map +1 -0
  15. package/dist/es/geometry/arc.js +53 -0
  16. package/dist/es/geometry/bend.d.ts +18 -0
  17. package/dist/es/geometry/bend.d.ts.map +1 -0
  18. package/dist/es/geometry/bend.js +29 -0
  19. package/dist/es/geometry/index.d.ts +3 -0
  20. package/dist/es/geometry/index.d.ts.map +1 -1
  21. package/dist/es/geometry/segment.d.ts +38 -0
  22. package/dist/es/geometry/segment.d.ts.map +1 -0
  23. package/dist/es/geometry/segment.js +82 -0
  24. package/dist/es/index.d.ts +4 -4
  25. package/dist/es/index.d.ts.map +1 -1
  26. package/dist/es/index.js +7 -4
  27. package/dist/es/ir/coordinate.d.ts +57 -0
  28. package/dist/es/ir/coordinate.d.ts.map +1 -0
  29. package/dist/es/ir/coordinate.js +27 -0
  30. package/dist/es/ir/index.d.ts +1 -0
  31. package/dist/es/ir/index.d.ts.map +1 -1
  32. package/dist/es/ir/node.d.ts +276 -17
  33. package/dist/es/ir/node.d.ts.map +1 -1
  34. package/dist/es/ir/node.js +28 -3
  35. package/dist/es/ir/path/path.d.ts +625 -15
  36. package/dist/es/ir/path/path.d.ts.map +1 -1
  37. package/dist/es/ir/path/path.js +22 -0
  38. package/dist/es/ir/path/step.d.ts +872 -20
  39. package/dist/es/ir/path/step.d.ts.map +1 -1
  40. package/dist/es/ir/path/step.js +86 -4
  41. package/dist/es/ir/path/target.d.ts +32 -2
  42. package/dist/es/ir/path/target.d.ts.map +1 -1
  43. package/dist/es/ir/path/target.js +7 -3
  44. package/dist/es/ir/position/at-position.d.ts +50 -0
  45. package/dist/es/ir/position/at-position.d.ts.map +1 -0
  46. package/dist/es/ir/position/at-position.js +30 -0
  47. package/dist/es/ir/position/index.d.ts +1 -0
  48. package/dist/es/ir/position/index.d.ts.map +1 -1
  49. package/dist/es/ir/scene.d.ts +2072 -112
  50. package/dist/es/ir/scene.d.ts.map +1 -1
  51. package/dist/es/ir/scene.js +6 -1
  52. package/dist/es/parsers/index.d.ts +1 -0
  53. package/dist/es/parsers/index.d.ts.map +1 -1
  54. package/dist/es/parsers/parseTargetSugar.d.ts +3 -0
  55. package/dist/es/parsers/parseTargetSugar.d.ts.map +1 -0
  56. package/dist/es/parsers/parseTargetSugar.js +31 -0
  57. package/dist/es/parsers/parseWay.d.ts +131 -22
  58. package/dist/es/parsers/parseWay.d.ts.map +1 -1
  59. package/dist/es/parsers/parseWay.js +149 -17
  60. package/dist/lib/compile/compile.cjs +33 -4
  61. package/dist/lib/compile/compile.d.ts +6 -0
  62. package/dist/lib/compile/compile.d.ts.map +1 -1
  63. package/dist/lib/compile/node.cjs +94 -4
  64. package/dist/lib/compile/node.d.ts +23 -2
  65. package/dist/lib/compile/node.d.ts.map +1 -1
  66. package/dist/lib/compile/path.cjs +333 -14
  67. package/dist/lib/compile/path.d.ts +3 -2
  68. package/dist/lib/compile/path.d.ts.map +1 -1
  69. package/dist/lib/compile/position.cjs +32 -5
  70. package/dist/lib/compile/position.d.ts +8 -5
  71. package/dist/lib/compile/position.d.ts.map +1 -1
  72. package/dist/lib/geometry/arc.cjs +55 -0
  73. package/dist/lib/geometry/arc.d.ts +34 -0
  74. package/dist/lib/geometry/arc.d.ts.map +1 -0
  75. package/dist/lib/geometry/bend.cjs +29 -0
  76. package/dist/lib/geometry/bend.d.ts +18 -0
  77. package/dist/lib/geometry/bend.d.ts.map +1 -0
  78. package/dist/lib/geometry/index.d.ts +3 -0
  79. package/dist/lib/geometry/index.d.ts.map +1 -1
  80. package/dist/lib/geometry/segment.cjs +88 -0
  81. package/dist/lib/geometry/segment.d.ts +38 -0
  82. package/dist/lib/geometry/segment.d.ts.map +1 -0
  83. package/dist/lib/index.cjs +18 -0
  84. package/dist/lib/index.d.ts +4 -4
  85. package/dist/lib/index.d.ts.map +1 -1
  86. package/dist/lib/ir/coordinate.cjs +27 -0
  87. package/dist/lib/ir/coordinate.d.ts +57 -0
  88. package/dist/lib/ir/coordinate.d.ts.map +1 -0
  89. package/dist/lib/ir/index.d.ts +1 -0
  90. package/dist/lib/ir/index.d.ts.map +1 -1
  91. package/dist/lib/ir/node.cjs +28 -2
  92. package/dist/lib/ir/node.d.ts +276 -17
  93. package/dist/lib/ir/node.d.ts.map +1 -1
  94. package/dist/lib/ir/path/path.cjs +22 -0
  95. package/dist/lib/ir/path/path.d.ts +625 -15
  96. package/dist/lib/ir/path/path.d.ts.map +1 -1
  97. package/dist/lib/ir/path/step.cjs +93 -3
  98. package/dist/lib/ir/path/step.d.ts +872 -20
  99. package/dist/lib/ir/path/step.d.ts.map +1 -1
  100. package/dist/lib/ir/path/target.cjs +8 -2
  101. package/dist/lib/ir/path/target.d.ts +32 -2
  102. package/dist/lib/ir/path/target.d.ts.map +1 -1
  103. package/dist/lib/ir/position/at-position.cjs +31 -0
  104. package/dist/lib/ir/position/at-position.d.ts +50 -0
  105. package/dist/lib/ir/position/at-position.d.ts.map +1 -0
  106. package/dist/lib/ir/position/index.d.ts +1 -0
  107. package/dist/lib/ir/position/index.d.ts.map +1 -1
  108. package/dist/lib/ir/scene.cjs +6 -1
  109. package/dist/lib/ir/scene.d.ts +2072 -112
  110. package/dist/lib/ir/scene.d.ts.map +1 -1
  111. package/dist/lib/parsers/index.d.ts +1 -0
  112. package/dist/lib/parsers/index.d.ts.map +1 -1
  113. package/dist/lib/parsers/parseTargetSugar.cjs +31 -0
  114. package/dist/lib/parsers/parseTargetSugar.d.ts +3 -0
  115. package/dist/lib/parsers/parseTargetSugar.d.ts.map +1 -0
  116. package/dist/lib/parsers/parseWay.cjs +149 -17
  117. package/dist/lib/parsers/parseWay.d.ts +131 -22
  118. package/dist/lib/parsers/parseWay.d.ts.map +1 -1
  119. package/package.json +1 -1
@@ -13,6 +13,12 @@ export type CompileOptions = {
13
13
  * 内部几何计算保持完整 double 精度,避免误差累积。
14
14
  */
15
15
  precision?: number;
16
+ /**
17
+ * 相对定位(AtPosition)的默认距离,对应 TikZ `node distance`;user units。
18
+ * 当 `Node.position` 是 `{ direction, of }` 形态且未自带 `distance` 时取此值;
19
+ * 未配则回退到 1。
20
+ */
21
+ nodeDistance?: number;
16
22
  };
17
23
  /**
18
24
  * IR → Scene。纯函数。
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/compile/compile.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,OAAO,CAAC;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAkB,MAAM,cAAc,CAAC;AAI1D,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AAGrE,2BAA2B;AAC3B,MAAM,MAAM,cAAc,GAAG;IAC3B,oCAAoC;IACpC,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAI,IAAI,EAAE,EAAE,UAAS,cAAmB,KAAG,KA2CrE,CAAC"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/compile/compile.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,OAAO,CAAC;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAkB,MAAM,cAAc,CAAC;AAK1D,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AAwBrE,2BAA2B;AAC3B,MAAM,MAAM,cAAc,GAAG;IAC3B,oCAAoC;IACpC,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAI,IAAI,EAAE,EAAE,UAAS,cAAmB,KAAG,KAsDrE,CAAC"}
@@ -1,11 +1,35 @@
1
1
  import { rect } from "../geometry/rect.js";
2
+ import { resolvePosition } from "./position.js";
2
3
  import { emitNodePrimitives, layoutNode } from "./node.js";
4
+ import { fallbackMeasurer } from "./text-metrics.js";
3
5
  import { emitPathPrimitive } from "./path.js";
4
6
  import { makeRound } from "./precision.js";
5
- import { fallbackMeasurer } from "./text-metrics.js";
6
7
  import { computeViewBox } from "./view-box.js";
7
8
  //#region src/compile/compile.ts
8
9
  /**
10
+ * 把 coordinate 注册成最小 NodeLayout——0×0 rectangle,用于
11
+ * 后续 path target / `at.of` 引用时 boundaryPoint 命中(0×0 rect
12
+ * 的 boundaryPoint 始终返回中心,符合"占位无形状边界"语义)。
13
+ */
14
+ var coordinateAsLayout = (id, center) => ({
15
+ id,
16
+ shape: "rectangle",
17
+ rect: {
18
+ x: center[0],
19
+ y: center[1],
20
+ width: 0,
21
+ height: 0,
22
+ rotate: 0
23
+ },
24
+ rotateDeg: 0,
25
+ margin: 0,
26
+ textWidth: 0,
27
+ textHeight: 0,
28
+ align: "middle",
29
+ lineHeight: 0,
30
+ fontSize: 0
31
+ });
32
+ /**
9
33
  * IR → Scene。纯函数。
10
34
  * 这是所有 adapter 共享的最深层共享代码。
11
35
  *
@@ -18,19 +42,24 @@ var compileToScene = (ir, options = {}) => {
18
42
  const measureText = options.measureText ?? fallbackMeasurer;
19
43
  const viewBoxPadding = options.padding ?? 10;
20
44
  const round = makeRound(options.precision ?? 2);
45
+ const nodeDistance = options.nodeDistance;
21
46
  const primitives = [];
22
47
  const nodeIndex = /* @__PURE__ */ new Map();
23
48
  const allPoints = [];
24
49
  for (const child of ir.children) if (child.type === "node") {
25
- const layout = layoutNode(child, measureText, nodeIndex);
50
+ const layout = layoutNode(child, measureText, nodeIndex, nodeDistance);
26
51
  if (child.id) nodeIndex.set(child.id, layout);
27
52
  for (const prim of emitNodePrimitives(layout, round)) primitives.push(prim);
28
53
  allPoints.push(rect.anchor(layout.rect, "north-west"), rect.anchor(layout.rect, "north-east"), rect.anchor(layout.rect, "south-west"), rect.anchor(layout.rect, "south-east"));
54
+ } else if (child.type === "coordinate") {
55
+ const center = resolvePosition(child.position, nodeIndex, nodeDistance);
56
+ if (!center) throw new Error(`Cannot resolve position for coordinate ${child.id}; polar.origin or at.of may reference an undefined node`);
57
+ nodeIndex.set(child.id, coordinateAsLayout(child.id, center));
29
58
  }
30
59
  for (const child of ir.children) if (child.type === "path") {
31
- const result = emitPathPrimitive(child, nodeIndex, round);
60
+ const result = emitPathPrimitive(child, nodeIndex, round, measureText);
32
61
  if (result) {
33
- primitives.push(result.primitive);
62
+ for (const prim of result.primitives) primitives.push(prim);
34
63
  for (const p of result.points) allPoints.push(p);
35
64
  }
36
65
  }
@@ -1,6 +1,6 @@
1
1
  import { Position } from '../geometry/point';
2
2
  import { Rect, RectAnchor } from '../geometry/rect';
3
- import { IRNode, NodeShape } from '../ir';
3
+ import { AtDirection, IRNode, NodeShape } from '../ir';
4
4
  import { ScenePrimitive, TextLine } from '../primitive';
5
5
  import { TextMeasurer } from './text-metrics';
6
6
  export type NodeLayout = {
@@ -62,6 +62,27 @@ export type NodeLayout = {
62
62
  textColor?: string;
63
63
  /** 整节点透明度 0~1;emit 时同时挂 shape 与 text primitive */
64
64
  opacity?: number;
65
+ /**
66
+ * 已解析的 label 列表(IR 层 `Node.label` 标准化后)。每条 label 已合并:
67
+ * - position 默认 'above'
68
+ * - distance 默认 DEFAULT_LABEL_DISTANCE
69
+ * - font 字段从 Node 继承(family / size / weight / style 任一未填则取 Node 块级值)
70
+ */
71
+ labels?: Array<NodeLabelLayout>;
72
+ };
73
+ /** 节点附属标签的 layout——layoutNode 阶段已合并好默认值与样式继承 */
74
+ export type NodeLabelLayout = {
75
+ text: string;
76
+ /** 8 方向枚举或数字角度(与 IR 同形态) */
77
+ position: AtDirection | number;
78
+ /** 已应用默认值的距离 */
79
+ distance: number;
80
+ textColor?: string;
81
+ opacity?: number;
82
+ fontSize: number;
83
+ fontFamily?: string;
84
+ fontWeight?: string | number;
85
+ fontStyle?: 'normal' | 'italic' | 'oblique';
65
86
  };
66
87
  /**
67
88
  * 取节点 shape 在 toward 方向上的"附着点"——path 端点贴边用。
@@ -89,7 +110,7 @@ export declare const angleBoundaryOf: (layout: NodeLayout, angleDeg: number) =>
89
110
  * - IR 的 rotate(度数)转弧度存进 Rect.rotate
90
111
  * - 透传 margin / 样式属性
91
112
  */
92
- export declare const layoutNode: (node: IRNode, measureText: TextMeasurer, nodeIndex: Map<string, NodeLayout>) => NodeLayout;
113
+ export declare const layoutNode: (node: IRNode, measureText: TextMeasurer, nodeIndex: Map<string, NodeLayout>, nodeDistance?: number) => NodeLayout;
93
114
  /**
94
115
  * 把 NodeLayout 翻译为 Scene primitives:
95
116
  * - shape 主体:按 shape 分发(rect / ellipse / path)
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,KAAK,EAAc,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA8BnD,MAAM,MAAM,UAAU,GAAG;IACvB,2CAA2C;IAC3C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,KAAK,EAAE,SAAS,CAAC;IACjB;;;;;;;;OAQG;IACH,IAAI,EAAE,IAAI,CAAC;IACX,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAClC,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,sDAAsD;IACtD,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC5C,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAsCF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,UAAU,EAAE,QAAQ,QAAQ,KAAG,QAYtE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,UAAU,EAAE,MAAM,UAAU,KAAG,QAW/D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,UAAU,EAAE,UAAU,MAAM,KAAG,QActE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EACZ,aAAa,YAAY,EACzB,WAAW,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,KACjC,UAgJF,CAAC;AAsEF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,UAAU,EAClB,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,KAC3B,KAAK,CAAC,cAAc,CAoDtB,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,8 @@ var DEFAULT_FONT_SIZE = 14;
8
8
  var DEFAULT_PADDING = 8;
9
9
  var DEFAULT_LINE_HEIGHT_FACTOR = 1.2;
10
10
  var DEG_TO_RAD = Math.PI / 180;
11
+ /** Node label 与 node 边界的默认距离(user units);TikZ 默认是 0pt 但视觉上太贴 */
12
+ var DEFAULT_LABEL_DISTANCE = 4;
11
13
  var SQRT2 = Math.SQRT2;
12
14
  /** dashed 预设:SVG stroke-dasharray "4 2"——4 px 实线 + 2 px 间隙循环 */
13
15
  var DASHED_PATTERN = "4 2";
@@ -80,6 +82,59 @@ var anchorOf = (layout, name) => {
80
82
  }
81
83
  };
82
84
  /**
85
+ * 8 方向 label position → (anchorName, 单位向量) 映射。
86
+ * 视觉语义与 `at.direction` 一致——above 是视觉上方(y 减小)。
87
+ */
88
+ var LABEL_DIRECTION_MAP = {
89
+ above: {
90
+ anchor: "north",
91
+ vec: [0, -1]
92
+ },
93
+ below: {
94
+ anchor: "south",
95
+ vec: [0, 1]
96
+ },
97
+ left: {
98
+ anchor: "west",
99
+ vec: [-1, 0]
100
+ },
101
+ right: {
102
+ anchor: "east",
103
+ vec: [1, 0]
104
+ },
105
+ "above-left": {
106
+ anchor: "north-west",
107
+ vec: [-Math.SQRT1_2, -Math.SQRT1_2]
108
+ },
109
+ "above-right": {
110
+ anchor: "north-east",
111
+ vec: [Math.SQRT1_2, -Math.SQRT1_2]
112
+ },
113
+ "below-left": {
114
+ anchor: "south-west",
115
+ vec: [-Math.SQRT1_2, Math.SQRT1_2]
116
+ },
117
+ "below-right": {
118
+ anchor: "south-east",
119
+ vec: [Math.SQRT1_2, Math.SQRT1_2]
120
+ }
121
+ };
122
+ /**
123
+ * 算 label 中心点:
124
+ * - 8 方向:节点对应 anchor 出发,按单位向量 × distance 外推
125
+ * - 数字角度:先取 angleBoundary 边界点,再沿 (cos, sin) 单位向量 × distance 外推
126
+ */
127
+ var labelCenter = (layout, label) => {
128
+ if (typeof label.position === "number") {
129
+ const rad = label.position * Math.PI / 180;
130
+ const [bx, by] = angleBoundaryOf(layout, label.position);
131
+ return [bx + Math.cos(rad) * label.distance, by + Math.sin(rad) * label.distance];
132
+ }
133
+ const { anchor, vec } = LABEL_DIRECTION_MAP[label.position];
134
+ const [bx, by] = anchorOf(layout, anchor);
135
+ return [bx + vec[0] * label.distance, by + vec[1] * label.distance];
136
+ };
137
+ /**
83
138
  * 取节点 shape 在指定角度方向上的边界点。角度约定与 PolarPosition 一致(度数):
84
139
  * 0° = +x(east),90° = +y(screen 下方)。
85
140
  * **不应用 margin**——同 anchorOf。用于 `'A.30'` 这种语法落点。
@@ -102,7 +157,7 @@ var angleBoundaryOf = (layout, angleDeg) => {
102
157
  * - IR 的 rotate(度数)转弧度存进 Rect.rotate
103
158
  * - 透传 margin / 样式属性
104
159
  */
105
- var layoutNode = (node, measureText, nodeIndex) => {
160
+ var layoutNode = (node, measureText, nodeIndex, nodeDistance) => {
106
161
  const sx = node.xScale ?? node.scale ?? 1;
107
162
  const sy = node.yScale ?? node.scale ?? 1;
108
163
  const fontScale = Math.min(sx, sy);
@@ -173,8 +228,22 @@ var layoutNode = (node, measureText, nodeIndex) => {
173
228
  break;
174
229
  }
175
230
  const rotateDeg = node.rotate ?? 0;
176
- const center = resolvePosition(node.position, nodeIndex);
177
- if (!center) throw new Error(`Cannot resolve position for node ${node.id ?? "(unnamed)"}; polar.origin may reference an undefined node`);
231
+ const center = resolvePosition(node.position, nodeIndex, nodeDistance);
232
+ if (!center) throw new Error(`Cannot resolve position for node ${node.id ?? "(unnamed)"}; polar.origin or at.of may reference an undefined node`);
233
+ const labels = (node.label === void 0 ? void 0 : Array.isArray(node.label) ? node.label : [node.label])?.map((lab) => {
234
+ const labFont = lab.font;
235
+ return {
236
+ text: lab.text,
237
+ position: lab.position ?? "above",
238
+ distance: lab.distance ?? DEFAULT_LABEL_DISTANCE,
239
+ textColor: lab.textColor ?? node.textColor,
240
+ opacity: lab.opacity,
241
+ fontSize: (labFont?.size ?? baseFontSize) * fontScale,
242
+ fontFamily: labFont?.family ?? fontFamily,
243
+ fontWeight: labFont?.weight ?? fontWeight,
244
+ fontStyle: labFont?.style ?? fontStyle
245
+ };
246
+ });
178
247
  return {
179
248
  id: node.id,
180
249
  shape,
@@ -204,7 +273,8 @@ var layoutNode = (node, measureText, nodeIndex) => {
204
273
  strokeDasharray: resolveDashArray(node.dashArray, node.dashed, node.dotted),
205
274
  roundedCorners: node.roundedCorners,
206
275
  textColor: node.textColor,
207
- opacity: node.opacity
276
+ opacity: node.opacity,
277
+ labels
208
278
  };
209
279
  };
210
280
  /** rectangle shape 的 RectPrim */
@@ -305,6 +375,26 @@ var emitNodePrimitives = (layout, round) => {
305
375
  measuredHeight: round(layout.textHeight)
306
376
  });
307
377
  }
378
+ if (layout.labels) for (const lab of layout.labels) {
379
+ const [lx, ly] = labelCenter(layout, lab);
380
+ inner.push({
381
+ type: "text",
382
+ x: round(lx),
383
+ y: round(ly),
384
+ lines: [{ text: lab.text }],
385
+ fontSize: lab.fontSize,
386
+ fontFamily: lab.fontFamily,
387
+ fontWeight: lab.fontWeight,
388
+ fontStyle: lab.fontStyle,
389
+ align: "middle",
390
+ baseline: "middle",
391
+ lineHeight: round(lab.fontSize * DEFAULT_LINE_HEIGHT_FACTOR),
392
+ fill: lab.textColor ?? "currentColor",
393
+ opacity: lab.opacity ?? layout.opacity,
394
+ measuredWidth: 0,
395
+ measuredHeight: round(lab.fontSize)
396
+ });
397
+ }
308
398
  if (layout.rotateDeg === 0) return inner;
309
399
  return [{
310
400
  type: "group",
@@ -1,6 +1,7 @@
1
1
  import { IRPath, IRPosition } from '../ir';
2
2
  import { ScenePrimitive } from '../primitive';
3
3
  import { NodeLayout } from './node';
4
+ import { TextMeasurer } from './text-metrics';
4
5
  /**
5
6
  * 把 IR Path 翻译为单个 PathPrim。
6
7
  *
@@ -22,8 +23,8 @@ import { NodeLayout } from './node';
22
23
  *
23
24
  * 引用未定义节点 / 解析失败时返回 null(path 整体跳过)。
24
25
  */
25
- export declare const emitPathPrimitive: (path: IRPath, nodeIndex: Map<string, NodeLayout>, round: (n: number) => number) => {
26
- primitive: ScenePrimitive;
26
+ export declare const emitPathPrimitive: (path: IRPath, nodeIndex: Map<string, NodeLayout>, round: (n: number) => number, measureText?: TextMeasurer) => {
27
+ primitives: Array<ScenePrimitive>;
27
28
  points: Array<IRPosition>;
28
29
  } | null;
29
30
  //# sourceMappingURL=path.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/compile/path.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,MAAM,EAAE,UAAU,EAAoB,MAAM,OAAO,CAAC;AAC9E,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,KAAK,UAAU,EAA8C,MAAM,QAAQ,CAAC;AAuIrF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,WAAW,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAClC,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,KAC3B;IAAE,SAAS,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;CAAE,GAAG,IAsN7D,CAAC"}
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/compile/path.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAEV,MAAM,EACN,UAAU,EAIX,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAY,cAAc,EAAY,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,KAAK,UAAU,EAA8C,MAAM,QAAQ,CAAC;AAGrF,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AAoWrE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,WAAW,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAClC,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAC5B,cAAa,YAA+B,KAC3C;IAAE,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;CAAE,GAAG,IA8arE,CAAC"}