@invinite-org/chartlang-adapter-kit 1.3.0 → 1.4.0
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/CHANGELOG.md +52 -0
- package/README.md +7 -0
- package/dist/canvas/index.d.ts +5 -0
- package/dist/canvas/index.d.ts.map +1 -0
- package/dist/canvas/index.js +5 -0
- package/dist/canvas/index.js.map +1 -0
- package/dist/canvas/mockContext.d.ts +168 -0
- package/dist/canvas/mockContext.d.ts.map +1 -0
- package/dist/canvas/mockContext.js +198 -0
- package/dist/canvas/mockContext.js.map +1 -0
- package/dist/canvas/paintPrimitive.d.ts +35 -0
- package/dist/canvas/paintPrimitive.d.ts.map +1 -0
- package/dist/canvas/paintPrimitive.js +171 -0
- package/dist/canvas/paintPrimitive.js.map +1 -0
- package/dist/canvas/renderCtx.d.ts +40 -0
- package/dist/canvas/renderCtx.d.ts.map +1 -0
- package/dist/canvas/renderCtx.js +4 -0
- package/dist/canvas/renderCtx.js.map +1 -0
- package/dist/geometry/_lib/arrowhead.d.ts +18 -0
- package/dist/geometry/_lib/arrowhead.d.ts.map +1 -0
- package/dist/geometry/_lib/arrowhead.js +38 -0
- package/dist/geometry/_lib/arrowhead.js.map +1 -0
- package/dist/geometry/_lib/bezier.d.ts +57 -0
- package/dist/geometry/_lib/bezier.d.ts.map +1 -0
- package/dist/geometry/_lib/bezier.js +84 -0
- package/dist/geometry/_lib/bezier.js.map +1 -0
- package/dist/geometry/_lib/chevron.d.ts +29 -0
- package/dist/geometry/_lib/chevron.d.ts.map +1 -0
- package/dist/geometry/_lib/chevron.js +37 -0
- package/dist/geometry/_lib/chevron.js.map +1 -0
- package/dist/geometry/_lib/dash.d.ts +30 -0
- package/dist/geometry/_lib/dash.d.ts.map +1 -0
- package/dist/geometry/_lib/dash.js +40 -0
- package/dist/geometry/_lib/dash.js.map +1 -0
- package/dist/geometry/_lib/fibLevels.d.ts +36 -0
- package/dist/geometry/_lib/fibLevels.d.ts.map +1 -0
- package/dist/geometry/_lib/fibLevels.js +44 -0
- package/dist/geometry/_lib/fibLevels.js.map +1 -0
- package/dist/geometry/_lib/gannLevels.d.ts +54 -0
- package/dist/geometry/_lib/gannLevels.d.ts.map +1 -0
- package/dist/geometry/_lib/gannLevels.js +88 -0
- package/dist/geometry/_lib/gannLevels.js.map +1 -0
- package/dist/geometry/_lib/lineExtend.d.ts +31 -0
- package/dist/geometry/_lib/lineExtend.d.ts.map +1 -0
- package/dist/geometry/_lib/lineExtend.js +48 -0
- package/dist/geometry/_lib/lineExtend.js.map +1 -0
- package/dist/geometry/_lib/namedPolyline.d.ts +25 -0
- package/dist/geometry/_lib/namedPolyline.d.ts.map +1 -0
- package/dist/geometry/_lib/namedPolyline.js +64 -0
- package/dist/geometry/_lib/namedPolyline.js.map +1 -0
- package/dist/geometry/_lib/pitchforkGeom.d.ts +46 -0
- package/dist/geometry/_lib/pitchforkGeom.d.ts.map +1 -0
- package/dist/geometry/_lib/pitchforkGeom.js +70 -0
- package/dist/geometry/_lib/pitchforkGeom.js.map +1 -0
- package/dist/geometry/_lib/shapeStyle.d.ts +21 -0
- package/dist/geometry/_lib/shapeStyle.d.ts.map +1 -0
- package/dist/geometry/_lib/shapeStyle.js +41 -0
- package/dist/geometry/_lib/shapeStyle.js.map +1 -0
- package/dist/geometry/_lib/strokeStyle.d.ts +34 -0
- package/dist/geometry/_lib/strokeStyle.d.ts.map +1 -0
- package/dist/geometry/_lib/strokeStyle.js +26 -0
- package/dist/geometry/_lib/strokeStyle.js.map +1 -0
- package/dist/geometry/_lib/textStyle.d.ts +70 -0
- package/dist/geometry/_lib/textStyle.d.ts.map +1 -0
- package/dist/geometry/_lib/textStyle.js +78 -0
- package/dist/geometry/_lib/textStyle.js.map +1 -0
- package/dist/geometry/decompose.d.ts +28 -0
- package/dist/geometry/decompose.d.ts.map +1 -0
- package/dist/geometry/decompose.js +176 -0
- package/dist/geometry/decompose.js.map +1 -0
- package/dist/geometry/index.d.ts +4 -0
- package/dist/geometry/index.d.ts.map +1 -0
- package/dist/geometry/index.js +5 -0
- package/dist/geometry/index.js.map +1 -0
- package/dist/geometry/kinds/annotations.d.ts +77 -0
- package/dist/geometry/kinds/annotations.d.ts.map +1 -0
- package/dist/geometry/kinds/annotations.js +219 -0
- package/dist/geometry/kinds/annotations.js.map +1 -0
- package/dist/geometry/kinds/boxes.d.ts +116 -0
- package/dist/geometry/kinds/boxes.d.ts.map +1 -0
- package/dist/geometry/kinds/boxes.js +285 -0
- package/dist/geometry/kinds/boxes.js.map +1 -0
- package/dist/geometry/kinds/channels.d.ts +72 -0
- package/dist/geometry/kinds/channels.d.ts.map +1 -0
- package/dist/geometry/kinds/channels.js +148 -0
- package/dist/geometry/kinds/channels.js.map +1 -0
- package/dist/geometry/kinds/containers.d.ts +54 -0
- package/dist/geometry/kinds/containers.d.ts.map +1 -0
- package/dist/geometry/kinds/containers.js +268 -0
- package/dist/geometry/kinds/containers.js.map +1 -0
- package/dist/geometry/kinds/curves.d.ts +53 -0
- package/dist/geometry/kinds/curves.d.ts.map +1 -0
- package/dist/geometry/kinds/curves.js +110 -0
- package/dist/geometry/kinds/curves.js.map +1 -0
- package/dist/geometry/kinds/cycles.d.ts +52 -0
- package/dist/geometry/kinds/cycles.d.ts.map +1 -0
- package/dist/geometry/kinds/cycles.js +158 -0
- package/dist/geometry/kinds/cycles.js.map +1 -0
- package/dist/geometry/kinds/elliott.d.ts +73 -0
- package/dist/geometry/kinds/elliott.d.ts.map +1 -0
- package/dist/geometry/kinds/elliott.js +116 -0
- package/dist/geometry/kinds/elliott.js.map +1 -0
- package/dist/geometry/kinds/fibonacci.d.ts +166 -0
- package/dist/geometry/kinds/fibonacci.d.ts.map +1 -0
- package/dist/geometry/kinds/fibonacci.js +458 -0
- package/dist/geometry/kinds/fibonacci.js.map +1 -0
- package/dist/geometry/kinds/freehand.d.ts +53 -0
- package/dist/geometry/kinds/freehand.d.ts.map +1 -0
- package/dist/geometry/kinds/freehand.js +115 -0
- package/dist/geometry/kinds/freehand.js.map +1 -0
- package/dist/geometry/kinds/gann.d.ts +63 -0
- package/dist/geometry/kinds/gann.d.ts.map +1 -0
- package/dist/geometry/kinds/gann.js +153 -0
- package/dist/geometry/kinds/gann.js.map +1 -0
- package/dist/geometry/kinds/lines.d.ts +90 -0
- package/dist/geometry/kinds/lines.d.ts.map +1 -0
- package/dist/geometry/kinds/lines.js +201 -0
- package/dist/geometry/kinds/lines.js.map +1 -0
- package/dist/geometry/kinds/marker.d.ts +21 -0
- package/dist/geometry/kinds/marker.d.ts.map +1 -0
- package/dist/geometry/kinds/marker.js +47 -0
- package/dist/geometry/kinds/marker.js.map +1 -0
- package/dist/geometry/kinds/patterns.d.ts +85 -0
- package/dist/geometry/kinds/patterns.d.ts.map +1 -0
- package/dist/geometry/kinds/patterns.js +133 -0
- package/dist/geometry/kinds/patterns.js.map +1 -0
- package/dist/geometry/kinds/pitchforks.d.ts +36 -0
- package/dist/geometry/kinds/pitchforks.d.ts.map +1 -0
- package/dist/geometry/kinds/pitchforks.js +109 -0
- package/dist/geometry/kinds/pitchforks.js.map +1 -0
- package/dist/geometry/project.d.ts +50 -0
- package/dist/geometry/project.d.ts.map +1 -0
- package/dist/geometry/project.js +62 -0
- package/dist/geometry/project.js.map +1 -0
- package/dist/geometry/types.d.ts +146 -0
- package/dist/geometry/types.d.ts.map +1 -0
- package/dist/geometry/types.js +4 -0
- package/dist/geometry/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +8 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// Copyright (c) 2026 Invinite. Licensed under the MIT License.
|
|
2
|
+
// See the LICENSE file in the repo root for full license text.
|
|
3
|
+
/**
|
|
4
|
+
* The canvas `textAlign` value a {@link DrawPrimitive} `text.align`
|
|
5
|
+
* maps to. The IR uses the narrower `left | center | right`.
|
|
6
|
+
*/
|
|
7
|
+
const ALIGN_TO_CANVAS = { left: "left", center: "center", right: "right" };
|
|
8
|
+
/**
|
|
9
|
+
* The canvas `textBaseline` value a {@link DrawPrimitive} `text.baseline`
|
|
10
|
+
* maps to. The IR uses the narrower `top | middle | bottom`.
|
|
11
|
+
*/
|
|
12
|
+
const BASELINE_TO_CANVAS = { top: "top", middle: "middle", bottom: "bottom" };
|
|
13
|
+
function applyFill(ctx, fill) {
|
|
14
|
+
ctx.fillStyle = fill.color;
|
|
15
|
+
ctx.globalAlpha = fill.alpha;
|
|
16
|
+
ctx.fill();
|
|
17
|
+
ctx.globalAlpha = 1;
|
|
18
|
+
}
|
|
19
|
+
function applyStrokeStyle(ctx, stroke) {
|
|
20
|
+
ctx.strokeStyle = stroke.color;
|
|
21
|
+
ctx.lineWidth = stroke.width;
|
|
22
|
+
ctx.setLineDash(stroke.dash);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Stroke the current path, bracketing the `stroke()` call in
|
|
26
|
+
* `globalAlpha` when `stroke.alpha` is set (the `highlighter`
|
|
27
|
+
* translucency), then resetting the dash. When `alpha` is omitted the
|
|
28
|
+
* call sequence is exactly `stroke()` → `setLineDash([])` — byte-identical
|
|
29
|
+
* to the Task-1 painter — so no-alpha strokes never re-hash.
|
|
30
|
+
*/
|
|
31
|
+
function strokeWithAlpha(ctx, stroke) {
|
|
32
|
+
if (stroke.alpha !== undefined) {
|
|
33
|
+
ctx.globalAlpha = stroke.alpha;
|
|
34
|
+
ctx.stroke();
|
|
35
|
+
ctx.globalAlpha = 1;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
ctx.stroke();
|
|
39
|
+
}
|
|
40
|
+
ctx.setLineDash([]);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Paint one {@link DrawPrimitive} into a {@link RenderCtx}. The canvas
|
|
44
|
+
* sink shared by the canvas2d, lightweight-charts, and uplot adapters.
|
|
45
|
+
* For each primitive the painter applies the stroke style (when set),
|
|
46
|
+
* builds the path, fills before stroking (so the outline draws on top
|
|
47
|
+
* of the band), and resets `setLineDash([])` + `globalAlpha = 1` after
|
|
48
|
+
* use so downstream draws are unaffected — matching the per-kind
|
|
49
|
+
* renderer conventions the IR replaces. A `stroke.alpha` (the
|
|
50
|
+
* `highlighter` translucency) brackets the `stroke()` in `globalAlpha`;
|
|
51
|
+
* an omitted `alpha` emits no `globalAlpha` mutation, keeping the
|
|
52
|
+
* sequence byte-identical to a Task-1 stroke.
|
|
53
|
+
*
|
|
54
|
+
* `text.bgColor` is carried on the IR but NOT painted here (the
|
|
55
|
+
* structural `RenderCtx` exposes neither `measureText` nor a
|
|
56
|
+
* background-rect path), mirroring the source renderers. The IR
|
|
57
|
+
* `marker` primitive is painted as a sized glyph; no basic kind emits
|
|
58
|
+
* it today, but adapters / future kinds rely on the painter covering
|
|
59
|
+
* every IR shape.
|
|
60
|
+
*
|
|
61
|
+
* @since 1.3
|
|
62
|
+
* @stable
|
|
63
|
+
* @example
|
|
64
|
+
* declare const ctx: RenderCtx;
|
|
65
|
+
* paintPrimitive(ctx, {
|
|
66
|
+
* kind: "polyline",
|
|
67
|
+
* points: [{ x: 0, y: 0 }, { x: 10, y: 10 }],
|
|
68
|
+
* closed: false,
|
|
69
|
+
* stroke: { color: "#000000", width: 1, dash: [] },
|
|
70
|
+
* });
|
|
71
|
+
* void paintPrimitive;
|
|
72
|
+
*/
|
|
73
|
+
export function paintPrimitive(ctx, p) {
|
|
74
|
+
switch (p.kind) {
|
|
75
|
+
case "polyline": {
|
|
76
|
+
if (p.points.length === 0)
|
|
77
|
+
return;
|
|
78
|
+
if (p.stroke !== undefined)
|
|
79
|
+
applyStrokeStyle(ctx, p.stroke);
|
|
80
|
+
ctx.beginPath();
|
|
81
|
+
ctx.moveTo(p.points[0].x, p.points[0].y);
|
|
82
|
+
for (let i = 1; i < p.points.length; i++) {
|
|
83
|
+
ctx.lineTo(p.points[i].x, p.points[i].y);
|
|
84
|
+
}
|
|
85
|
+
if (p.closed)
|
|
86
|
+
ctx.closePath();
|
|
87
|
+
if (p.fill !== undefined)
|
|
88
|
+
applyFill(ctx, p.fill);
|
|
89
|
+
if (p.stroke !== undefined)
|
|
90
|
+
strokeWithAlpha(ctx, p.stroke);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
case "arc": {
|
|
94
|
+
if (p.stroke !== undefined)
|
|
95
|
+
applyStrokeStyle(ctx, p.stroke);
|
|
96
|
+
ctx.beginPath();
|
|
97
|
+
ctx.arc(p.cx, p.cy, p.r, p.start, p.end);
|
|
98
|
+
if (p.closed)
|
|
99
|
+
ctx.closePath();
|
|
100
|
+
if (p.fill !== undefined)
|
|
101
|
+
applyFill(ctx, p.fill);
|
|
102
|
+
if (p.stroke !== undefined)
|
|
103
|
+
strokeWithAlpha(ctx, p.stroke);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
case "text": {
|
|
107
|
+
ctx.font = p.font;
|
|
108
|
+
ctx.textAlign = ALIGN_TO_CANVAS[p.align];
|
|
109
|
+
ctx.textBaseline = BASELINE_TO_CANVAS[p.baseline];
|
|
110
|
+
ctx.fillStyle = p.color;
|
|
111
|
+
ctx.fillText(p.text, p.x, p.y);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
case "marker": {
|
|
115
|
+
const polygon = markerPolygon(p.shape, p.x, p.y, p.size);
|
|
116
|
+
if (p.stroke !== undefined)
|
|
117
|
+
applyStrokeStyle(ctx, p.stroke);
|
|
118
|
+
ctx.beginPath();
|
|
119
|
+
ctx.moveTo(polygon[0].x, polygon[0].y);
|
|
120
|
+
for (let i = 1; i < polygon.length; i++) {
|
|
121
|
+
ctx.lineTo(polygon[i].x, polygon[i].y);
|
|
122
|
+
}
|
|
123
|
+
ctx.closePath();
|
|
124
|
+
if (p.fill !== undefined)
|
|
125
|
+
applyFill(ctx, p.fill);
|
|
126
|
+
if (p.stroke !== undefined)
|
|
127
|
+
strokeWithAlpha(ctx, p.stroke);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Vertices of a sized marker glyph centred on `(x, y)`. `circle` is
|
|
134
|
+
* approximated as a square for the closed-polygon painter — the IR
|
|
135
|
+
* `marker` is emitted by no basic kind today, so the approximation only
|
|
136
|
+
* matters once an adapter / later task uses it; the contract is a
|
|
137
|
+
* non-empty closed polygon for every shape.
|
|
138
|
+
*/
|
|
139
|
+
function markerPolygon(shape, x, y, size) {
|
|
140
|
+
const h = size / 2;
|
|
141
|
+
switch (shape) {
|
|
142
|
+
case "circle":
|
|
143
|
+
case "square":
|
|
144
|
+
return [
|
|
145
|
+
{ x: x - h, y: y - h },
|
|
146
|
+
{ x: x + h, y: y - h },
|
|
147
|
+
{ x: x + h, y: y + h },
|
|
148
|
+
{ x: x - h, y: y + h },
|
|
149
|
+
];
|
|
150
|
+
case "diamond":
|
|
151
|
+
return [
|
|
152
|
+
{ x, y: y - h },
|
|
153
|
+
{ x: x + h, y },
|
|
154
|
+
{ x, y: y + h },
|
|
155
|
+
{ x: x - h, y },
|
|
156
|
+
];
|
|
157
|
+
case "triangle-up":
|
|
158
|
+
return [
|
|
159
|
+
{ x, y: y - h },
|
|
160
|
+
{ x: x + h, y: y + h },
|
|
161
|
+
{ x: x - h, y: y + h },
|
|
162
|
+
];
|
|
163
|
+
case "triangle-down":
|
|
164
|
+
return [
|
|
165
|
+
{ x, y: y + h },
|
|
166
|
+
{ x: x + h, y: y - h },
|
|
167
|
+
{ x: x - h, y: y - h },
|
|
168
|
+
];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=paintPrimitive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paintPrimitive.js","sourceRoot":"","sources":["../../src/canvas/paintPrimitive.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type { DrawPrimitive, FillStyle, StrokeStyle } from \"../geometry/types.js\";\nimport type { RenderCtx } from \"./renderCtx.js\";\n\n/**\n * The canvas `textAlign` value a {@link DrawPrimitive} `text.align`\n * maps to. The IR uses the narrower `left | center | right`.\n */\nconst ALIGN_TO_CANVAS: Readonly<Record<\"left\" | \"center\" | \"right\", \"left\" | \"center\" | \"right\">> =\n { left: \"left\", center: \"center\", right: \"right\" };\n\n/**\n * The canvas `textBaseline` value a {@link DrawPrimitive} `text.baseline`\n * maps to. The IR uses the narrower `top | middle | bottom`.\n */\nconst BASELINE_TO_CANVAS: Readonly<\n Record<\"top\" | \"middle\" | \"bottom\", \"top\" | \"middle\" | \"bottom\">\n> = { top: \"top\", middle: \"middle\", bottom: \"bottom\" };\n\nfunction applyFill(ctx: RenderCtx, fill: FillStyle): void {\n ctx.fillStyle = fill.color;\n ctx.globalAlpha = fill.alpha;\n ctx.fill();\n ctx.globalAlpha = 1;\n}\n\nfunction applyStrokeStyle(ctx: RenderCtx, stroke: StrokeStyle): void {\n ctx.strokeStyle = stroke.color;\n ctx.lineWidth = stroke.width;\n ctx.setLineDash(stroke.dash);\n}\n\n/**\n * Stroke the current path, bracketing the `stroke()` call in\n * `globalAlpha` when `stroke.alpha` is set (the `highlighter`\n * translucency), then resetting the dash. When `alpha` is omitted the\n * call sequence is exactly `stroke()` → `setLineDash([])` — byte-identical\n * to the Task-1 painter — so no-alpha strokes never re-hash.\n */\nfunction strokeWithAlpha(ctx: RenderCtx, stroke: StrokeStyle): void {\n if (stroke.alpha !== undefined) {\n ctx.globalAlpha = stroke.alpha;\n ctx.stroke();\n ctx.globalAlpha = 1;\n } else {\n ctx.stroke();\n }\n ctx.setLineDash([]);\n}\n\n/**\n * Paint one {@link DrawPrimitive} into a {@link RenderCtx}. The canvas\n * sink shared by the canvas2d, lightweight-charts, and uplot adapters.\n * For each primitive the painter applies the stroke style (when set),\n * builds the path, fills before stroking (so the outline draws on top\n * of the band), and resets `setLineDash([])` + `globalAlpha = 1` after\n * use so downstream draws are unaffected — matching the per-kind\n * renderer conventions the IR replaces. A `stroke.alpha` (the\n * `highlighter` translucency) brackets the `stroke()` in `globalAlpha`;\n * an omitted `alpha` emits no `globalAlpha` mutation, keeping the\n * sequence byte-identical to a Task-1 stroke.\n *\n * `text.bgColor` is carried on the IR but NOT painted here (the\n * structural `RenderCtx` exposes neither `measureText` nor a\n * background-rect path), mirroring the source renderers. The IR\n * `marker` primitive is painted as a sized glyph; no basic kind emits\n * it today, but adapters / future kinds rely on the painter covering\n * every IR shape.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const ctx: RenderCtx;\n * paintPrimitive(ctx, {\n * kind: \"polyline\",\n * points: [{ x: 0, y: 0 }, { x: 10, y: 10 }],\n * closed: false,\n * stroke: { color: \"#000000\", width: 1, dash: [] },\n * });\n * void paintPrimitive;\n */\nexport function paintPrimitive(ctx: RenderCtx, p: DrawPrimitive): void {\n switch (p.kind) {\n case \"polyline\": {\n if (p.points.length === 0) return;\n if (p.stroke !== undefined) applyStrokeStyle(ctx, p.stroke);\n ctx.beginPath();\n ctx.moveTo(p.points[0].x, p.points[0].y);\n for (let i = 1; i < p.points.length; i++) {\n ctx.lineTo(p.points[i].x, p.points[i].y);\n }\n if (p.closed) ctx.closePath();\n if (p.fill !== undefined) applyFill(ctx, p.fill);\n if (p.stroke !== undefined) strokeWithAlpha(ctx, p.stroke);\n return;\n }\n case \"arc\": {\n if (p.stroke !== undefined) applyStrokeStyle(ctx, p.stroke);\n ctx.beginPath();\n ctx.arc(p.cx, p.cy, p.r, p.start, p.end);\n if (p.closed) ctx.closePath();\n if (p.fill !== undefined) applyFill(ctx, p.fill);\n if (p.stroke !== undefined) strokeWithAlpha(ctx, p.stroke);\n return;\n }\n case \"text\": {\n ctx.font = p.font;\n ctx.textAlign = ALIGN_TO_CANVAS[p.align];\n ctx.textBaseline = BASELINE_TO_CANVAS[p.baseline];\n ctx.fillStyle = p.color;\n ctx.fillText(p.text, p.x, p.y);\n return;\n }\n case \"marker\": {\n const polygon = markerPolygon(p.shape, p.x, p.y, p.size);\n if (p.stroke !== undefined) applyStrokeStyle(ctx, p.stroke);\n ctx.beginPath();\n ctx.moveTo(polygon[0].x, polygon[0].y);\n for (let i = 1; i < polygon.length; i++) {\n ctx.lineTo(polygon[i].x, polygon[i].y);\n }\n ctx.closePath();\n if (p.fill !== undefined) applyFill(ctx, p.fill);\n if (p.stroke !== undefined) strokeWithAlpha(ctx, p.stroke);\n return;\n }\n }\n}\n\n/**\n * Vertices of a sized marker glyph centred on `(x, y)`. `circle` is\n * approximated as a square for the closed-polygon painter — the IR\n * `marker` is emitted by no basic kind today, so the approximation only\n * matters once an adapter / later task uses it; the contract is a\n * non-empty closed polygon for every shape.\n */\nfunction markerPolygon(\n shape: \"circle\" | \"square\" | \"diamond\" | \"triangle-up\" | \"triangle-down\",\n x: number,\n y: number,\n size: number,\n): ReadonlyArray<{ readonly x: number; readonly y: number }> {\n const h = size / 2;\n switch (shape) {\n case \"circle\":\n case \"square\":\n return [\n { x: x - h, y: y - h },\n { x: x + h, y: y - h },\n { x: x + h, y: y + h },\n { x: x - h, y: y + h },\n ];\n case \"diamond\":\n return [\n { x, y: y - h },\n { x: x + h, y },\n { x, y: y + h },\n { x: x - h, y },\n ];\n case \"triangle-up\":\n return [\n { x, y: y - h },\n { x: x + h, y: y + h },\n { x: x - h, y: y + h },\n ];\n case \"triangle-down\":\n return [\n { x, y: y + h },\n { x: x + h, y: y - h },\n { x: x - h, y: y - h },\n ];\n }\n}\n"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal `CanvasRenderingContext2D` subset the canvas-family sink
|
|
3
|
+
* touches. Declared here (and re-used by {@link import("./paintPrimitive").paintPrimitive}
|
|
4
|
+
* and {@link import("./mockContext").MockCanvasContext}) so production
|
|
5
|
+
* `CanvasRenderingContext2D`, `OffscreenCanvasRenderingContext2D`, and
|
|
6
|
+
* the test `MockCanvasContext` all satisfy one structural type. Moved
|
|
7
|
+
* from the canvas2d adapter's `render/clear.ts` so lightweight-charts /
|
|
8
|
+
* uplot / canvas2d share one painter and one mock.
|
|
9
|
+
*
|
|
10
|
+
* @since 1.3
|
|
11
|
+
* @stable
|
|
12
|
+
* @example
|
|
13
|
+
* declare const ctx: RenderCtx;
|
|
14
|
+
* ctx.clearRect(0, 0, 1, 1);
|
|
15
|
+
* void ctx;
|
|
16
|
+
*/
|
|
17
|
+
export type RenderCtx = {
|
|
18
|
+
clearRect(x: number, y: number, w: number, h: number): void;
|
|
19
|
+
translate(x: number, y: number): void;
|
|
20
|
+
save(): void;
|
|
21
|
+
restore(): void;
|
|
22
|
+
beginPath(): void;
|
|
23
|
+
moveTo(x: number, y: number): void;
|
|
24
|
+
lineTo(x: number, y: number): void;
|
|
25
|
+
stroke(): void;
|
|
26
|
+
fillRect(x: number, y: number, w: number, h: number): void;
|
|
27
|
+
fill(): void;
|
|
28
|
+
arc(x: number, y: number, radius: number, start: number, end: number): void;
|
|
29
|
+
closePath(): void;
|
|
30
|
+
setLineDash(segments: ReadonlyArray<number>): void;
|
|
31
|
+
fillText(text: string, x: number, y: number): void;
|
|
32
|
+
strokeStyle: string;
|
|
33
|
+
fillStyle: string;
|
|
34
|
+
lineWidth: number;
|
|
35
|
+
globalAlpha: number;
|
|
36
|
+
font: string;
|
|
37
|
+
textAlign: "start" | "center" | "end" | "left" | "right";
|
|
38
|
+
textBaseline: "top" | "middle" | "bottom" | "alphabetic" | "hanging";
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=renderCtx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderCtx.d.ts","sourceRoot":"","sources":["../../src/canvas/renderCtx.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,SAAS,GAAG;IACpB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5D,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,IAAI,IAAI,IAAI,CAAC;IACb,OAAO,IAAI,IAAI,CAAC;IAChB,SAAS,IAAI,IAAI,CAAC;IAClB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,MAAM,IAAI,IAAI,CAAC;IACf,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3D,IAAI,IAAI,IAAI,CAAC;IACb,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5E,SAAS,IAAI,IAAI,CAAC;IAClB,WAAW,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IACzD,YAAY,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;CACxE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderCtx.js","sourceRoot":"","sources":["../../src/canvas/renderCtx.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\n/**\n * Minimal `CanvasRenderingContext2D` subset the canvas-family sink\n * touches. Declared here (and re-used by {@link import(\"./paintPrimitive\").paintPrimitive}\n * and {@link import(\"./mockContext\").MockCanvasContext}) so production\n * `CanvasRenderingContext2D`, `OffscreenCanvasRenderingContext2D`, and\n * the test `MockCanvasContext` all satisfy one structural type. Moved\n * from the canvas2d adapter's `render/clear.ts` so lightweight-charts /\n * uplot / canvas2d share one painter and one mock.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const ctx: RenderCtx;\n * ctx.clearRect(0, 0, 1, 1);\n * void ctx;\n */\nexport type RenderCtx = {\n clearRect(x: number, y: number, w: number, h: number): void;\n translate(x: number, y: number): void;\n save(): void;\n restore(): void;\n beginPath(): void;\n moveTo(x: number, y: number): void;\n lineTo(x: number, y: number): void;\n stroke(): void;\n fillRect(x: number, y: number, w: number, h: number): void;\n fill(): void;\n arc(x: number, y: number, radius: number, start: number, end: number): void;\n closePath(): void;\n setLineDash(segments: ReadonlyArray<number>): void;\n fillText(text: string, x: number, y: number): void;\n strokeStyle: string;\n fillStyle: string;\n lineWidth: number;\n globalAlpha: number;\n font: string;\n textAlign: \"start\" | \"center\" | \"end\" | \"left\" | \"right\";\n textBaseline: \"top\" | \"middle\" | \"bottom\" | \"alphabetic\" | \"hanging\";\n};\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Point2 } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Return the three vertices of a filled isoceles-triangle arrowhead at
|
|
4
|
+
* `to` pointing along the `from → to` direction. The order is
|
|
5
|
+
* `[tip, leftWing, rightWing]` so a caller paints a closed polyline
|
|
6
|
+
* `moveTo(tip) → lineTo(left) → lineTo(right) → close`. Pure — no `ctx`.
|
|
7
|
+
*
|
|
8
|
+
* `size` defaults to 8 CSS px (the wing length).
|
|
9
|
+
*
|
|
10
|
+
* @since 1.3
|
|
11
|
+
* @stable
|
|
12
|
+
* @example
|
|
13
|
+
* const tri = arrowheadPolygon({ x: 0, y: 0 }, { x: 100, y: 0 });
|
|
14
|
+
* // tri[0] === { x: 100, y: 0 } (tip)
|
|
15
|
+
* void tri;
|
|
16
|
+
*/
|
|
17
|
+
export declare function arrowheadPolygon(from: Point2, to: Point2, size?: number): ReadonlyArray<Point2>;
|
|
18
|
+
//# sourceMappingURL=arrowhead.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arrowhead.d.ts","sourceRoot":"","sources":["../../../src/geometry/_lib/arrowhead.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAK1C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC5B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,MAA+B,GACtC,aAAa,CAAC,MAAM,CAAC,CAWvB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Copyright (c) 2026 Invinite. Licensed under the MIT License.
|
|
2
|
+
// See the LICENSE file in the repo root for full license text.
|
|
3
|
+
//
|
|
4
|
+
// Arrowhead geometry ported from
|
|
5
|
+
// invinite/src/components/trading-chart/tools/arrow-tool.ts,
|
|
6
|
+
// invinite/src/components/trading-chart/tools/arrow-marker-tool.ts,
|
|
7
|
+
// commit 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite.
|
|
8
|
+
// Re-licensed MIT for chartlang.
|
|
9
|
+
const DEFAULT_ARROWHEAD_SIZE = 8;
|
|
10
|
+
const ARROWHEAD_HALF_ANGLE = Math.PI / 6; // 30° each side → 60° total
|
|
11
|
+
/**
|
|
12
|
+
* Return the three vertices of a filled isoceles-triangle arrowhead at
|
|
13
|
+
* `to` pointing along the `from → to` direction. The order is
|
|
14
|
+
* `[tip, leftWing, rightWing]` so a caller paints a closed polyline
|
|
15
|
+
* `moveTo(tip) → lineTo(left) → lineTo(right) → close`. Pure — no `ctx`.
|
|
16
|
+
*
|
|
17
|
+
* `size` defaults to 8 CSS px (the wing length).
|
|
18
|
+
*
|
|
19
|
+
* @since 1.3
|
|
20
|
+
* @stable
|
|
21
|
+
* @example
|
|
22
|
+
* const tri = arrowheadPolygon({ x: 0, y: 0 }, { x: 100, y: 0 });
|
|
23
|
+
* // tri[0] === { x: 100, y: 0 } (tip)
|
|
24
|
+
* void tri;
|
|
25
|
+
*/
|
|
26
|
+
export function arrowheadPolygon(from, to, size = DEFAULT_ARROWHEAD_SIZE) {
|
|
27
|
+
const angle = Math.atan2(to.y - from.y, to.x - from.x);
|
|
28
|
+
const left = {
|
|
29
|
+
x: to.x - size * Math.cos(angle - ARROWHEAD_HALF_ANGLE),
|
|
30
|
+
y: to.y - size * Math.sin(angle - ARROWHEAD_HALF_ANGLE),
|
|
31
|
+
};
|
|
32
|
+
const right = {
|
|
33
|
+
x: to.x - size * Math.cos(angle + ARROWHEAD_HALF_ANGLE),
|
|
34
|
+
y: to.y - size * Math.sin(angle + ARROWHEAD_HALF_ANGLE),
|
|
35
|
+
};
|
|
36
|
+
return [to, left, right];
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=arrowhead.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arrowhead.js","sourceRoot":"","sources":["../../../src/geometry/_lib/arrowhead.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAC/D,EAAE;AACF,iCAAiC;AACjC,+DAA+D;AAC/D,sEAAsE;AACtE,iEAAiE;AACjE,iCAAiC;AAIjC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACjC,MAAM,oBAAoB,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,4BAA4B;AAEtE;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,gBAAgB,CAC5B,IAAY,EACZ,EAAU,EACV,OAAe,sBAAsB;IAErC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,IAAI,GAAW;QACjB,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,oBAAoB,CAAC;QACvD,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,oBAAoB,CAAC;KAC1D,CAAC;IACF,MAAM,KAAK,GAAW;QAClB,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,oBAAoB,CAAC;QACvD,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,oBAAoB,CAAC;KAC1D,CAAC;IACF,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAC7B,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Arrowhead geometry ported from\n// invinite/src/components/trading-chart/tools/arrow-tool.ts,\n// invinite/src/components/trading-chart/tools/arrow-marker-tool.ts,\n// commit 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite.\n// Re-licensed MIT for chartlang.\n\nimport type { Point2 } from \"../types.js\";\n\nconst DEFAULT_ARROWHEAD_SIZE = 8;\nconst ARROWHEAD_HALF_ANGLE = Math.PI / 6; // 30° each side → 60° total\n\n/**\n * Return the three vertices of a filled isoceles-triangle arrowhead at\n * `to` pointing along the `from → to` direction. The order is\n * `[tip, leftWing, rightWing]` so a caller paints a closed polyline\n * `moveTo(tip) → lineTo(left) → lineTo(right) → close`. Pure — no `ctx`.\n *\n * `size` defaults to 8 CSS px (the wing length).\n *\n * @since 1.3\n * @stable\n * @example\n * const tri = arrowheadPolygon({ x: 0, y: 0 }, { x: 100, y: 0 });\n * // tri[0] === { x: 100, y: 0 } (tip)\n * void tri;\n */\nexport function arrowheadPolygon(\n from: Point2,\n to: Point2,\n size: number = DEFAULT_ARROWHEAD_SIZE,\n): ReadonlyArray<Point2> {\n const angle = Math.atan2(to.y - from.y, to.x - from.x);\n const left: Point2 = {\n x: to.x - size * Math.cos(angle - ARROWHEAD_HALF_ANGLE),\n y: to.y - size * Math.sin(angle - ARROWHEAD_HALF_ANGLE),\n };\n const right: Point2 = {\n x: to.x - size * Math.cos(angle + ARROWHEAD_HALF_ANGLE),\n y: to.y - size * Math.sin(angle + ARROWHEAD_HALF_ANGLE),\n };\n return [to, left, right];\n}\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Point2 } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Evaluate a quadratic Bezier curve at parameter `t ∈ [0, 1]`. The
|
|
4
|
+
* curve interpolates `p0` (at `t = 0`) and `p2` (at `t = 1`) with `p1`
|
|
5
|
+
* as the off-curve control point. Endpoints are float-exact:
|
|
6
|
+
* `quadraticBezier(p0, p1, p2, 0) === p0` and `… 1) === p2`.
|
|
7
|
+
*
|
|
8
|
+
* @since 1.3
|
|
9
|
+
* @stable
|
|
10
|
+
* @example
|
|
11
|
+
* const mid = quadraticBezier({ x: 0, y: 0 }, { x: 1, y: 2 }, { x: 2, y: 0 }, 0.5);
|
|
12
|
+
* // mid.x === 1; mid.y === 1
|
|
13
|
+
* void mid;
|
|
14
|
+
*/
|
|
15
|
+
export declare function quadraticBezier(p0: Point2, p1: Point2, p2: Point2, t: number): Point2;
|
|
16
|
+
/**
|
|
17
|
+
* Evaluate a cubic Bezier curve at parameter `t ∈ [0, 1]`. The curve
|
|
18
|
+
* interpolates `p0` (at `t = 0`) and `p3` (at `t = 1`) with `p1` and
|
|
19
|
+
* `p2` as the two off-curve control points. Endpoints are float-exact.
|
|
20
|
+
*
|
|
21
|
+
* @since 1.3
|
|
22
|
+
* @stable
|
|
23
|
+
* @example
|
|
24
|
+
* const start = cubicBezier(
|
|
25
|
+
* { x: 0, y: 0 }, { x: 1, y: 3 }, { x: 2, y: 3 }, { x: 3, y: 0 }, 0,
|
|
26
|
+
* );
|
|
27
|
+
* // start === { x: 0, y: 0 }
|
|
28
|
+
* void start;
|
|
29
|
+
*/
|
|
30
|
+
export declare function cubicBezier(p0: Point2, p1: Point2, p2: Point2, p3: Point2, t: number): Point2;
|
|
31
|
+
/**
|
|
32
|
+
* Sample a quadratic Bezier into `samples + 1` points evenly spaced in
|
|
33
|
+
* parameter `t ∈ [0, 1]`. The first sample is `p0`, the last is `p2`.
|
|
34
|
+
*
|
|
35
|
+
* @since 1.3
|
|
36
|
+
* @stable
|
|
37
|
+
* @example
|
|
38
|
+
* const pts = sampleQuadratic({ x: 0, y: 0 }, { x: 1, y: 2 }, { x: 2, y: 0 }, 4);
|
|
39
|
+
* // pts.length === 5; pts[0] === { x: 0, y: 0 }; pts[4] === { x: 2, y: 0 }
|
|
40
|
+
* void pts;
|
|
41
|
+
*/
|
|
42
|
+
export declare function sampleQuadratic(p0: Point2, p1: Point2, p2: Point2, samples: number): ReadonlyArray<Point2>;
|
|
43
|
+
/**
|
|
44
|
+
* Sample a cubic Bezier into `samples + 1` points evenly spaced in
|
|
45
|
+
* parameter `t ∈ [0, 1]`. Mirrors {@link sampleQuadratic}.
|
|
46
|
+
*
|
|
47
|
+
* @since 1.3
|
|
48
|
+
* @stable
|
|
49
|
+
* @example
|
|
50
|
+
* const pts = sampleCubic(
|
|
51
|
+
* { x: 0, y: 0 }, { x: 1, y: 3 }, { x: 2, y: 3 }, { x: 3, y: 0 }, 8,
|
|
52
|
+
* );
|
|
53
|
+
* // pts.length === 9; pts[0] === { x: 0, y: 0 }; pts[8] === { x: 3, y: 0 }
|
|
54
|
+
* void pts;
|
|
55
|
+
*/
|
|
56
|
+
export declare function sampleCubic(p0: Point2, p1: Point2, p2: Point2, p3: Point2, samples: number): ReadonlyArray<Point2>;
|
|
57
|
+
//# sourceMappingURL=bezier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bezier.d.ts","sourceRoot":"","sources":["../../../src/geometry/_lib/bezier.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAMrF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ7F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC3B,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,GAChB,aAAa,CAAC,MAAM,CAAC,CAMvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACvB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,GAChB,aAAa,CAAC,MAAM,CAAC,CAMvB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Copyright (c) 2026 Invinite. Licensed under the MIT License.
|
|
2
|
+
// See the LICENSE file in the repo root for full license text.
|
|
3
|
+
/**
|
|
4
|
+
* Evaluate a quadratic Bezier curve at parameter `t ∈ [0, 1]`. The
|
|
5
|
+
* curve interpolates `p0` (at `t = 0`) and `p2` (at `t = 1`) with `p1`
|
|
6
|
+
* as the off-curve control point. Endpoints are float-exact:
|
|
7
|
+
* `quadraticBezier(p0, p1, p2, 0) === p0` and `… 1) === p2`.
|
|
8
|
+
*
|
|
9
|
+
* @since 1.3
|
|
10
|
+
* @stable
|
|
11
|
+
* @example
|
|
12
|
+
* const mid = quadraticBezier({ x: 0, y: 0 }, { x: 1, y: 2 }, { x: 2, y: 0 }, 0.5);
|
|
13
|
+
* // mid.x === 1; mid.y === 1
|
|
14
|
+
* void mid;
|
|
15
|
+
*/
|
|
16
|
+
export function quadraticBezier(p0, p1, p2, t) {
|
|
17
|
+
const u = 1 - t;
|
|
18
|
+
return {
|
|
19
|
+
x: u * u * p0.x + 2 * u * t * p1.x + t * t * p2.x,
|
|
20
|
+
y: u * u * p0.y + 2 * u * t * p1.y + t * t * p2.y,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Evaluate a cubic Bezier curve at parameter `t ∈ [0, 1]`. The curve
|
|
25
|
+
* interpolates `p0` (at `t = 0`) and `p3` (at `t = 1`) with `p1` and
|
|
26
|
+
* `p2` as the two off-curve control points. Endpoints are float-exact.
|
|
27
|
+
*
|
|
28
|
+
* @since 1.3
|
|
29
|
+
* @stable
|
|
30
|
+
* @example
|
|
31
|
+
* const start = cubicBezier(
|
|
32
|
+
* { x: 0, y: 0 }, { x: 1, y: 3 }, { x: 2, y: 3 }, { x: 3, y: 0 }, 0,
|
|
33
|
+
* );
|
|
34
|
+
* // start === { x: 0, y: 0 }
|
|
35
|
+
* void start;
|
|
36
|
+
*/
|
|
37
|
+
export function cubicBezier(p0, p1, p2, p3, t) {
|
|
38
|
+
const u = 1 - t;
|
|
39
|
+
const uu = u * u;
|
|
40
|
+
const tt = t * t;
|
|
41
|
+
return {
|
|
42
|
+
x: uu * u * p0.x + 3 * uu * t * p1.x + 3 * u * tt * p2.x + tt * t * p3.x,
|
|
43
|
+
y: uu * u * p0.y + 3 * uu * t * p1.y + 3 * u * tt * p2.y + tt * t * p3.y,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Sample a quadratic Bezier into `samples + 1` points evenly spaced in
|
|
48
|
+
* parameter `t ∈ [0, 1]`. The first sample is `p0`, the last is `p2`.
|
|
49
|
+
*
|
|
50
|
+
* @since 1.3
|
|
51
|
+
* @stable
|
|
52
|
+
* @example
|
|
53
|
+
* const pts = sampleQuadratic({ x: 0, y: 0 }, { x: 1, y: 2 }, { x: 2, y: 0 }, 4);
|
|
54
|
+
* // pts.length === 5; pts[0] === { x: 0, y: 0 }; pts[4] === { x: 2, y: 0 }
|
|
55
|
+
* void pts;
|
|
56
|
+
*/
|
|
57
|
+
export function sampleQuadratic(p0, p1, p2, samples) {
|
|
58
|
+
const out = [];
|
|
59
|
+
for (let i = 0; i <= samples; i++) {
|
|
60
|
+
out.push(quadraticBezier(p0, p1, p2, i / samples));
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Sample a cubic Bezier into `samples + 1` points evenly spaced in
|
|
66
|
+
* parameter `t ∈ [0, 1]`. Mirrors {@link sampleQuadratic}.
|
|
67
|
+
*
|
|
68
|
+
* @since 1.3
|
|
69
|
+
* @stable
|
|
70
|
+
* @example
|
|
71
|
+
* const pts = sampleCubic(
|
|
72
|
+
* { x: 0, y: 0 }, { x: 1, y: 3 }, { x: 2, y: 3 }, { x: 3, y: 0 }, 8,
|
|
73
|
+
* );
|
|
74
|
+
* // pts.length === 9; pts[0] === { x: 0, y: 0 }; pts[8] === { x: 3, y: 0 }
|
|
75
|
+
* void pts;
|
|
76
|
+
*/
|
|
77
|
+
export function sampleCubic(p0, p1, p2, p3, samples) {
|
|
78
|
+
const out = [];
|
|
79
|
+
for (let i = 0; i <= samples; i++) {
|
|
80
|
+
out.push(cubicBezier(p0, p1, p2, p3, i / samples));
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=bezier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bezier.js","sourceRoot":"","sources":["../../../src/geometry/_lib/bezier.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAI/D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,CAAS;IACzE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO;QACH,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QACjD,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;KACpD,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,CAAS;IACjF,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IACjB,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IACjB,OAAO;QACH,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QACxE,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;KAC3E,CAAC;AACN,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAC3B,EAAU,EACV,EAAU,EACV,EAAU,EACV,OAAe;IAEf,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CACvB,EAAU,EACV,EAAU,EACV,EAAU,EACV,EAAU,EACV,OAAe;IAEf,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type { Point2 } from \"../types.js\";\n\n/**\n * Evaluate a quadratic Bezier curve at parameter `t ∈ [0, 1]`. The\n * curve interpolates `p0` (at `t = 0`) and `p2` (at `t = 1`) with `p1`\n * as the off-curve control point. Endpoints are float-exact:\n * `quadraticBezier(p0, p1, p2, 0) === p0` and `… 1) === p2`.\n *\n * @since 1.3\n * @stable\n * @example\n * const mid = quadraticBezier({ x: 0, y: 0 }, { x: 1, y: 2 }, { x: 2, y: 0 }, 0.5);\n * // mid.x === 1; mid.y === 1\n * void mid;\n */\nexport function quadraticBezier(p0: Point2, p1: Point2, p2: Point2, t: number): Point2 {\n const u = 1 - t;\n return {\n x: u * u * p0.x + 2 * u * t * p1.x + t * t * p2.x,\n y: u * u * p0.y + 2 * u * t * p1.y + t * t * p2.y,\n };\n}\n\n/**\n * Evaluate a cubic Bezier curve at parameter `t ∈ [0, 1]`. The curve\n * interpolates `p0` (at `t = 0`) and `p3` (at `t = 1`) with `p1` and\n * `p2` as the two off-curve control points. Endpoints are float-exact.\n *\n * @since 1.3\n * @stable\n * @example\n * const start = cubicBezier(\n * { x: 0, y: 0 }, { x: 1, y: 3 }, { x: 2, y: 3 }, { x: 3, y: 0 }, 0,\n * );\n * // start === { x: 0, y: 0 }\n * void start;\n */\nexport function cubicBezier(p0: Point2, p1: Point2, p2: Point2, p3: Point2, t: number): Point2 {\n const u = 1 - t;\n const uu = u * u;\n const tt = t * t;\n return {\n x: uu * u * p0.x + 3 * uu * t * p1.x + 3 * u * tt * p2.x + tt * t * p3.x,\n y: uu * u * p0.y + 3 * uu * t * p1.y + 3 * u * tt * p2.y + tt * t * p3.y,\n };\n}\n\n/**\n * Sample a quadratic Bezier into `samples + 1` points evenly spaced in\n * parameter `t ∈ [0, 1]`. The first sample is `p0`, the last is `p2`.\n *\n * @since 1.3\n * @stable\n * @example\n * const pts = sampleQuadratic({ x: 0, y: 0 }, { x: 1, y: 2 }, { x: 2, y: 0 }, 4);\n * // pts.length === 5; pts[0] === { x: 0, y: 0 }; pts[4] === { x: 2, y: 0 }\n * void pts;\n */\nexport function sampleQuadratic(\n p0: Point2,\n p1: Point2,\n p2: Point2,\n samples: number,\n): ReadonlyArray<Point2> {\n const out: Point2[] = [];\n for (let i = 0; i <= samples; i++) {\n out.push(quadraticBezier(p0, p1, p2, i / samples));\n }\n return out;\n}\n\n/**\n * Sample a cubic Bezier into `samples + 1` points evenly spaced in\n * parameter `t ∈ [0, 1]`. Mirrors {@link sampleQuadratic}.\n *\n * @since 1.3\n * @stable\n * @example\n * const pts = sampleCubic(\n * { x: 0, y: 0 }, { x: 1, y: 3 }, { x: 2, y: 3 }, { x: 3, y: 0 }, 8,\n * );\n * // pts.length === 9; pts[0] === { x: 0, y: 0 }; pts[8] === { x: 3, y: 0 }\n * void pts;\n */\nexport function sampleCubic(\n p0: Point2,\n p1: Point2,\n p2: Point2,\n p3: Point2,\n samples: number,\n): ReadonlyArray<Point2> {\n const out: Point2[] = [];\n for (let i = 0; i <= samples; i++) {\n out.push(cubicBezier(p0, p1, p2, p3, i / samples));\n }\n return out;\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Point2 } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Vertical direction of a chevron glyph. `"up"` puts the tip above the
|
|
4
|
+
* anchor (smaller y); `"down"` puts the tip below (larger y).
|
|
5
|
+
*
|
|
6
|
+
* @since 1.3
|
|
7
|
+
* @stable
|
|
8
|
+
* @example
|
|
9
|
+
* const d: ChevronDirection = "up";
|
|
10
|
+
* void d;
|
|
11
|
+
*/
|
|
12
|
+
export type ChevronDirection = "up" | "down";
|
|
13
|
+
/**
|
|
14
|
+
* Return the three vertices of a filled triangle chevron glyph centred
|
|
15
|
+
* on `at`, pointing up or down. The order is `[tip, baseLeft,
|
|
16
|
+
* baseRight]` so a caller paints a closed polyline. Pure — no `ctx`.
|
|
17
|
+
* Consumed by the `arrow-mark-up` / `arrow-mark-down` decomposers.
|
|
18
|
+
*
|
|
19
|
+
* `baseWidth` defaults to 12 CSS px, `height` to 10 CSS px.
|
|
20
|
+
*
|
|
21
|
+
* @since 1.3
|
|
22
|
+
* @stable
|
|
23
|
+
* @example
|
|
24
|
+
* const tri = chevronPolygon({ x: 100, y: 100 }, "up");
|
|
25
|
+
* // tri[0].y === 95 (tip is half the height above the anchor)
|
|
26
|
+
* void tri;
|
|
27
|
+
*/
|
|
28
|
+
export declare function chevronPolygon(at: Point2, direction: ChevronDirection, baseWidth?: number, height?: number): ReadonlyArray<Point2>;
|
|
29
|
+
//# sourceMappingURL=chevron.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chevron.d.ts","sourceRoot":"","sources":["../../../src/geometry/_lib/chevron.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAK1C;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,MAAM,CAAC;AAE7C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC1B,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,gBAAgB,EAC3B,SAAS,GAAE,MAA2B,EACtC,MAAM,GAAE,MAAuB,GAChC,aAAa,CAAC,MAAM,CAAC,CAUvB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Copyright (c) 2026 Invinite. Licensed under the MIT License.
|
|
2
|
+
// See the LICENSE file in the repo root for full license text.
|
|
3
|
+
//
|
|
4
|
+
// Chevron glyph geometry ported from
|
|
5
|
+
// invinite/src/components/trading-chart/tools/arrow-mark-up-tool.ts,
|
|
6
|
+
// invinite/src/components/trading-chart/tools/arrow-mark-down-tool.ts,
|
|
7
|
+
// commit 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite.
|
|
8
|
+
// Re-licensed MIT for chartlang.
|
|
9
|
+
const DEFAULT_BASE_WIDTH = 12;
|
|
10
|
+
const DEFAULT_HEIGHT = 10;
|
|
11
|
+
/**
|
|
12
|
+
* Return the three vertices of a filled triangle chevron glyph centred
|
|
13
|
+
* on `at`, pointing up or down. The order is `[tip, baseLeft,
|
|
14
|
+
* baseRight]` so a caller paints a closed polyline. Pure — no `ctx`.
|
|
15
|
+
* Consumed by the `arrow-mark-up` / `arrow-mark-down` decomposers.
|
|
16
|
+
*
|
|
17
|
+
* `baseWidth` defaults to 12 CSS px, `height` to 10 CSS px.
|
|
18
|
+
*
|
|
19
|
+
* @since 1.3
|
|
20
|
+
* @stable
|
|
21
|
+
* @example
|
|
22
|
+
* const tri = chevronPolygon({ x: 100, y: 100 }, "up");
|
|
23
|
+
* // tri[0].y === 95 (tip is half the height above the anchor)
|
|
24
|
+
* void tri;
|
|
25
|
+
*/
|
|
26
|
+
export function chevronPolygon(at, direction, baseWidth = DEFAULT_BASE_WIDTH, height = DEFAULT_HEIGHT) {
|
|
27
|
+
const halfWidth = baseWidth / 2;
|
|
28
|
+
const halfHeight = height / 2;
|
|
29
|
+
const tipY = direction === "up" ? at.y - halfHeight : at.y + halfHeight;
|
|
30
|
+
const baseY = direction === "up" ? at.y + halfHeight : at.y - halfHeight;
|
|
31
|
+
return [
|
|
32
|
+
{ x: at.x, y: tipY },
|
|
33
|
+
{ x: at.x - halfWidth, y: baseY },
|
|
34
|
+
{ x: at.x + halfWidth, y: baseY },
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=chevron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chevron.js","sourceRoot":"","sources":["../../../src/geometry/_lib/chevron.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAC/D,EAAE;AACF,qCAAqC;AACrC,uEAAuE;AACvE,yEAAyE;AACzE,iEAAiE;AACjE,iCAAiC;AAIjC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAC9B,MAAM,cAAc,GAAG,EAAE,CAAC;AAc1B;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,cAAc,CAC1B,EAAU,EACV,SAA2B,EAC3B,YAAoB,kBAAkB,EACtC,SAAiB,cAAc;IAE/B,MAAM,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC;IAChC,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC;IACxE,MAAM,KAAK,GAAG,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC;IACzE,OAAO;QACH,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE;QACpB,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE;QACjC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE;KACpC,CAAC;AACN,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n//\n// Chevron glyph geometry ported from\n// invinite/src/components/trading-chart/tools/arrow-mark-up-tool.ts,\n// invinite/src/components/trading-chart/tools/arrow-mark-down-tool.ts,\n// commit 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite.\n// Re-licensed MIT for chartlang.\n\nimport type { Point2 } from \"../types.js\";\n\nconst DEFAULT_BASE_WIDTH = 12;\nconst DEFAULT_HEIGHT = 10;\n\n/**\n * Vertical direction of a chevron glyph. `\"up\"` puts the tip above the\n * anchor (smaller y); `\"down\"` puts the tip below (larger y).\n *\n * @since 1.3\n * @stable\n * @example\n * const d: ChevronDirection = \"up\";\n * void d;\n */\nexport type ChevronDirection = \"up\" | \"down\";\n\n/**\n * Return the three vertices of a filled triangle chevron glyph centred\n * on `at`, pointing up or down. The order is `[tip, baseLeft,\n * baseRight]` so a caller paints a closed polyline. Pure — no `ctx`.\n * Consumed by the `arrow-mark-up` / `arrow-mark-down` decomposers.\n *\n * `baseWidth` defaults to 12 CSS px, `height` to 10 CSS px.\n *\n * @since 1.3\n * @stable\n * @example\n * const tri = chevronPolygon({ x: 100, y: 100 }, \"up\");\n * // tri[0].y === 95 (tip is half the height above the anchor)\n * void tri;\n */\nexport function chevronPolygon(\n at: Point2,\n direction: ChevronDirection,\n baseWidth: number = DEFAULT_BASE_WIDTH,\n height: number = DEFAULT_HEIGHT,\n): ReadonlyArray<Point2> {\n const halfWidth = baseWidth / 2;\n const halfHeight = height / 2;\n const tipY = direction === \"up\" ? at.y - halfHeight : at.y + halfHeight;\n const baseY = direction === \"up\" ? at.y + halfHeight : at.y - halfHeight;\n return [\n { x: at.x, y: tipY },\n { x: at.x - halfWidth, y: baseY },\n { x: at.x + halfWidth, y: baseY },\n ];\n}\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { LineStyle } from "@invinite-org/chartlang-core";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical `setLineDash` segment array for each {@link LineStyle}.
|
|
4
|
+
* Copied (not moved) from the canvas2d adapter's `render/lineDash.ts`,
|
|
5
|
+
* which still serves the surviving plot renderers there. Decomposers
|
|
6
|
+
* map a `LineStyle` to a `StrokeStyle.dash` through this helper.
|
|
7
|
+
*
|
|
8
|
+
* `"solid"` → `[]`, `"dashed"` → `[6, 4]`, `"dotted"` → `[2, 4]`.
|
|
9
|
+
*
|
|
10
|
+
* @since 1.3
|
|
11
|
+
* @stable
|
|
12
|
+
* @example
|
|
13
|
+
* const d = dashPattern("dashed"); // [6, 4]
|
|
14
|
+
* void d;
|
|
15
|
+
*/
|
|
16
|
+
export declare function dashPattern(style: LineStyle): ReadonlyArray<number>;
|
|
17
|
+
/**
|
|
18
|
+
* The `setLineDash` segment array for a solid stroke — an empty array.
|
|
19
|
+
* Shared by the decomposers that emit always-solid primitives (fib
|
|
20
|
+
* arcs, gann/pitchfork rays, container borders) so the `"solid"` dash
|
|
21
|
+
* constant lives in one place instead of a per-file re-declaration.
|
|
22
|
+
*
|
|
23
|
+
* @since 1.3
|
|
24
|
+
* @stable
|
|
25
|
+
* @example
|
|
26
|
+
* const d = SOLID_DASH; // []
|
|
27
|
+
* void d;
|
|
28
|
+
*/
|
|
29
|
+
export declare const SOLID_DASH: ReadonlyArray<number>;
|
|
30
|
+
//# sourceMappingURL=dash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dash.d.ts","sourceRoot":"","sources":["../../../src/geometry/_lib/dash.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CASnE;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,EAAE,aAAa,CAAC,MAAM,CAAM,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Copyright (c) 2026 Invinite. Licensed under the MIT License.
|
|
2
|
+
// See the LICENSE file in the repo root for full license text.
|
|
3
|
+
/**
|
|
4
|
+
* Canonical `setLineDash` segment array for each {@link LineStyle}.
|
|
5
|
+
* Copied (not moved) from the canvas2d adapter's `render/lineDash.ts`,
|
|
6
|
+
* which still serves the surviving plot renderers there. Decomposers
|
|
7
|
+
* map a `LineStyle` to a `StrokeStyle.dash` through this helper.
|
|
8
|
+
*
|
|
9
|
+
* `"solid"` → `[]`, `"dashed"` → `[6, 4]`, `"dotted"` → `[2, 4]`.
|
|
10
|
+
*
|
|
11
|
+
* @since 1.3
|
|
12
|
+
* @stable
|
|
13
|
+
* @example
|
|
14
|
+
* const d = dashPattern("dashed"); // [6, 4]
|
|
15
|
+
* void d;
|
|
16
|
+
*/
|
|
17
|
+
export function dashPattern(style) {
|
|
18
|
+
switch (style) {
|
|
19
|
+
case "solid":
|
|
20
|
+
return [];
|
|
21
|
+
case "dashed":
|
|
22
|
+
return [6, 4];
|
|
23
|
+
case "dotted":
|
|
24
|
+
return [2, 4];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The `setLineDash` segment array for a solid stroke — an empty array.
|
|
29
|
+
* Shared by the decomposers that emit always-solid primitives (fib
|
|
30
|
+
* arcs, gann/pitchfork rays, container borders) so the `"solid"` dash
|
|
31
|
+
* constant lives in one place instead of a per-file re-declaration.
|
|
32
|
+
*
|
|
33
|
+
* @since 1.3
|
|
34
|
+
* @stable
|
|
35
|
+
* @example
|
|
36
|
+
* const d = SOLID_DASH; // []
|
|
37
|
+
* void d;
|
|
38
|
+
*/
|
|
39
|
+
export const SOLID_DASH = [];
|
|
40
|
+
//# sourceMappingURL=dash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dash.js","sourceRoot":"","sources":["../../../src/geometry/_lib/dash.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAI/D;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CAAC,KAAgB;IACxC,QAAQ,KAAK,EAAE,CAAC;QACZ,KAAK,OAAO;YACR,OAAO,EAAE,CAAC;QACd,KAAK,QAAQ;YACT,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAClB,KAAK,QAAQ;YACT,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACtB,CAAC;AACL,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,UAAU,GAA0B,EAAE,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type { LineStyle } from \"@invinite-org/chartlang-core\";\n\n/**\n * Canonical `setLineDash` segment array for each {@link LineStyle}.\n * Copied (not moved) from the canvas2d adapter's `render/lineDash.ts`,\n * which still serves the surviving plot renderers there. Decomposers\n * map a `LineStyle` to a `StrokeStyle.dash` through this helper.\n *\n * `\"solid\"` → `[]`, `\"dashed\"` → `[6, 4]`, `\"dotted\"` → `[2, 4]`.\n *\n * @since 1.3\n * @stable\n * @example\n * const d = dashPattern(\"dashed\"); // [6, 4]\n * void d;\n */\nexport function dashPattern(style: LineStyle): ReadonlyArray<number> {\n switch (style) {\n case \"solid\":\n return [];\n case \"dashed\":\n return [6, 4];\n case \"dotted\":\n return [2, 4];\n }\n}\n\n/**\n * The `setLineDash` segment array for a solid stroke — an empty array.\n * Shared by the decomposers that emit always-solid primitives (fib\n * arcs, gann/pitchfork rays, container borders) so the `\"solid\"` dash\n * constant lives in one place instead of a per-file re-declaration.\n *\n * @since 1.3\n * @stable\n * @example\n * const d = SOLID_DASH; // []\n * void d;\n */\nexport const SOLID_DASH: ReadonlyArray<number> = [];\n"]}
|