@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.
Files changed (143) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +7 -0
  3. package/dist/canvas/index.d.ts +5 -0
  4. package/dist/canvas/index.d.ts.map +1 -0
  5. package/dist/canvas/index.js +5 -0
  6. package/dist/canvas/index.js.map +1 -0
  7. package/dist/canvas/mockContext.d.ts +168 -0
  8. package/dist/canvas/mockContext.d.ts.map +1 -0
  9. package/dist/canvas/mockContext.js +198 -0
  10. package/dist/canvas/mockContext.js.map +1 -0
  11. package/dist/canvas/paintPrimitive.d.ts +35 -0
  12. package/dist/canvas/paintPrimitive.d.ts.map +1 -0
  13. package/dist/canvas/paintPrimitive.js +171 -0
  14. package/dist/canvas/paintPrimitive.js.map +1 -0
  15. package/dist/canvas/renderCtx.d.ts +40 -0
  16. package/dist/canvas/renderCtx.d.ts.map +1 -0
  17. package/dist/canvas/renderCtx.js +4 -0
  18. package/dist/canvas/renderCtx.js.map +1 -0
  19. package/dist/geometry/_lib/arrowhead.d.ts +18 -0
  20. package/dist/geometry/_lib/arrowhead.d.ts.map +1 -0
  21. package/dist/geometry/_lib/arrowhead.js +38 -0
  22. package/dist/geometry/_lib/arrowhead.js.map +1 -0
  23. package/dist/geometry/_lib/bezier.d.ts +57 -0
  24. package/dist/geometry/_lib/bezier.d.ts.map +1 -0
  25. package/dist/geometry/_lib/bezier.js +84 -0
  26. package/dist/geometry/_lib/bezier.js.map +1 -0
  27. package/dist/geometry/_lib/chevron.d.ts +29 -0
  28. package/dist/geometry/_lib/chevron.d.ts.map +1 -0
  29. package/dist/geometry/_lib/chevron.js +37 -0
  30. package/dist/geometry/_lib/chevron.js.map +1 -0
  31. package/dist/geometry/_lib/dash.d.ts +30 -0
  32. package/dist/geometry/_lib/dash.d.ts.map +1 -0
  33. package/dist/geometry/_lib/dash.js +40 -0
  34. package/dist/geometry/_lib/dash.js.map +1 -0
  35. package/dist/geometry/_lib/fibLevels.d.ts +36 -0
  36. package/dist/geometry/_lib/fibLevels.d.ts.map +1 -0
  37. package/dist/geometry/_lib/fibLevels.js +44 -0
  38. package/dist/geometry/_lib/fibLevels.js.map +1 -0
  39. package/dist/geometry/_lib/gannLevels.d.ts +54 -0
  40. package/dist/geometry/_lib/gannLevels.d.ts.map +1 -0
  41. package/dist/geometry/_lib/gannLevels.js +88 -0
  42. package/dist/geometry/_lib/gannLevels.js.map +1 -0
  43. package/dist/geometry/_lib/lineExtend.d.ts +31 -0
  44. package/dist/geometry/_lib/lineExtend.d.ts.map +1 -0
  45. package/dist/geometry/_lib/lineExtend.js +48 -0
  46. package/dist/geometry/_lib/lineExtend.js.map +1 -0
  47. package/dist/geometry/_lib/namedPolyline.d.ts +25 -0
  48. package/dist/geometry/_lib/namedPolyline.d.ts.map +1 -0
  49. package/dist/geometry/_lib/namedPolyline.js +64 -0
  50. package/dist/geometry/_lib/namedPolyline.js.map +1 -0
  51. package/dist/geometry/_lib/pitchforkGeom.d.ts +46 -0
  52. package/dist/geometry/_lib/pitchforkGeom.d.ts.map +1 -0
  53. package/dist/geometry/_lib/pitchforkGeom.js +70 -0
  54. package/dist/geometry/_lib/pitchforkGeom.js.map +1 -0
  55. package/dist/geometry/_lib/shapeStyle.d.ts +21 -0
  56. package/dist/geometry/_lib/shapeStyle.d.ts.map +1 -0
  57. package/dist/geometry/_lib/shapeStyle.js +41 -0
  58. package/dist/geometry/_lib/shapeStyle.js.map +1 -0
  59. package/dist/geometry/_lib/strokeStyle.d.ts +34 -0
  60. package/dist/geometry/_lib/strokeStyle.d.ts.map +1 -0
  61. package/dist/geometry/_lib/strokeStyle.js +26 -0
  62. package/dist/geometry/_lib/strokeStyle.js.map +1 -0
  63. package/dist/geometry/_lib/textStyle.d.ts +70 -0
  64. package/dist/geometry/_lib/textStyle.d.ts.map +1 -0
  65. package/dist/geometry/_lib/textStyle.js +78 -0
  66. package/dist/geometry/_lib/textStyle.js.map +1 -0
  67. package/dist/geometry/decompose.d.ts +28 -0
  68. package/dist/geometry/decompose.d.ts.map +1 -0
  69. package/dist/geometry/decompose.js +176 -0
  70. package/dist/geometry/decompose.js.map +1 -0
  71. package/dist/geometry/index.d.ts +4 -0
  72. package/dist/geometry/index.d.ts.map +1 -0
  73. package/dist/geometry/index.js +5 -0
  74. package/dist/geometry/index.js.map +1 -0
  75. package/dist/geometry/kinds/annotations.d.ts +77 -0
  76. package/dist/geometry/kinds/annotations.d.ts.map +1 -0
  77. package/dist/geometry/kinds/annotations.js +219 -0
  78. package/dist/geometry/kinds/annotations.js.map +1 -0
  79. package/dist/geometry/kinds/boxes.d.ts +116 -0
  80. package/dist/geometry/kinds/boxes.d.ts.map +1 -0
  81. package/dist/geometry/kinds/boxes.js +285 -0
  82. package/dist/geometry/kinds/boxes.js.map +1 -0
  83. package/dist/geometry/kinds/channels.d.ts +72 -0
  84. package/dist/geometry/kinds/channels.d.ts.map +1 -0
  85. package/dist/geometry/kinds/channels.js +148 -0
  86. package/dist/geometry/kinds/channels.js.map +1 -0
  87. package/dist/geometry/kinds/containers.d.ts +54 -0
  88. package/dist/geometry/kinds/containers.d.ts.map +1 -0
  89. package/dist/geometry/kinds/containers.js +268 -0
  90. package/dist/geometry/kinds/containers.js.map +1 -0
  91. package/dist/geometry/kinds/curves.d.ts +53 -0
  92. package/dist/geometry/kinds/curves.d.ts.map +1 -0
  93. package/dist/geometry/kinds/curves.js +110 -0
  94. package/dist/geometry/kinds/curves.js.map +1 -0
  95. package/dist/geometry/kinds/cycles.d.ts +52 -0
  96. package/dist/geometry/kinds/cycles.d.ts.map +1 -0
  97. package/dist/geometry/kinds/cycles.js +158 -0
  98. package/dist/geometry/kinds/cycles.js.map +1 -0
  99. package/dist/geometry/kinds/elliott.d.ts +73 -0
  100. package/dist/geometry/kinds/elliott.d.ts.map +1 -0
  101. package/dist/geometry/kinds/elliott.js +116 -0
  102. package/dist/geometry/kinds/elliott.js.map +1 -0
  103. package/dist/geometry/kinds/fibonacci.d.ts +166 -0
  104. package/dist/geometry/kinds/fibonacci.d.ts.map +1 -0
  105. package/dist/geometry/kinds/fibonacci.js +458 -0
  106. package/dist/geometry/kinds/fibonacci.js.map +1 -0
  107. package/dist/geometry/kinds/freehand.d.ts +53 -0
  108. package/dist/geometry/kinds/freehand.d.ts.map +1 -0
  109. package/dist/geometry/kinds/freehand.js +115 -0
  110. package/dist/geometry/kinds/freehand.js.map +1 -0
  111. package/dist/geometry/kinds/gann.d.ts +63 -0
  112. package/dist/geometry/kinds/gann.d.ts.map +1 -0
  113. package/dist/geometry/kinds/gann.js +153 -0
  114. package/dist/geometry/kinds/gann.js.map +1 -0
  115. package/dist/geometry/kinds/lines.d.ts +90 -0
  116. package/dist/geometry/kinds/lines.d.ts.map +1 -0
  117. package/dist/geometry/kinds/lines.js +201 -0
  118. package/dist/geometry/kinds/lines.js.map +1 -0
  119. package/dist/geometry/kinds/marker.d.ts +21 -0
  120. package/dist/geometry/kinds/marker.d.ts.map +1 -0
  121. package/dist/geometry/kinds/marker.js +47 -0
  122. package/dist/geometry/kinds/marker.js.map +1 -0
  123. package/dist/geometry/kinds/patterns.d.ts +85 -0
  124. package/dist/geometry/kinds/patterns.d.ts.map +1 -0
  125. package/dist/geometry/kinds/patterns.js +133 -0
  126. package/dist/geometry/kinds/patterns.js.map +1 -0
  127. package/dist/geometry/kinds/pitchforks.d.ts +36 -0
  128. package/dist/geometry/kinds/pitchforks.d.ts.map +1 -0
  129. package/dist/geometry/kinds/pitchforks.js +109 -0
  130. package/dist/geometry/kinds/pitchforks.js.map +1 -0
  131. package/dist/geometry/project.d.ts +50 -0
  132. package/dist/geometry/project.d.ts.map +1 -0
  133. package/dist/geometry/project.js +62 -0
  134. package/dist/geometry/project.js.map +1 -0
  135. package/dist/geometry/types.d.ts +146 -0
  136. package/dist/geometry/types.d.ts.map +1 -0
  137. package/dist/geometry/types.js +4 -0
  138. package/dist/geometry/types.js.map +1 -0
  139. package/dist/index.d.ts +2 -0
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.js +1 -0
  142. package/dist/index.js.map +1 -1
  143. 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,4 @@
1
+ // Copyright (c) 2026 Invinite. Licensed under the MIT License.
2
+ // See the LICENSE file in the repo root for full license text.
3
+ export {};
4
+ //# sourceMappingURL=renderCtx.js.map
@@ -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"]}