@retikz/core 0.1.0-alpha.5 → 0.1.0-beta.1
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 +17 -0
- package/dist/es/compile/compile.d.ts.map +1 -1
- package/dist/es/compile/compile.js +40 -15
- package/dist/es/compile/index.d.ts +1 -1
- package/dist/es/compile/index.d.ts.map +1 -1
- package/dist/es/compile/node.d.ts +3 -3
- package/dist/es/compile/node.d.ts.map +1 -1
- package/dist/es/compile/node.js +1 -1
- package/dist/es/compile/path/anchor.d.ts +19 -0
- package/dist/es/compile/path/anchor.d.ts.map +1 -0
- package/dist/es/compile/path/anchor.js +54 -0
- package/dist/es/compile/{path.d.ts → path/index.d.ts} +18 -7
- package/dist/es/compile/path/index.d.ts.map +1 -0
- package/dist/es/compile/path/index.js +308 -0
- package/dist/es/compile/path/label.d.ts +18 -0
- package/dist/es/compile/path/label.d.ts.map +1 -0
- package/dist/es/compile/path/label.js +102 -0
- package/dist/es/compile/path/relative.d.ts +8 -0
- package/dist/es/compile/path/relative.d.ts.map +1 -0
- package/dist/es/compile/path/relative.js +48 -0
- package/dist/es/compile/path/shrink.d.ts +24 -0
- package/dist/es/compile/path/shrink.d.ts.map +1 -0
- package/dist/es/compile/path/shrink.js +136 -0
- package/dist/es/compile/path/split.d.ts +15 -0
- package/dist/es/compile/path/split.d.ts.map +1 -0
- package/dist/es/compile/path/split.js +46 -0
- package/dist/es/compile/text-metrics.d.ts +4 -1
- package/dist/es/compile/text-metrics.d.ts.map +1 -1
- package/dist/es/compile/text-metrics.js +11 -5
- package/dist/es/geometry/_transform.d.ts +21 -0
- package/dist/es/geometry/_transform.d.ts.map +1 -0
- package/dist/es/geometry/_transform.js +27 -0
- package/dist/es/geometry/bend.d.ts +1 -1
- package/dist/es/geometry/bend.js +1 -1
- package/dist/es/geometry/circle.d.ts +2 -3
- package/dist/es/geometry/circle.d.ts.map +1 -1
- package/dist/es/geometry/circle.js +1 -16
- package/dist/es/geometry/diamond.d.ts +2 -3
- package/dist/es/geometry/diamond.d.ts.map +1 -1
- package/dist/es/geometry/diamond.js +1 -16
- package/dist/es/geometry/ellipse.d.ts +2 -3
- package/dist/es/geometry/ellipse.d.ts.map +1 -1
- package/dist/es/geometry/ellipse.js +1 -16
- package/dist/es/geometry/polar.d.ts +2 -2
- package/dist/es/geometry/polar.d.ts.map +1 -1
- package/dist/es/geometry/polar.js +2 -6
- package/dist/es/geometry/rect.d.ts.map +1 -1
- package/dist/es/geometry/rect.js +1 -18
- package/dist/es/geometry/segment.d.ts +5 -1
- package/dist/es/geometry/segment.d.ts.map +1 -1
- package/dist/es/index.d.ts +10 -6
- package/dist/es/index.d.ts.map +1 -1
- package/dist/es/index.js +4 -2
- package/dist/es/ir/font.d.ts +21 -0
- package/dist/es/ir/font.d.ts.map +1 -0
- package/dist/es/ir/font.js +15 -0
- package/dist/es/ir/index.d.ts +2 -0
- package/dist/es/ir/index.d.ts.map +1 -1
- package/dist/es/ir/node.d.ts +28 -139
- package/dist/es/ir/node.d.ts.map +1 -1
- package/dist/es/ir/node.js +6 -30
- package/dist/es/ir/path/arrow.d.ts +12 -12
- package/dist/es/ir/path/path.d.ts +16 -16
- package/dist/es/ir/path/path.js +4 -4
- package/dist/es/ir/path/step.d.ts +1 -1
- package/dist/es/ir/path/step.d.ts.map +1 -1
- package/dist/es/ir/path/step.js +8 -8
- package/dist/es/ir/position/offset-position.js +1 -1
- package/dist/es/ir/position/polar-position.d.ts.map +1 -1
- package/dist/es/ir/position/polar-position.js +2 -2
- package/dist/es/ir/position/position.d.ts.map +1 -1
- package/dist/es/ir/position/position.js +1 -1
- package/dist/es/ir/scene.d.ts +112 -112
- package/dist/es/ir/text.d.ts +96 -0
- package/dist/es/ir/text.d.ts.map +1 -0
- package/dist/es/ir/text.js +20 -0
- package/dist/es/parsers/parseTargetSugar.d.ts +4 -0
- package/dist/es/parsers/parseTargetSugar.d.ts.map +1 -1
- package/dist/es/parsers/parseTargetSugar.js +3 -2
- package/dist/es/primitive/ellipse.d.ts +2 -2
- package/dist/es/primitive/group.d.ts +23 -7
- package/dist/es/primitive/group.d.ts.map +1 -1
- package/dist/es/primitive/path.d.ts +51 -11
- package/dist/es/primitive/path.d.ts.map +1 -1
- package/dist/es/primitive/rect.d.ts +2 -2
- package/dist/es/primitive/rect.d.ts.map +1 -1
- package/dist/es/primitive/text.d.ts +10 -3
- package/dist/es/primitive/text.d.ts.map +1 -1
- package/dist/es/primitive/view-box.d.ts +1 -1
- package/dist/es/primitive/view-box.d.ts.map +1 -1
- package/dist/es/types.d.ts +8 -0
- package/dist/es/types.d.ts.map +1 -1
- package/dist/lib/compile/compile.cjs +40 -15
- package/dist/lib/compile/compile.d.ts +17 -0
- package/dist/lib/compile/compile.d.ts.map +1 -1
- package/dist/lib/compile/index.d.ts +1 -1
- package/dist/lib/compile/index.d.ts.map +1 -1
- package/dist/lib/compile/node.cjs +1 -1
- package/dist/lib/compile/node.d.ts +3 -3
- package/dist/lib/compile/node.d.ts.map +1 -1
- package/dist/lib/compile/path/anchor.cjs +58 -0
- package/dist/lib/compile/path/anchor.d.ts +19 -0
- package/dist/lib/compile/path/anchor.d.ts.map +1 -0
- package/dist/lib/compile/path/index.cjs +308 -0
- package/dist/lib/compile/{path.d.ts → path/index.d.ts} +18 -7
- package/dist/lib/compile/path/index.d.ts.map +1 -0
- package/dist/lib/compile/path/label.cjs +103 -0
- package/dist/lib/compile/path/label.d.ts +18 -0
- package/dist/lib/compile/path/label.d.ts.map +1 -0
- package/dist/lib/compile/path/relative.cjs +48 -0
- package/dist/lib/compile/path/relative.d.ts +8 -0
- package/dist/lib/compile/path/relative.d.ts.map +1 -0
- package/dist/lib/compile/path/shrink.cjs +138 -0
- package/dist/lib/compile/path/shrink.d.ts +24 -0
- package/dist/lib/compile/path/shrink.d.ts.map +1 -0
- package/dist/lib/compile/path/split.cjs +46 -0
- package/dist/lib/compile/path/split.d.ts +15 -0
- package/dist/lib/compile/path/split.d.ts.map +1 -0
- package/dist/lib/compile/text-metrics.cjs +11 -5
- package/dist/lib/compile/text-metrics.d.ts +4 -1
- package/dist/lib/compile/text-metrics.d.ts.map +1 -1
- package/dist/lib/geometry/_transform.cjs +28 -0
- package/dist/lib/geometry/_transform.d.ts +21 -0
- package/dist/lib/geometry/_transform.d.ts.map +1 -0
- package/dist/lib/geometry/bend.cjs +1 -1
- package/dist/lib/geometry/bend.d.ts +1 -1
- package/dist/lib/geometry/circle.cjs +5 -20
- package/dist/lib/geometry/circle.d.ts +2 -3
- package/dist/lib/geometry/circle.d.ts.map +1 -1
- package/dist/lib/geometry/diamond.cjs +5 -20
- package/dist/lib/geometry/diamond.d.ts +2 -3
- package/dist/lib/geometry/diamond.d.ts.map +1 -1
- package/dist/lib/geometry/ellipse.cjs +5 -20
- package/dist/lib/geometry/ellipse.d.ts +2 -3
- package/dist/lib/geometry/ellipse.d.ts.map +1 -1
- package/dist/lib/geometry/polar.cjs +2 -6
- package/dist/lib/geometry/polar.d.ts +2 -2
- package/dist/lib/geometry/polar.d.ts.map +1 -1
- package/dist/lib/geometry/rect.cjs +5 -22
- package/dist/lib/geometry/rect.d.ts.map +1 -1
- package/dist/lib/geometry/segment.d.ts +5 -1
- package/dist/lib/geometry/segment.d.ts.map +1 -1
- package/dist/lib/index.cjs +5 -3
- package/dist/lib/index.d.ts +10 -6
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/ir/font.cjs +15 -0
- package/dist/lib/ir/font.d.ts +21 -0
- package/dist/lib/ir/font.d.ts.map +1 -0
- package/dist/lib/ir/index.d.ts +2 -0
- package/dist/lib/ir/index.d.ts.map +1 -1
- package/dist/lib/ir/node.cjs +7 -34
- package/dist/lib/ir/node.d.ts +28 -139
- package/dist/lib/ir/node.d.ts.map +1 -1
- package/dist/lib/ir/path/arrow.d.ts +12 -12
- package/dist/lib/ir/path/path.cjs +4 -4
- package/dist/lib/ir/path/path.d.ts +16 -16
- package/dist/lib/ir/path/step.cjs +8 -8
- package/dist/lib/ir/path/step.d.ts +1 -1
- package/dist/lib/ir/path/step.d.ts.map +1 -1
- package/dist/lib/ir/position/offset-position.cjs +1 -1
- package/dist/lib/ir/position/polar-position.cjs +2 -2
- package/dist/lib/ir/position/polar-position.d.ts.map +1 -1
- package/dist/lib/ir/position/position.cjs +1 -1
- package/dist/lib/ir/position/position.d.ts.map +1 -1
- package/dist/lib/ir/scene.d.ts +112 -112
- package/dist/lib/ir/text.cjs +21 -0
- package/dist/lib/ir/text.d.ts +96 -0
- package/dist/lib/ir/text.d.ts.map +1 -0
- package/dist/lib/parsers/parseTargetSugar.cjs +3 -2
- package/dist/lib/parsers/parseTargetSugar.d.ts +4 -0
- package/dist/lib/parsers/parseTargetSugar.d.ts.map +1 -1
- package/dist/lib/primitive/ellipse.d.ts +2 -2
- package/dist/lib/primitive/group.d.ts +23 -7
- package/dist/lib/primitive/group.d.ts.map +1 -1
- package/dist/lib/primitive/path.d.ts +51 -11
- package/dist/lib/primitive/path.d.ts.map +1 -1
- package/dist/lib/primitive/rect.d.ts +2 -2
- package/dist/lib/primitive/rect.d.ts.map +1 -1
- package/dist/lib/primitive/text.d.ts +10 -3
- package/dist/lib/primitive/text.d.ts.map +1 -1
- package/dist/lib/primitive/view-box.d.ts +1 -1
- package/dist/lib/primitive/view-box.d.ts.map +1 -1
- package/dist/lib/types.d.ts +8 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/package.json +13 -4
- package/dist/es/compile/path.d.ts.map +0 -1
- package/dist/es/compile/path.js +0 -636
- package/dist/lib/compile/path.cjs +0 -636
- package/dist/lib/compile/path.d.ts.map +0 -1
|
@@ -1,636 +0,0 @@
|
|
|
1
|
-
const require_arrow = require("../ir/path/arrow.cjs");
|
|
2
|
-
const require_position = require("./position.cjs");
|
|
3
|
-
const require_node = require("./node.cjs");
|
|
4
|
-
const require_arc = require("../geometry/arc.cjs");
|
|
5
|
-
const require_bend = require("../geometry/bend.cjs");
|
|
6
|
-
const require_segment = require("../geometry/segment.cjs");
|
|
7
|
-
const require_parseTarget = require("./parseTarget.cjs");
|
|
8
|
-
const require_text_metrics = require("./text-metrics.cjs");
|
|
9
|
-
//#region src/compile/path.ts
|
|
10
|
-
/**
|
|
11
|
-
* 端点级 spec:顶层默认 ⊕ end-side override(逐字段 merge)
|
|
12
|
-
* @description 缺省字段继承顶层(不是"完全替换");空心 shape 上 fill 字段被丢(silent no-op)
|
|
13
|
-
*/
|
|
14
|
-
var resolveArrowEndSpec = (topLevel, endSide) => {
|
|
15
|
-
const baseShape = endSide?.shape ?? topLevel.shape ?? "normal";
|
|
16
|
-
const out = { shape: baseShape };
|
|
17
|
-
const scale = endSide?.scale ?? topLevel.scale;
|
|
18
|
-
if (scale !== void 0) out.scale = scale;
|
|
19
|
-
const length = endSide?.length ?? topLevel.length;
|
|
20
|
-
if (length !== void 0) out.length = length;
|
|
21
|
-
const width = endSide?.width ?? topLevel.width;
|
|
22
|
-
if (width !== void 0) out.width = width;
|
|
23
|
-
const color = endSide?.color ?? topLevel.color;
|
|
24
|
-
if (color !== void 0) out.color = color;
|
|
25
|
-
const opacity = endSide?.opacity ?? topLevel.opacity;
|
|
26
|
-
if (opacity !== void 0) out.opacity = opacity;
|
|
27
|
-
const lineWidth = endSide?.lineWidth ?? topLevel.lineWidth;
|
|
28
|
-
if (lineWidth !== void 0) out.lineWidth = lineWidth;
|
|
29
|
-
if (!require_arrow.HOLLOW_ARROW_SHAPES.has(baseShape)) {
|
|
30
|
-
const fill = endSide?.fill ?? topLevel.fill;
|
|
31
|
-
if (fill !== void 0) out.fill = fill;
|
|
32
|
-
}
|
|
33
|
-
return out;
|
|
34
|
-
};
|
|
35
|
-
/** IR path-level `arrow` + `arrowDetail` → PathPrim 起末视觉规格 */
|
|
36
|
-
var arrowMarkers = (arrow, detail) => {
|
|
37
|
-
if (!arrow || arrow === "none") return {};
|
|
38
|
-
const top = detail ?? {};
|
|
39
|
-
const startSpec = resolveArrowEndSpec(top, top.start);
|
|
40
|
-
const endSpec = resolveArrowEndSpec(top, top.end);
|
|
41
|
-
switch (arrow) {
|
|
42
|
-
case "->": return { arrowEnd: endSpec };
|
|
43
|
-
case "<-": return { arrowStart: startSpec };
|
|
44
|
-
case "<->": return {
|
|
45
|
-
arrowStart: startSpec,
|
|
46
|
-
arrowEnd: endSpec
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
/**
|
|
51
|
-
* 端点级 shrink(strokeWidth 倍):line 末端朝起点缩这么多,让 marker apex 落回原 target
|
|
52
|
-
* @description 不分实心/空心:所有 shape 都让 line 端点接在箭头尾部、apex 顶端仍贴原 target。低 opacity 下不会再透出 line。viewBox=10,shrink = (apex.x - refX) × length × scale / 10(strokeWidth 倍)。
|
|
53
|
-
*
|
|
54
|
-
* 几何对齐(必须与 react/render/arrowMarkers.tsx 中 renderInner 的 refX 一致):
|
|
55
|
-
* - `normal` / `diamond` / `circle`:apex 在 viewBox x=10、back 外缘 x=0 → refX=0,shrink = length × scale
|
|
56
|
-
* - `stealth`:apex x=10、V tip x=3(line 嵌进 V 凹口)→ refX=3,shrink = 0.7 × length × scale
|
|
57
|
-
* - `open` / `openDiamond`:apex x=9、back stroke 外缘 x = 1 - lineWidth/2 → refX = 1 - lineWidth/2,shrink = (8 + lineWidth/2) × length × scale / 10
|
|
58
|
-
* - `openCircle`:apex 外缘右 x ≈ 10、back 外缘左 x = 0.75 - lineWidth/2 → refX = 0.75 - lineWidth/2,shrink ≈ length × scale
|
|
59
|
-
*/
|
|
60
|
-
var computeShrink = (spec) => {
|
|
61
|
-
const length = (spec.length ?? 6) * (spec.scale ?? 1);
|
|
62
|
-
if (require_arrow.HOLLOW_ARROW_SHAPES.has(spec.shape)) {
|
|
63
|
-
if (spec.shape === "openCircle") return length;
|
|
64
|
-
return (8 + (spec.lineWidth ?? 1.5) / 2) * length / 10;
|
|
65
|
-
}
|
|
66
|
-
if (spec.shape === "stealth") return 7 * length / 10;
|
|
67
|
-
return length;
|
|
68
|
-
};
|
|
69
|
-
/** 把 p 朝 target 方向移动 dist */
|
|
70
|
-
var shiftToward = (p, target, dist) => {
|
|
71
|
-
const dx = target[0] - p[0];
|
|
72
|
-
const dy = target[1] - p[1];
|
|
73
|
-
const len = Math.sqrt(dx * dx + dy * dy);
|
|
74
|
-
if (len === 0 || dist === 0) return p;
|
|
75
|
-
return [p[0] + dx / len * dist, p[1] + dy / len * dist];
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* 求 step.to 的参考点(给 boundary clip 算方向 / 折角 corner 用)
|
|
79
|
-
* @description 三态:`'A'`(auto) 节点中心;`'A.<anchor>'`/`'A.<deg>'` 显式锚点 refPoint=endpoint 位置不随邻居变。直接坐标/极坐标解析为笛卡尔
|
|
80
|
-
*/
|
|
81
|
-
var refPointOfTarget = (target, nodeIndex) => {
|
|
82
|
-
if (typeof target === "string") {
|
|
83
|
-
const ref = require_parseTarget.parseNodeRef(target);
|
|
84
|
-
const node = nodeIndex.get(ref.id);
|
|
85
|
-
if (!node) return null;
|
|
86
|
-
switch (ref.kind) {
|
|
87
|
-
case "node": return [node.rect.x, node.rect.y];
|
|
88
|
-
case "anchor": return require_node.anchorOf(node, ref.anchor);
|
|
89
|
-
case "angle": return require_node.angleBoundaryOf(node, ref.angle);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (typeof target === "object" && !Array.isArray(target) && ("relative" in target || "relativeAccumulate" in target)) return null;
|
|
93
|
-
return require_position.resolvePosition(target, nodeIndex);
|
|
94
|
-
};
|
|
95
|
-
/** 折角中间点:`-|` → (curr.x, prev.y);`|-` → (prev.x, curr.y) */
|
|
96
|
-
var cornerOf = (prev, curr, via) => via === "-|" ? [curr[0], prev[1]] : [prev[0], curr[1]];
|
|
97
|
-
/**
|
|
98
|
-
* 在 toward 方向算 step.to 的实际绘制端点
|
|
99
|
-
* @description 节点 auto `'A'`:按 shape 走 boundaryPointOf 求中心→toward 射线交点;命名 anchor/角度:位置已定不受 toward 影响;直接坐标/极坐标:解析后返回;失败返回 null
|
|
100
|
-
*/
|
|
101
|
-
var clipForTarget = (target, toward, nodeIndex) => {
|
|
102
|
-
if (typeof target === "string") {
|
|
103
|
-
const ref = require_parseTarget.parseNodeRef(target);
|
|
104
|
-
const node = nodeIndex.get(ref.id);
|
|
105
|
-
if (!node) return null;
|
|
106
|
-
switch (ref.kind) {
|
|
107
|
-
case "node": return require_node.boundaryPointOf(node, toward);
|
|
108
|
-
case "anchor": return require_node.anchorOf(node, ref.anchor);
|
|
109
|
-
case "angle": return require_node.angleBoundaryOf(node, ref.angle);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (typeof target === "object" && !Array.isArray(target) && ("relative" in target || "relativeAccumulate" in target)) return null;
|
|
113
|
-
return require_position.resolvePosition(target, nodeIndex);
|
|
114
|
-
};
|
|
115
|
-
/** 两个 IRPosition 两分量精确相等(未 round) */
|
|
116
|
-
var samePoint = (a, b) => !!a && !!b && a[0] === b[0] && a[1] === b[1];
|
|
117
|
-
/**
|
|
118
|
-
* 语义 stroke 档位 → 数值(user units)
|
|
119
|
-
* @description 对齐 TikZ 比例(thin=0.4pt→1=默认 strokeWidth):ultraThin 0.25、veryThin 0.5、thin 1、semithick 1.5、thick 2、veryThick 3、ultraThick 4。显式 strokeWidth 覆盖 thickness
|
|
120
|
-
*/
|
|
121
|
-
var THICKNESS_TO_WIDTH = {
|
|
122
|
-
ultraThin: .25,
|
|
123
|
-
veryThin: .5,
|
|
124
|
-
thin: 1,
|
|
125
|
-
semithick: 1.5,
|
|
126
|
-
thick: 2,
|
|
127
|
-
veryThick: 3,
|
|
128
|
-
ultraThick: 4
|
|
129
|
-
};
|
|
130
|
-
/** 边标注默认字号 / 偏移量 */
|
|
131
|
-
var LABEL_FONT_SIZE = 14;
|
|
132
|
-
var LABEL_LINE_HEIGHT_FACTOR = 1.2;
|
|
133
|
-
var LABEL_SIDE_OFFSET = 4;
|
|
134
|
-
var RAD_TO_DEG = 180 / Math.PI;
|
|
135
|
-
/** keyword → t 数值映射;含旧 3 keyword(midway/near-start/near-end)+ 新 4 keyword */
|
|
136
|
-
var KEYWORD_TO_T = {
|
|
137
|
-
"at-start": 0,
|
|
138
|
-
"very-near-start": .125,
|
|
139
|
-
"near-start": .25,
|
|
140
|
-
midway: .5,
|
|
141
|
-
"near-end": .75,
|
|
142
|
-
"very-near-end": .875,
|
|
143
|
-
"at-end": 1
|
|
144
|
-
};
|
|
145
|
-
/**
|
|
146
|
-
* label.position → 段参数 t∈[0,1]
|
|
147
|
-
* @description 数值原样返回(schema 已 clamp 0..1);keyword 走 KEYWORD_TO_T 映射;undefined 退默认 midway (0.5)
|
|
148
|
-
*/
|
|
149
|
-
var tForLabelPosition = (pos) => {
|
|
150
|
-
if (typeof pos === "number") return pos;
|
|
151
|
-
if (typeof pos === "string" && pos in KEYWORD_TO_T) return KEYWORD_TO_T[pos];
|
|
152
|
-
return .5;
|
|
153
|
-
};
|
|
154
|
-
/**
|
|
155
|
-
* step.label + 段采样 → TextPrim(sloped 时裹一层 group 旋转)
|
|
156
|
-
* @description 默认 side='above'/position='midway':above/below 锚点 y±offset、align=middle、baseline=bottom/top;left/right x±offset、align=end/start、baseline=middle;sloped 不偏移裹 group rotate(angle, cx, cy) 由切线 atan2 算(SVG y-down CW 正)。返回 primitive + viewBox 外接点
|
|
157
|
-
*/
|
|
158
|
-
var emitLabelPrimitive = (label, sample, measureText, round) => {
|
|
159
|
-
const fontSize = LABEL_FONT_SIZE;
|
|
160
|
-
const lineHeight = fontSize * LABEL_LINE_HEIGHT_FACTOR;
|
|
161
|
-
const m = measureText(label.text, { size: fontSize });
|
|
162
|
-
const measuredWidth = m.width;
|
|
163
|
-
const measuredHeight = m.height || lineHeight;
|
|
164
|
-
const side = label.side ?? "above";
|
|
165
|
-
let x = sample.point[0];
|
|
166
|
-
let y = sample.point[1];
|
|
167
|
-
let align = "middle";
|
|
168
|
-
let baseline = "middle";
|
|
169
|
-
if (side === "above") {
|
|
170
|
-
y -= LABEL_SIDE_OFFSET;
|
|
171
|
-
baseline = "bottom";
|
|
172
|
-
} else if (side === "below") {
|
|
173
|
-
y += LABEL_SIDE_OFFSET;
|
|
174
|
-
baseline = "top";
|
|
175
|
-
} else if (side === "left") {
|
|
176
|
-
x -= LABEL_SIDE_OFFSET;
|
|
177
|
-
align = "end";
|
|
178
|
-
} else if (side === "right") {
|
|
179
|
-
x += LABEL_SIDE_OFFSET;
|
|
180
|
-
align = "start";
|
|
181
|
-
} else baseline = "bottom";
|
|
182
|
-
const text = {
|
|
183
|
-
type: "text",
|
|
184
|
-
x: round(x),
|
|
185
|
-
y: round(y),
|
|
186
|
-
lines: [{ text: label.text }],
|
|
187
|
-
fontSize,
|
|
188
|
-
align,
|
|
189
|
-
baseline,
|
|
190
|
-
lineHeight: round(lineHeight),
|
|
191
|
-
measuredWidth: round(measuredWidth),
|
|
192
|
-
measuredHeight: round(measuredHeight),
|
|
193
|
-
fill: "currentColor"
|
|
194
|
-
};
|
|
195
|
-
if (side === "sloped") {
|
|
196
|
-
const groupPrim = {
|
|
197
|
-
type: "group",
|
|
198
|
-
transforms: [{
|
|
199
|
-
kind: "rotate",
|
|
200
|
-
degrees: round(Math.atan2(sample.tangent[1], sample.tangent[0]) * RAD_TO_DEG),
|
|
201
|
-
cx: round(x),
|
|
202
|
-
cy: round(y)
|
|
203
|
-
}],
|
|
204
|
-
children: [text]
|
|
205
|
-
};
|
|
206
|
-
const r = Math.max(measuredWidth / 2, measuredHeight / 2);
|
|
207
|
-
return {
|
|
208
|
-
primitive: groupPrim,
|
|
209
|
-
points: [
|
|
210
|
-
[x - r, y - r],
|
|
211
|
-
[x + r, y - r],
|
|
212
|
-
[x - r, y + r],
|
|
213
|
-
[x + r, y + r]
|
|
214
|
-
]
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
const halfW = measuredWidth / 2;
|
|
218
|
-
const halfH = measuredHeight / 2;
|
|
219
|
-
return {
|
|
220
|
-
primitive: text,
|
|
221
|
-
points: [
|
|
222
|
-
[x - halfW, y - halfH],
|
|
223
|
-
[x + halfW, y - halfH],
|
|
224
|
-
[x - halfW, y + halfH],
|
|
225
|
-
[x + halfW, y + halfH]
|
|
226
|
-
]
|
|
227
|
-
};
|
|
228
|
-
};
|
|
229
|
-
/**
|
|
230
|
-
* relative/relativeAccumulate 目标解析为绝对 Position(step kind 不变,to 全为绝对坐标)
|
|
231
|
-
* @description relative 不更新 prevEnd(TikZ `+`),relativeAccumulate 更新(TikZ `++`)。prevEnd 推进:有 to 的 kind 用 refPointOfTarget(to);arc 用 arcEndPoint;circlePath/ellipsePath/cycle 不变。首步 relative 时 prevEnd 回退 [0,0];解析失败保持原 step
|
|
232
|
-
*/
|
|
233
|
-
var normalizeRelativeTargets = (steps, nodeIndex) => {
|
|
234
|
-
let prevEnd = null;
|
|
235
|
-
const out = [];
|
|
236
|
-
for (const step of steps) {
|
|
237
|
-
if (step.kind === "cycle") {
|
|
238
|
-
out.push(step);
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
|
-
if (step.kind === "circlePath" || step.kind === "ellipsePath") {
|
|
242
|
-
out.push(step);
|
|
243
|
-
continue;
|
|
244
|
-
}
|
|
245
|
-
if (step.kind === "arc") {
|
|
246
|
-
out.push(step);
|
|
247
|
-
if (prevEnd) prevEnd = require_arc.arcEndPoint(prevEnd, step.radius, step.endAngle);
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
const original = step.to;
|
|
251
|
-
let resolvedTo = original;
|
|
252
|
-
let updatePrevEnd = true;
|
|
253
|
-
if (typeof original === "object" && !Array.isArray(original) && "relative" in original) {
|
|
254
|
-
const ref = prevEnd ?? [0, 0];
|
|
255
|
-
resolvedTo = [ref[0] + original.relative[0], ref[1] + original.relative[1]];
|
|
256
|
-
updatePrevEnd = false;
|
|
257
|
-
} else if (typeof original === "object" && !Array.isArray(original) && "relativeAccumulate" in original) {
|
|
258
|
-
const ref = prevEnd ?? [0, 0];
|
|
259
|
-
resolvedTo = [ref[0] + original.relativeAccumulate[0], ref[1] + original.relativeAccumulate[1]];
|
|
260
|
-
}
|
|
261
|
-
out.push({
|
|
262
|
-
...step,
|
|
263
|
-
to: resolvedTo
|
|
264
|
-
});
|
|
265
|
-
if (updatePrevEnd) {
|
|
266
|
-
const pos = refPointOfTarget(resolvedTo, nodeIndex);
|
|
267
|
-
if (pos) prevEnd = pos;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return out;
|
|
271
|
-
};
|
|
272
|
-
/**
|
|
273
|
-
* IR Path → PathPrim
|
|
274
|
-
* @description 每个绘制段独立用节点中心算两端 boundary clip——中段节点的入/出 boundary 点通常不同,path 在该节点可见"断开"(与 TikZ `\draw (A)--(B)--(C);` 段独立 clip 一致)。仍产一个 PathPrim:commands 用多组 move/line 表达 sub-path;段起点等于上段终点时复用 cursor 省 move。cycle 段闭回最近 move 起点,起点==lastEnd && 终点==subPathStart 时输出 close,否则显式画段 line。引用未定义节点/解析失败返回 null
|
|
275
|
-
*/
|
|
276
|
-
var emitPathPrimitive = (path, nodeIndex, round, measureText = require_text_metrics.fallbackMeasurer) => {
|
|
277
|
-
const steps = normalizeRelativeTargets(path.children, nodeIndex);
|
|
278
|
-
if (steps.length < 2) return null;
|
|
279
|
-
/** 每段 step.label 翻译出的 TextPrim(或 sloped 旋转的 group),与 path 主体同级返回 */
|
|
280
|
-
const labelPrims = [];
|
|
281
|
-
/** 算 sample 后 emitLabelPrimitive,结果累积到 labelPrims/points */
|
|
282
|
-
const collectLabel = (step, sampleAt) => {
|
|
283
|
-
if (step.kind === "move" || step.kind === "cycle" || !("label" in step) || !step.label) return;
|
|
284
|
-
const sample = sampleAt(tForLabelPosition(step.label.position));
|
|
285
|
-
const r = emitLabelPrimitive(step.label, sample, measureText, round);
|
|
286
|
-
labelPrims.push(r.primitive);
|
|
287
|
-
for (const p of r.points) points.push(p);
|
|
288
|
-
};
|
|
289
|
-
const hasTo = (s) => s.kind !== "cycle" && s.kind !== "arc" && s.kind !== "circlePath" && s.kind !== "ellipsePath";
|
|
290
|
-
const anchors = steps.map((s) => hasTo(s) ? refPointOfTarget(s.to, nodeIndex) : null);
|
|
291
|
-
/** 找 i 之前最近的"有 to 字段的 step" 及其 anchor */
|
|
292
|
-
const findPrev = (i) => {
|
|
293
|
-
for (let j = i - 1; j >= 0; j--) {
|
|
294
|
-
const s = steps[j];
|
|
295
|
-
if (!hasTo(s)) continue;
|
|
296
|
-
const a = anchors[j];
|
|
297
|
-
if (!a) return null;
|
|
298
|
-
return {
|
|
299
|
-
step: s,
|
|
300
|
-
anchor: a
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
return null;
|
|
304
|
-
};
|
|
305
|
-
/** 找 i 之前最近的 move 的 to,cycle 闭合的目标 */
|
|
306
|
-
const findRecentMoveTo = (i) => {
|
|
307
|
-
for (let j = i - 1; j >= 0; j--) {
|
|
308
|
-
const s = steps[j];
|
|
309
|
-
if (s.kind === "move") return s.to;
|
|
310
|
-
}
|
|
311
|
-
return null;
|
|
312
|
-
};
|
|
313
|
-
const commands = [];
|
|
314
|
-
const points = [];
|
|
315
|
-
let lastEnd = null;
|
|
316
|
-
let subPathStart = null;
|
|
317
|
-
/**
|
|
318
|
-
* 笔位覆盖:arc/circlePath/ellipsePath 无 `to` 字段不能用 prev.step.to 重算起点
|
|
319
|
-
* @description 设置 penOverride 让下个绘制段直接用此点当 fromClip 后清空。arc=弧终点;circlePath/ellipsePath=center("画完留在圆心")
|
|
320
|
-
*/
|
|
321
|
-
let penOverride = null;
|
|
322
|
-
const roundPoint = (p) => [round(p[0]), round(p[1])];
|
|
323
|
-
const emitMove = (p) => {
|
|
324
|
-
const rp = roundPoint(p);
|
|
325
|
-
commands.push({
|
|
326
|
-
kind: "move",
|
|
327
|
-
to: [rp[0], rp[1]]
|
|
328
|
-
});
|
|
329
|
-
points.push(p);
|
|
330
|
-
subPathStart = p;
|
|
331
|
-
lastEnd = p;
|
|
332
|
-
};
|
|
333
|
-
const emitLine = (p) => {
|
|
334
|
-
const rp = roundPoint(p);
|
|
335
|
-
commands.push({
|
|
336
|
-
kind: "line",
|
|
337
|
-
to: [rp[0], rp[1]]
|
|
338
|
-
});
|
|
339
|
-
points.push(p);
|
|
340
|
-
lastEnd = p;
|
|
341
|
-
};
|
|
342
|
-
const emitClose = () => {
|
|
343
|
-
commands.push({ kind: "close" });
|
|
344
|
-
lastEnd = subPathStart;
|
|
345
|
-
};
|
|
346
|
-
const emitQuad = (control, p) => {
|
|
347
|
-
const rc = roundPoint(control);
|
|
348
|
-
const rp = roundPoint(p);
|
|
349
|
-
commands.push({
|
|
350
|
-
kind: "quad",
|
|
351
|
-
control: [rc[0], rc[1]],
|
|
352
|
-
to: [rp[0], rp[1]]
|
|
353
|
-
});
|
|
354
|
-
points.push(control);
|
|
355
|
-
points.push(p);
|
|
356
|
-
lastEnd = p;
|
|
357
|
-
};
|
|
358
|
-
const emitCubic = (c1, c2, p) => {
|
|
359
|
-
const rc1 = roundPoint(c1);
|
|
360
|
-
const rc2 = roundPoint(c2);
|
|
361
|
-
const rp = roundPoint(p);
|
|
362
|
-
commands.push({
|
|
363
|
-
kind: "cubic",
|
|
364
|
-
control1: [rc1[0], rc1[1]],
|
|
365
|
-
control2: [rc2[0], rc2[1]],
|
|
366
|
-
to: [rp[0], rp[1]]
|
|
367
|
-
});
|
|
368
|
-
points.push(c1);
|
|
369
|
-
points.push(c2);
|
|
370
|
-
points.push(p);
|
|
371
|
-
lastEnd = p;
|
|
372
|
-
};
|
|
373
|
-
const emitArc = (center, radius, startAngle, endAngle) => {
|
|
374
|
-
const rc = roundPoint(center);
|
|
375
|
-
commands.push({
|
|
376
|
-
kind: "arc",
|
|
377
|
-
center: [rc[0], rc[1]],
|
|
378
|
-
radius: round(radius),
|
|
379
|
-
startAngle,
|
|
380
|
-
endAngle
|
|
381
|
-
});
|
|
382
|
-
points.push(require_arc.arcEndPoint(center, radius, endAngle));
|
|
383
|
-
lastEnd = require_arc.arcEndPoint(center, radius, endAngle);
|
|
384
|
-
};
|
|
385
|
-
const emitEllipseArc = (center, radiusX, radiusY, startAngle, endAngle) => {
|
|
386
|
-
const rc = roundPoint(center);
|
|
387
|
-
commands.push({
|
|
388
|
-
kind: "ellipseArc",
|
|
389
|
-
center: [rc[0], rc[1]],
|
|
390
|
-
radiusX: round(radiusX),
|
|
391
|
-
radiusY: round(radiusY),
|
|
392
|
-
startAngle,
|
|
393
|
-
endAngle
|
|
394
|
-
});
|
|
395
|
-
const endPt = [center[0] + Math.cos(endAngle * Math.PI / 180) * radiusX, center[1] + Math.sin(endAngle * Math.PI / 180) * radiusY];
|
|
396
|
-
points.push(endPt);
|
|
397
|
-
lastEnd = endPt;
|
|
398
|
-
};
|
|
399
|
-
/** 段起点:与 lastEnd 相同则复用 cursor(省 move),否则发 move */
|
|
400
|
-
const startSegment = (p) => {
|
|
401
|
-
if (samePoint(p, lastEnd)) return;
|
|
402
|
-
emitMove(p);
|
|
403
|
-
};
|
|
404
|
-
for (let i = 0; i < steps.length; i++) {
|
|
405
|
-
const step = steps[i];
|
|
406
|
-
if (step.kind === "move") continue;
|
|
407
|
-
if (step.kind === "cycle") {
|
|
408
|
-
const moveTo = findRecentMoveTo(i);
|
|
409
|
-
const prev = findPrev(i);
|
|
410
|
-
if (!moveTo || !prev) continue;
|
|
411
|
-
const moveAnchor = refPointOfTarget(moveTo, nodeIndex);
|
|
412
|
-
if (!moveAnchor) return null;
|
|
413
|
-
const fromClip = clipForTarget(prev.step.to, moveAnchor, nodeIndex);
|
|
414
|
-
const toClip = clipForTarget(moveTo, prev.anchor, nodeIndex);
|
|
415
|
-
if (!fromClip || !toClip) return null;
|
|
416
|
-
if (samePoint(fromClip, lastEnd) && samePoint(toClip, subPathStart)) {
|
|
417
|
-
emitClose();
|
|
418
|
-
continue;
|
|
419
|
-
}
|
|
420
|
-
startSegment(fromClip);
|
|
421
|
-
emitLine(toClip);
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
424
|
-
const prev = findPrev(i);
|
|
425
|
-
if (!prev) return null;
|
|
426
|
-
if (step.kind === "arc") {
|
|
427
|
-
const center = prev.anchor;
|
|
428
|
-
const startPt = require_arc.arcEndPoint(center, step.radius, step.startAngle);
|
|
429
|
-
const endPt = require_arc.arcEndPoint(center, step.radius, step.endAngle);
|
|
430
|
-
startSegment(startPt);
|
|
431
|
-
emitArc(center, step.radius, step.startAngle, step.endAngle);
|
|
432
|
-
for (const p of require_arc.arcBoundingPoints(center, step.radius, step.startAngle, step.endAngle)) points.push(p);
|
|
433
|
-
collectLabel(step, (t) => require_segment.arcSegmentSample(center, step.radius, step.startAngle, step.endAngle, t));
|
|
434
|
-
penOverride = endPt;
|
|
435
|
-
continue;
|
|
436
|
-
}
|
|
437
|
-
if (step.kind === "circlePath") {
|
|
438
|
-
const center = prev.anchor;
|
|
439
|
-
const r = step.radius;
|
|
440
|
-
startSegment([center[0] + r, center[1]]);
|
|
441
|
-
emitEllipseArc(center, r, r, 0, 360);
|
|
442
|
-
points.push([center[0] + r, center[1]]);
|
|
443
|
-
points.push([center[0] - r, center[1]]);
|
|
444
|
-
points.push([center[0], center[1] + r]);
|
|
445
|
-
points.push([center[0], center[1] - r]);
|
|
446
|
-
collectLabel(step, (t) => require_segment.circleSegmentSample(center, r, t));
|
|
447
|
-
penOverride = center;
|
|
448
|
-
continue;
|
|
449
|
-
}
|
|
450
|
-
if (step.kind === "ellipsePath") {
|
|
451
|
-
const center = prev.anchor;
|
|
452
|
-
const rx = step.radiusX;
|
|
453
|
-
const ry = step.radiusY;
|
|
454
|
-
startSegment([center[0] + rx, center[1]]);
|
|
455
|
-
emitEllipseArc(center, rx, ry, 0, 360);
|
|
456
|
-
points.push([center[0] + rx, center[1]]);
|
|
457
|
-
points.push([center[0] - rx, center[1]]);
|
|
458
|
-
points.push([center[0], center[1] + ry]);
|
|
459
|
-
points.push([center[0], center[1] - ry]);
|
|
460
|
-
collectLabel(step, (t) => require_segment.ellipseSegmentSample(center, rx, ry, t));
|
|
461
|
-
penOverride = center;
|
|
462
|
-
continue;
|
|
463
|
-
}
|
|
464
|
-
const currAnchor = anchors[i];
|
|
465
|
-
if (!currAnchor) return null;
|
|
466
|
-
const usedOverride = penOverride;
|
|
467
|
-
penOverride = null;
|
|
468
|
-
if (step.kind === "line") {
|
|
469
|
-
const fromClip = usedOverride ?? clipForTarget(prev.step.to, currAnchor, nodeIndex);
|
|
470
|
-
const toClip = clipForTarget(step.to, prev.anchor, nodeIndex);
|
|
471
|
-
if (!fromClip || !toClip) return null;
|
|
472
|
-
startSegment(fromClip);
|
|
473
|
-
emitLine(toClip);
|
|
474
|
-
collectLabel(step, (t) => require_segment.lineSegmentSample(fromClip, toClip, t));
|
|
475
|
-
continue;
|
|
476
|
-
}
|
|
477
|
-
if (step.kind === "curve") {
|
|
478
|
-
const fromClip = usedOverride ?? clipForTarget(prev.step.to, step.control, nodeIndex);
|
|
479
|
-
const toClip = clipForTarget(step.to, step.control, nodeIndex);
|
|
480
|
-
if (!fromClip || !toClip) return null;
|
|
481
|
-
startSegment(fromClip);
|
|
482
|
-
emitQuad(step.control, toClip);
|
|
483
|
-
collectLabel(step, (t) => require_segment.quadSegmentSample(fromClip, step.control, toClip, t));
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
if (step.kind === "cubic") {
|
|
487
|
-
const fromClip = usedOverride ?? clipForTarget(prev.step.to, step.control1, nodeIndex);
|
|
488
|
-
const toClip = clipForTarget(step.to, step.control2, nodeIndex);
|
|
489
|
-
if (!fromClip || !toClip) return null;
|
|
490
|
-
startSegment(fromClip);
|
|
491
|
-
emitCubic(step.control1, step.control2, toClip);
|
|
492
|
-
collectLabel(step, (t) => require_segment.cubicSegmentSample(fromClip, step.control1, step.control2, toClip, t));
|
|
493
|
-
continue;
|
|
494
|
-
}
|
|
495
|
-
if (step.kind === "bend") {
|
|
496
|
-
const angle = step.bendAngle ?? 30;
|
|
497
|
-
const [c1, c2] = require_bend.bendControlPoints(prev.anchor, currAnchor, step.bendDirection, angle);
|
|
498
|
-
const fromClip = usedOverride ?? clipForTarget(prev.step.to, c1, nodeIndex);
|
|
499
|
-
const toClip = clipForTarget(step.to, c2, nodeIndex);
|
|
500
|
-
if (!fromClip || !toClip) return null;
|
|
501
|
-
startSegment(fromClip);
|
|
502
|
-
emitCubic(c1, c2, toClip);
|
|
503
|
-
collectLabel(step, (t) => require_segment.cubicSegmentSample(fromClip, c1, c2, toClip, t));
|
|
504
|
-
continue;
|
|
505
|
-
}
|
|
506
|
-
const corner = cornerOf(prev.anchor, currAnchor, step.via);
|
|
507
|
-
const fromClip = usedOverride ?? clipForTarget(prev.step.to, corner, nodeIndex);
|
|
508
|
-
const toClip = clipForTarget(step.to, corner, nodeIndex);
|
|
509
|
-
if (!fromClip || !toClip) return null;
|
|
510
|
-
startSegment(fromClip);
|
|
511
|
-
emitLine(corner);
|
|
512
|
-
emitLine(toClip);
|
|
513
|
-
collectLabel(step, (t) => require_segment.foldSegmentSample(fromClip, corner, toClip, t));
|
|
514
|
-
}
|
|
515
|
-
const strokeWidth = path.strokeWidth ?? (path.thickness ? THICKNESS_TO_WIDTH[path.thickness] : 1);
|
|
516
|
-
const baseProps = {
|
|
517
|
-
stroke: path.stroke ?? "currentColor",
|
|
518
|
-
strokeWidth,
|
|
519
|
-
fill: path.fill ?? "none",
|
|
520
|
-
fillRule: path.fillRule,
|
|
521
|
-
strokeDasharray: path.strokeDasharray,
|
|
522
|
-
strokeLinecap: path.lineCap,
|
|
523
|
-
strokeLinejoin: path.lineJoin,
|
|
524
|
-
opacity: path.opacity,
|
|
525
|
-
fillOpacity: path.fillOpacity,
|
|
526
|
-
strokeOpacity: path.drawOpacity
|
|
527
|
-
};
|
|
528
|
-
const markers = arrowMarkers(path.arrow, path.arrowDetail);
|
|
529
|
-
const hasArrows = !!markers.arrowStart || !!markers.arrowEnd;
|
|
530
|
-
const shrinkStart = markers.arrowStart ? computeShrink(markers.arrowStart) : 0;
|
|
531
|
-
const shrinkEnd = markers.arrowEnd ? computeShrink(markers.arrowEnd) : 0;
|
|
532
|
-
/** 取一个 PathCommand 末端 endpoint(move/line/quad/cubic → to;arc/ellipseArc → polar(end);close 无端点) */
|
|
533
|
-
const endpointOf = (cmd) => {
|
|
534
|
-
switch (cmd.kind) {
|
|
535
|
-
case "move":
|
|
536
|
-
case "line":
|
|
537
|
-
case "quad":
|
|
538
|
-
case "cubic": return [cmd.to[0], cmd.to[1]];
|
|
539
|
-
case "arc": {
|
|
540
|
-
const rad = cmd.endAngle * Math.PI / 180;
|
|
541
|
-
return [cmd.center[0] + Math.cos(rad) * cmd.radius, cmd.center[1] + Math.sin(rad) * cmd.radius];
|
|
542
|
-
}
|
|
543
|
-
case "ellipseArc": {
|
|
544
|
-
const rad = cmd.endAngle * Math.PI / 180;
|
|
545
|
-
return [cmd.center[0] + Math.cos(rad) * cmd.radiusX, cmd.center[1] + Math.sin(rad) * cmd.radiusY];
|
|
546
|
-
}
|
|
547
|
-
case "close": return null;
|
|
548
|
-
}
|
|
549
|
-
};
|
|
550
|
-
/** 改写一个 PathCommand 的 endpoint(用于 shrink) */
|
|
551
|
-
const setEndpoint = (idx, newPt) => {
|
|
552
|
-
const cmd = commands[idx];
|
|
553
|
-
if (cmd.kind === "close") return;
|
|
554
|
-
const rp = [round(newPt[0]), round(newPt[1])];
|
|
555
|
-
if (cmd.kind === "move" || cmd.kind === "line") commands[idx] = {
|
|
556
|
-
...cmd,
|
|
557
|
-
to: rp
|
|
558
|
-
};
|
|
559
|
-
else if (cmd.kind === "quad") commands[idx] = {
|
|
560
|
-
...cmd,
|
|
561
|
-
to: rp
|
|
562
|
-
};
|
|
563
|
-
else if (cmd.kind === "cubic") commands[idx] = {
|
|
564
|
-
...cmd,
|
|
565
|
-
to: rp
|
|
566
|
-
};
|
|
567
|
-
};
|
|
568
|
-
if (shrinkStart > 0) {
|
|
569
|
-
const firstIdx = commands.findIndex((o) => o.kind === "move");
|
|
570
|
-
if (firstIdx >= 0) {
|
|
571
|
-
const cur = commands[firstIdx];
|
|
572
|
-
const nextIdx = commands.findIndex((o, idx) => idx > firstIdx && o.kind !== "close");
|
|
573
|
-
if (cur.kind === "move" && nextIdx >= 0) {
|
|
574
|
-
const nextPt = endpointOf(commands[nextIdx]);
|
|
575
|
-
if (nextPt) setEndpoint(firstIdx, shiftToward([cur.to[0], cur.to[1]], nextPt, shrinkStart * strokeWidth));
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
if (shrinkEnd > 0) {
|
|
580
|
-
let lastIdx = -1;
|
|
581
|
-
for (let i = commands.length - 1; i >= 0; i--) if (commands[i].kind !== "close") {
|
|
582
|
-
lastIdx = i;
|
|
583
|
-
break;
|
|
584
|
-
}
|
|
585
|
-
if (lastIdx > 0) {
|
|
586
|
-
let prevIdx = lastIdx - 1;
|
|
587
|
-
while (prevIdx >= 0 && commands[prevIdx].kind === "close") prevIdx--;
|
|
588
|
-
if (prevIdx >= 0) {
|
|
589
|
-
const curPt = endpointOf(commands[lastIdx]);
|
|
590
|
-
const prevPt = endpointOf(commands[prevIdx]);
|
|
591
|
-
if (curPt && prevPt) {
|
|
592
|
-
const shifted = shiftToward(curPt, prevPt, shrinkEnd * strokeWidth);
|
|
593
|
-
setEndpoint(lastIdx, shifted);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
const subPathStarts = [];
|
|
599
|
-
commands.forEach((cmd, idx) => {
|
|
600
|
-
if (cmd.kind === "move") subPathStarts.push(idx);
|
|
601
|
-
});
|
|
602
|
-
if (!hasArrows || subPathStarts.length <= 1) return {
|
|
603
|
-
primitives: [{
|
|
604
|
-
type: "path",
|
|
605
|
-
commands,
|
|
606
|
-
...baseProps,
|
|
607
|
-
...markers
|
|
608
|
-
}, ...labelPrims],
|
|
609
|
-
points
|
|
610
|
-
};
|
|
611
|
-
const subPathSlices = [];
|
|
612
|
-
for (let s = 0; s < subPathStarts.length; s++) {
|
|
613
|
-
const start = subPathStarts[s];
|
|
614
|
-
const end = s + 1 < subPathStarts.length ? subPathStarts[s + 1] : commands.length;
|
|
615
|
-
subPathSlices.push(commands.slice(start, end));
|
|
616
|
-
}
|
|
617
|
-
return {
|
|
618
|
-
primitives: [{
|
|
619
|
-
type: "group",
|
|
620
|
-
children: subPathSlices.map((sub, i) => {
|
|
621
|
-
const isFirst = i === 0;
|
|
622
|
-
const isLast = i === subPathSlices.length - 1;
|
|
623
|
-
return {
|
|
624
|
-
type: "path",
|
|
625
|
-
commands: sub,
|
|
626
|
-
...baseProps,
|
|
627
|
-
...isFirst && markers.arrowStart ? { arrowStart: markers.arrowStart } : {},
|
|
628
|
-
...isLast && markers.arrowEnd ? { arrowEnd: markers.arrowEnd } : {}
|
|
629
|
-
};
|
|
630
|
-
})
|
|
631
|
-
}, ...labelPrims],
|
|
632
|
-
points
|
|
633
|
-
};
|
|
634
|
-
};
|
|
635
|
-
//#endregion
|
|
636
|
-
exports.emitPathPrimitive = emitPathPrimitive;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/compile/path.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAGV,MAAM,EACN,UAAU,EAIX,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAIV,cAAc,EAEf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,KAAK,UAAU,EAA8C,MAAM,QAAQ,CAAC;AAGrF,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AA8VrE;;;GAGG;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,IAoerE,CAAC"}
|