@invinite-org/chartlang-adapter-kit 1.2.1 → 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 +157 -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/capabilities/capabilities.d.ts +9 -7
- package/dist/capabilities/capabilities.d.ts.map +1 -1
- package/dist/capabilities/capabilities.js +14 -8
- package/dist/capabilities/capabilities.js.map +1 -1
- 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/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/validation/validateEmission.d.ts.map +1 -1
- package/dist/validation/validateEmission.js +47 -0
- package/dist/validation/validateEmission.js.map +1 -1
- package/package.json +9 -2
|
@@ -0,0 +1,458 @@
|
|
|
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
|
+
// Fibonacci geometry moved from the canvas2d adapter's per-kind
|
|
5
|
+
// renderers
|
|
6
|
+
// examples/canvas2d-adapter/src/render/draw/{fibRetracement,
|
|
7
|
+
// fibTrendExtension,fibChannel,fibTimeZone,fibWedge,fibSpeedFan,
|
|
8
|
+
// fibSpeedArcs,fibSpiral,fibCircles,fibTrendTime}.ts.
|
|
9
|
+
// The originating math is invinite's fib-* tools (commit
|
|
10
|
+
// 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite); re-licensed
|
|
11
|
+
// MIT for chartlang.
|
|
12
|
+
import { sampleCubic } from "../_lib/bezier.js";
|
|
13
|
+
import { SOLID_DASH } from "../_lib/dash.js";
|
|
14
|
+
import { FIB_LEVELS, formatLevel } from "../_lib/fibLevels.js";
|
|
15
|
+
import { extendLineSegment } from "../_lib/lineExtend.js";
|
|
16
|
+
import { priceToY, timeToX, worldPointToPixel } from "../project.js";
|
|
17
|
+
const DEFAULT_COLOR = "#facc15";
|
|
18
|
+
const DEFAULT_LINE_WIDTH = 1;
|
|
19
|
+
const LABEL_FONT = "12px sans-serif";
|
|
20
|
+
const LABEL_OFFSET_PX = 4;
|
|
21
|
+
const LABEL_TOP_PX = 12;
|
|
22
|
+
const LABEL_OFFSET_FRACTION = 0.25;
|
|
23
|
+
const TAU = Math.PI * 2;
|
|
24
|
+
/**
|
|
25
|
+
* Build a level-line label `text` primitive. Shared by every fib
|
|
26
|
+
* decomposer so the font / colour / alignment convention lives once.
|
|
27
|
+
* Price- and radius-axis fibs use `baseline: "middle"`; time-axis fibs
|
|
28
|
+
* pass `baseline: "top"`.
|
|
29
|
+
*/
|
|
30
|
+
function fibLabel(text, x, y, color, baseline) {
|
|
31
|
+
return { kind: "text", x, y, text, color, font: LABEL_FONT, align: "left", baseline };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Decompose a `fib-retracement` drawing — one horizontal level line per
|
|
35
|
+
* Fibonacci ratio between `anchors[0].price` and `anchors[1].price`,
|
|
36
|
+
* each honouring `style.extendLeft` / `style.extendRight` via
|
|
37
|
+
* {@link extendLineSegment}. `style.levels` overrides {@link FIB_LEVELS};
|
|
38
|
+
* `style.showLabels === true` appends a right-edge `formatLevel` label
|
|
39
|
+
* per rail.
|
|
40
|
+
*
|
|
41
|
+
* @since 1.3
|
|
42
|
+
* @stable
|
|
43
|
+
* @example
|
|
44
|
+
* declare const s: FibRetracementState;
|
|
45
|
+
* declare const v: Viewport;
|
|
46
|
+
* const prims = decomposeFibRetracement(s, v);
|
|
47
|
+
* void prims;
|
|
48
|
+
*/
|
|
49
|
+
export function decomposeFibRetracement(state, view) {
|
|
50
|
+
const a = worldPointToPixel(state.anchors[0], view);
|
|
51
|
+
const b = worldPointToPixel(state.anchors[1], view);
|
|
52
|
+
const color = state.style.color ?? DEFAULT_COLOR;
|
|
53
|
+
const levels = state.style.levels ?? FIB_LEVELS;
|
|
54
|
+
const fromPrice = state.anchors[0].price;
|
|
55
|
+
const toPrice = state.anchors[1].price;
|
|
56
|
+
const out = [];
|
|
57
|
+
for (const level of levels) {
|
|
58
|
+
const levelPrice = fromPrice + level * (toPrice - fromPrice);
|
|
59
|
+
const levelY = priceToY(levelPrice, view);
|
|
60
|
+
const { from, to } = extendLineSegment({ x: a.x, y: levelY }, { x: b.x, y: levelY }, { extendLeft: state.style.extendLeft, extendRight: state.style.extendRight }, view);
|
|
61
|
+
out.push({
|
|
62
|
+
kind: "polyline",
|
|
63
|
+
points: [
|
|
64
|
+
{ x: from.x, y: levelY },
|
|
65
|
+
{ x: to.x, y: levelY },
|
|
66
|
+
],
|
|
67
|
+
closed: false,
|
|
68
|
+
stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },
|
|
69
|
+
});
|
|
70
|
+
if (state.style.showLabels === true) {
|
|
71
|
+
out.push(fibLabel(formatLevel(level), to.x + LABEL_OFFSET_PX, levelY, color, "middle"));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Decompose a `fib-trend-extension` drawing — projects fib-ratio
|
|
78
|
+
* extensions from `anchors[2].price` using the A→B leg's price delta
|
|
79
|
+
* (`anchors[1].price − anchors[0].price`). Each projected price is one
|
|
80
|
+
* horizontal line from `timeToX(anchors[2].time)` rightward to the
|
|
81
|
+
* viewport edge. `style.levels` overrides {@link FIB_LEVELS};
|
|
82
|
+
* `showLabels` appends a label past the right edge.
|
|
83
|
+
*
|
|
84
|
+
* @since 1.3
|
|
85
|
+
* @stable
|
|
86
|
+
* @example
|
|
87
|
+
* declare const s: FibTrendExtensionState;
|
|
88
|
+
* declare const v: Viewport;
|
|
89
|
+
* const prims = decomposeFibTrendExtension(s, v);
|
|
90
|
+
* void prims;
|
|
91
|
+
*/
|
|
92
|
+
export function decomposeFibTrendExtension(state, view) {
|
|
93
|
+
const [A, B, C] = state.anchors;
|
|
94
|
+
const color = state.style.color ?? DEFAULT_COLOR;
|
|
95
|
+
const levels = state.style.levels ?? FIB_LEVELS;
|
|
96
|
+
const priceDelta = B.price - A.price;
|
|
97
|
+
const startX = timeToX(C.time, view);
|
|
98
|
+
const endX = view.pxWidth;
|
|
99
|
+
const out = [];
|
|
100
|
+
for (const level of levels) {
|
|
101
|
+
const levelPrice = C.price + level * priceDelta;
|
|
102
|
+
const levelY = priceToY(levelPrice, view);
|
|
103
|
+
out.push({
|
|
104
|
+
kind: "polyline",
|
|
105
|
+
points: [
|
|
106
|
+
{ x: startX, y: levelY },
|
|
107
|
+
{ x: endX, y: levelY },
|
|
108
|
+
],
|
|
109
|
+
closed: false,
|
|
110
|
+
stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },
|
|
111
|
+
});
|
|
112
|
+
if (state.style.showLabels === true) {
|
|
113
|
+
out.push(fibLabel(formatLevel(level), endX + LABEL_OFFSET_PX, levelY, color, "middle"));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Decompose a `fib-channel` drawing — one parallel rail per Fibonacci
|
|
120
|
+
* ratio: each rail translates the primary `(anchors[0], anchors[1])`
|
|
121
|
+
* line by `level · (anchors[2].y − anchors[0].y)` in pixel space.
|
|
122
|
+
* `style.levels` overrides {@link FIB_LEVELS}; `showLabels` appends a
|
|
123
|
+
* label at the rail's right endpoint.
|
|
124
|
+
*
|
|
125
|
+
* @since 1.3
|
|
126
|
+
* @stable
|
|
127
|
+
* @example
|
|
128
|
+
* declare const s: FibChannelState;
|
|
129
|
+
* declare const v: Viewport;
|
|
130
|
+
* const prims = decomposeFibChannel(s, v);
|
|
131
|
+
* void prims;
|
|
132
|
+
*/
|
|
133
|
+
export function decomposeFibChannel(state, view) {
|
|
134
|
+
const a = worldPointToPixel(state.anchors[0], view);
|
|
135
|
+
const b = worldPointToPixel(state.anchors[1], view);
|
|
136
|
+
const c = worldPointToPixel(state.anchors[2], view);
|
|
137
|
+
const color = state.style.color ?? DEFAULT_COLOR;
|
|
138
|
+
const levels = state.style.levels ?? FIB_LEVELS;
|
|
139
|
+
const offsetUnit = c.y - a.y;
|
|
140
|
+
const out = [];
|
|
141
|
+
for (const level of levels) {
|
|
142
|
+
const offsetY = level * offsetUnit;
|
|
143
|
+
const fromY = a.y + offsetY;
|
|
144
|
+
const toY = b.y + offsetY;
|
|
145
|
+
out.push({
|
|
146
|
+
kind: "polyline",
|
|
147
|
+
points: [
|
|
148
|
+
{ x: a.x, y: fromY },
|
|
149
|
+
{ x: b.x, y: toY },
|
|
150
|
+
],
|
|
151
|
+
closed: false,
|
|
152
|
+
stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },
|
|
153
|
+
});
|
|
154
|
+
if (state.style.showLabels === true) {
|
|
155
|
+
out.push(fibLabel(formatLevel(level), b.x + LABEL_OFFSET_PX, toY, color, "middle"));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Decompose a `fib-time-zone` drawing — vertical lines at fib-ratio
|
|
162
|
+
* spaced times `anchors[0].time + level · (anchors[1].time −
|
|
163
|
+
* anchors[0].time)`, each spanning the full viewport height.
|
|
164
|
+
* `style.levels` overrides {@link FIB_LEVELS}; `showLabels` appends a
|
|
165
|
+
* top-anchored label.
|
|
166
|
+
*
|
|
167
|
+
* @since 1.3
|
|
168
|
+
* @stable
|
|
169
|
+
* @example
|
|
170
|
+
* declare const s: FibTimeZoneState;
|
|
171
|
+
* declare const v: Viewport;
|
|
172
|
+
* const prims = decomposeFibTimeZone(s, v);
|
|
173
|
+
* void prims;
|
|
174
|
+
*/
|
|
175
|
+
export function decomposeFibTimeZone(state, view) {
|
|
176
|
+
const [A, B] = state.anchors;
|
|
177
|
+
const color = state.style.color ?? DEFAULT_COLOR;
|
|
178
|
+
const levels = state.style.levels ?? FIB_LEVELS;
|
|
179
|
+
const timeDelta = B.time - A.time;
|
|
180
|
+
const out = [];
|
|
181
|
+
for (const level of levels) {
|
|
182
|
+
const tx = timeToX(A.time + level * timeDelta, view);
|
|
183
|
+
out.push({
|
|
184
|
+
kind: "polyline",
|
|
185
|
+
points: [
|
|
186
|
+
{ x: tx, y: 0 },
|
|
187
|
+
{ x: tx, y: view.pxHeight },
|
|
188
|
+
],
|
|
189
|
+
closed: false,
|
|
190
|
+
stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },
|
|
191
|
+
});
|
|
192
|
+
if (state.style.showLabels === true) {
|
|
193
|
+
out.push(fibLabel(formatLevel(level), tx + LABEL_OFFSET_PX, LABEL_TOP_PX, color, "top"));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return out;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Decompose a `fib-trend-time` drawing — vertical lines at fib-spaced
|
|
200
|
+
* times anchored at `anchors[2]`: `t = C.time + level · (B.time −
|
|
201
|
+
* A.time)`. Mirrors `fib-time-zone` but uses the A→B leg as the
|
|
202
|
+
* time-delta unit projected from C. `showLabels` appends a top label.
|
|
203
|
+
*
|
|
204
|
+
* @since 1.3
|
|
205
|
+
* @stable
|
|
206
|
+
* @example
|
|
207
|
+
* declare const s: FibTrendTimeState;
|
|
208
|
+
* declare const v: Viewport;
|
|
209
|
+
* const prims = decomposeFibTrendTime(s, v);
|
|
210
|
+
* void prims;
|
|
211
|
+
*/
|
|
212
|
+
export function decomposeFibTrendTime(state, view) {
|
|
213
|
+
const [A, B, C] = state.anchors;
|
|
214
|
+
const color = state.style.color ?? DEFAULT_COLOR;
|
|
215
|
+
const levels = state.style.levels ?? FIB_LEVELS;
|
|
216
|
+
const timeDelta = B.time - A.time;
|
|
217
|
+
const out = [];
|
|
218
|
+
for (const level of levels) {
|
|
219
|
+
const tx = timeToX(C.time + level * timeDelta, view);
|
|
220
|
+
out.push({
|
|
221
|
+
kind: "polyline",
|
|
222
|
+
points: [
|
|
223
|
+
{ x: tx, y: 0 },
|
|
224
|
+
{ x: tx, y: view.pxHeight },
|
|
225
|
+
],
|
|
226
|
+
closed: false,
|
|
227
|
+
stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },
|
|
228
|
+
});
|
|
229
|
+
if (state.style.showLabels === true) {
|
|
230
|
+
out.push(fibLabel(formatLevel(level), tx + LABEL_OFFSET_PX, LABEL_TOP_PX, color, "top"));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return out;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Decompose a `fib-wedge` drawing — a fan of rays from `anchors[0]` (the
|
|
237
|
+
* pivot) at fib-ratio-interpolated angles between the pivot→`anchors[1]`
|
|
238
|
+
* and pivot→`anchors[2]` direction vectors. Ray length is
|
|
239
|
+
* `max(pxWidth, pxHeight) · 2` so strokes always exit the viewport; a
|
|
240
|
+
* degenerate (zero-magnitude) direction skips that level. `showLabels`
|
|
241
|
+
* appends a label a quarter of the way along each ray.
|
|
242
|
+
*
|
|
243
|
+
* @since 1.3
|
|
244
|
+
* @stable
|
|
245
|
+
* @example
|
|
246
|
+
* declare const s: FibWedgeState;
|
|
247
|
+
* declare const v: Viewport;
|
|
248
|
+
* const prims = decomposeFibWedge(s, v);
|
|
249
|
+
* void prims;
|
|
250
|
+
*/
|
|
251
|
+
export function decomposeFibWedge(state, view) {
|
|
252
|
+
const pivot = worldPointToPixel(state.anchors[0], view);
|
|
253
|
+
const r1 = worldPointToPixel(state.anchors[1], view);
|
|
254
|
+
const r2 = worldPointToPixel(state.anchors[2], view);
|
|
255
|
+
const color = state.style.color ?? DEFAULT_COLOR;
|
|
256
|
+
const levels = state.style.levels ?? FIB_LEVELS;
|
|
257
|
+
const d1x = r1.x - pivot.x;
|
|
258
|
+
const d1y = r1.y - pivot.y;
|
|
259
|
+
const d2x = r2.x - pivot.x;
|
|
260
|
+
const d2y = r2.y - pivot.y;
|
|
261
|
+
const rayLength = Math.max(view.pxWidth, view.pxHeight) * 2;
|
|
262
|
+
const out = [];
|
|
263
|
+
for (const level of levels) {
|
|
264
|
+
const dx = d1x + level * (d2x - d1x);
|
|
265
|
+
const dy = d1y + level * (d2y - d1y);
|
|
266
|
+
const mag = Math.hypot(dx, dy);
|
|
267
|
+
if (mag === 0)
|
|
268
|
+
continue;
|
|
269
|
+
const ux = dx / mag;
|
|
270
|
+
const uy = dy / mag;
|
|
271
|
+
out.push({
|
|
272
|
+
kind: "polyline",
|
|
273
|
+
points: [pivot, { x: pivot.x + ux * rayLength, y: pivot.y + uy * rayLength }],
|
|
274
|
+
closed: false,
|
|
275
|
+
stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },
|
|
276
|
+
});
|
|
277
|
+
if (state.style.showLabels === true) {
|
|
278
|
+
out.push(fibLabel(formatLevel(level), pivot.x + ux * rayLength * LABEL_OFFSET_FRACTION, pivot.y + uy * rayLength * LABEL_OFFSET_FRACTION, color, "middle"));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return out;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Decompose a `fib-speed-fan` drawing — a fan of rays from `anchors[0]`.
|
|
285
|
+
* Each ray scales the A→B y-delta by a fib ratio while keeping the
|
|
286
|
+
* x-delta constant. Ray length is `max(pxWidth, pxHeight) · 2`; a
|
|
287
|
+
* degenerate direction skips that level. `showLabels` appends a label a
|
|
288
|
+
* quarter of the way along each ray.
|
|
289
|
+
*
|
|
290
|
+
* @since 1.3
|
|
291
|
+
* @stable
|
|
292
|
+
* @example
|
|
293
|
+
* declare const s: FibSpeedFanState;
|
|
294
|
+
* declare const v: Viewport;
|
|
295
|
+
* const prims = decomposeFibSpeedFan(s, v);
|
|
296
|
+
* void prims;
|
|
297
|
+
*/
|
|
298
|
+
export function decomposeFibSpeedFan(state, view) {
|
|
299
|
+
const from = worldPointToPixel(state.anchors[0], view);
|
|
300
|
+
const to = worldPointToPixel(state.anchors[1], view);
|
|
301
|
+
const color = state.style.color ?? DEFAULT_COLOR;
|
|
302
|
+
const levels = state.style.levels ?? FIB_LEVELS;
|
|
303
|
+
const dx = to.x - from.x;
|
|
304
|
+
const dy = to.y - from.y;
|
|
305
|
+
const rayLength = Math.max(view.pxWidth, view.pxHeight) * 2;
|
|
306
|
+
const out = [];
|
|
307
|
+
for (const level of levels) {
|
|
308
|
+
const rdy = level * dy;
|
|
309
|
+
const mag = Math.hypot(dx, rdy);
|
|
310
|
+
if (mag === 0)
|
|
311
|
+
continue;
|
|
312
|
+
const ux = dx / mag;
|
|
313
|
+
const uy = rdy / mag;
|
|
314
|
+
out.push({
|
|
315
|
+
kind: "polyline",
|
|
316
|
+
points: [from, { x: from.x + ux * rayLength, y: from.y + uy * rayLength }],
|
|
317
|
+
closed: false,
|
|
318
|
+
stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },
|
|
319
|
+
});
|
|
320
|
+
if (state.style.showLabels === true) {
|
|
321
|
+
out.push(fibLabel(formatLevel(level), from.x + ux * rayLength * LABEL_OFFSET_FRACTION, from.y + uy * rayLength * LABEL_OFFSET_FRACTION, color, "middle"));
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return out;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Decompose a `fib-speed-arcs` drawing — concentric full circles centred
|
|
328
|
+
* at `anchors[0]` with radii `level · R₀`, `R₀ = |anchors[1] −
|
|
329
|
+
* anchors[0]|` in pixel space. Always-full-circle (half-disk variant
|
|
330
|
+
* deferred). `showLabels` appends a label to the right of each arc.
|
|
331
|
+
*
|
|
332
|
+
* @since 1.3
|
|
333
|
+
* @stable
|
|
334
|
+
* @example
|
|
335
|
+
* declare const s: FibSpeedArcsState;
|
|
336
|
+
* declare const v: Viewport;
|
|
337
|
+
* const prims = decomposeFibSpeedArcs(s, v);
|
|
338
|
+
* void prims;
|
|
339
|
+
*/
|
|
340
|
+
export function decomposeFibSpeedArcs(state, view) {
|
|
341
|
+
const centre = worldPointToPixel(state.anchors[0], view);
|
|
342
|
+
const edge = worldPointToPixel(state.anchors[1], view);
|
|
343
|
+
const color = state.style.color ?? DEFAULT_COLOR;
|
|
344
|
+
const levels = state.style.levels ?? FIB_LEVELS;
|
|
345
|
+
const r0 = Math.hypot(edge.x - centre.x, edge.y - centre.y);
|
|
346
|
+
return concentricArcs(centre, r0, levels, color, state.style.showLabels === true);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Decompose a `fib-circles` drawing — concentric full circles centred at
|
|
350
|
+
* `anchors[0]` with radii `level · R₀`, `R₀ = |anchors[1] − anchors[0]|`
|
|
351
|
+
* (the radius-point distance) in pixel space. Uses fib ratios (not the
|
|
352
|
+
* integer Fibonacci sequence). `showLabels` appends a label to the right
|
|
353
|
+
* of each circle.
|
|
354
|
+
*
|
|
355
|
+
* @since 1.3
|
|
356
|
+
* @stable
|
|
357
|
+
* @example
|
|
358
|
+
* declare const s: FibCirclesState;
|
|
359
|
+
* declare const v: Viewport;
|
|
360
|
+
* const prims = decomposeFibCircles(s, v);
|
|
361
|
+
* void prims;
|
|
362
|
+
*/
|
|
363
|
+
export function decomposeFibCircles(state, view) {
|
|
364
|
+
const centre = worldPointToPixel(state.anchors[0], view);
|
|
365
|
+
const radiusPoint = worldPointToPixel(state.anchors[1], view);
|
|
366
|
+
const color = state.style.color ?? DEFAULT_COLOR;
|
|
367
|
+
const levels = state.style.levels ?? FIB_LEVELS;
|
|
368
|
+
const r0 = Math.hypot(radiusPoint.x - centre.x, radiusPoint.y - centre.y);
|
|
369
|
+
return concentricArcs(centre, r0, levels, color, state.style.showLabels === true);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Shared concentric-arc builder for `fib-speed-arcs` / `fib-circles`:
|
|
373
|
+
* one full `arc` primitive per level at radius `level · r0`, plus an
|
|
374
|
+
* optional right-edge label. Matches the canvas2d source, which emits a
|
|
375
|
+
* (possibly zero-radius) arc per level without an early return.
|
|
376
|
+
*/
|
|
377
|
+
function concentricArcs(centre, r0, levels, color, showLabels) {
|
|
378
|
+
const out = [];
|
|
379
|
+
for (const level of levels) {
|
|
380
|
+
const radius = level * r0;
|
|
381
|
+
out.push({
|
|
382
|
+
kind: "arc",
|
|
383
|
+
cx: centre.x,
|
|
384
|
+
cy: centre.y,
|
|
385
|
+
r: radius,
|
|
386
|
+
start: 0,
|
|
387
|
+
end: TAU,
|
|
388
|
+
closed: false,
|
|
389
|
+
stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },
|
|
390
|
+
});
|
|
391
|
+
if (showLabels) {
|
|
392
|
+
out.push(fibLabel(formatLevel(level), centre.x + radius + LABEL_OFFSET_PX, centre.y, color, "middle"));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return out;
|
|
396
|
+
}
|
|
397
|
+
// Number of quarter-turns sampled = 8 → 2 full rotations.
|
|
398
|
+
const SPIRAL_QUARTERS = 8;
|
|
399
|
+
// Samples per quarter for the cubic Bezier approximation.
|
|
400
|
+
const SPIRAL_SAMPLES_PER_QUARTER = 16;
|
|
401
|
+
// φ ≈ 1.618. Each quarter scales the spiral radius by 1/φ inward.
|
|
402
|
+
const PHI = (1 + Math.sqrt(5)) / 2;
|
|
403
|
+
// Classical Bezier-arc factor for a 90° quadrant: k = 4(√2 − 1)/3.
|
|
404
|
+
const SPIRAL_K = (4 * (Math.sqrt(2) - 1)) / 3;
|
|
405
|
+
/**
|
|
406
|
+
* Decompose a `fib-spiral` drawing — a chained cubic-Bezier
|
|
407
|
+
* approximation of a golden spiral as one open polyline. Each
|
|
408
|
+
* quarter-turn is one cubic Bezier with the classical `k ≈ 0.5523` arc
|
|
409
|
+
* factor; the radius shrinks by `1/φ` per quarter. Centre =
|
|
410
|
+
* `anchors[0]`; initial radius `|anchors[1] − anchors[0]|` in pixel
|
|
411
|
+
* space. A zero initial radius returns `[]` (matching the source's
|
|
412
|
+
* `if (r === 0) return`).
|
|
413
|
+
*
|
|
414
|
+
* @since 1.3
|
|
415
|
+
* @stable
|
|
416
|
+
* @example
|
|
417
|
+
* declare const s: FibSpiralState;
|
|
418
|
+
* declare const v: Viewport;
|
|
419
|
+
* const prims = decomposeFibSpiral(s, v);
|
|
420
|
+
* void prims;
|
|
421
|
+
*/
|
|
422
|
+
export function decomposeFibSpiral(state, view) {
|
|
423
|
+
const centre = worldPointToPixel(state.anchors[0], view);
|
|
424
|
+
const edge = worldPointToPixel(state.anchors[1], view);
|
|
425
|
+
const color = state.style.color ?? DEFAULT_COLOR;
|
|
426
|
+
let r = Math.hypot(edge.x - centre.x, edge.y - centre.y);
|
|
427
|
+
if (r === 0)
|
|
428
|
+
return [];
|
|
429
|
+
const points = [{ x: centre.x + r, y: centre.y }];
|
|
430
|
+
for (let q = 0; q < SPIRAL_QUARTERS; q++) {
|
|
431
|
+
const baseAngle = q * (Math.PI / 2);
|
|
432
|
+
const r1 = r;
|
|
433
|
+
const r2 = r / PHI;
|
|
434
|
+
const cos0 = Math.cos(baseAngle);
|
|
435
|
+
const sin0 = Math.sin(baseAngle);
|
|
436
|
+
const cos1 = Math.cos(baseAngle + Math.PI / 2);
|
|
437
|
+
const sin1 = Math.sin(baseAngle + Math.PI / 2);
|
|
438
|
+
const p0 = { x: centre.x + r1 * cos0, y: centre.y + r1 * sin0 };
|
|
439
|
+
const p3 = { x: centre.x + r2 * cos1, y: centre.y + r2 * sin1 };
|
|
440
|
+
const p1 = { x: p0.x + SPIRAL_K * r1 * cos1, y: p0.y + SPIRAL_K * r1 * sin1 };
|
|
441
|
+
const p2 = { x: p3.x + SPIRAL_K * r2 * cos0, y: p3.y + SPIRAL_K * r2 * sin0 };
|
|
442
|
+
const samples = sampleCubic(p0, p1, p2, p3, SPIRAL_SAMPLES_PER_QUARTER);
|
|
443
|
+
// Skip the first sample (the previous quarter's endpoint / the
|
|
444
|
+
// initial start point) to avoid a duplicate vertex.
|
|
445
|
+
for (let i = 1; i < samples.length; i++)
|
|
446
|
+
points.push(samples[i]);
|
|
447
|
+
r = r2;
|
|
448
|
+
}
|
|
449
|
+
return [
|
|
450
|
+
{
|
|
451
|
+
kind: "polyline",
|
|
452
|
+
points,
|
|
453
|
+
closed: false,
|
|
454
|
+
stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },
|
|
455
|
+
},
|
|
456
|
+
];
|
|
457
|
+
}
|
|
458
|
+
//# sourceMappingURL=fibonacci.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fibonacci.js","sourceRoot":"","sources":["../../../src/geometry/kinds/fibonacci.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//\n// Fibonacci geometry moved from the canvas2d adapter's per-kind\n// renderers\n// examples/canvas2d-adapter/src/render/draw/{fibRetracement,\n// fibTrendExtension,fibChannel,fibTimeZone,fibWedge,fibSpeedFan,\n// fibSpeedArcs,fibSpiral,fibCircles,fibTrendTime}.ts.\n// The originating math is invinite's fib-* tools (commit\n// 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite); re-licensed\n// MIT for chartlang.\n\nimport type {\n FibChannelState,\n FibCirclesState,\n FibRetracementState,\n FibSpeedArcsState,\n FibSpeedFanState,\n FibSpiralState,\n FibTimeZoneState,\n FibTrendExtensionState,\n FibTrendTimeState,\n FibWedgeState,\n} from \"@invinite-org/chartlang-core\";\n\nimport { sampleCubic } from \"../_lib/bezier.js\";\nimport { SOLID_DASH } from \"../_lib/dash.js\";\nimport { FIB_LEVELS, formatLevel } from \"../_lib/fibLevels.js\";\nimport { extendLineSegment } from \"../_lib/lineExtend.js\";\nimport { priceToY, timeToX, worldPointToPixel } from \"../project.js\";\nimport type { DrawPrimitive, Point2, Viewport } from \"../types.js\";\n\nconst DEFAULT_COLOR = \"#facc15\";\nconst DEFAULT_LINE_WIDTH = 1;\nconst LABEL_FONT = \"12px sans-serif\";\nconst LABEL_OFFSET_PX = 4;\nconst LABEL_TOP_PX = 12;\nconst LABEL_OFFSET_FRACTION = 0.25;\nconst TAU = Math.PI * 2;\n\n/**\n * Build a level-line label `text` primitive. Shared by every fib\n * decomposer so the font / colour / alignment convention lives once.\n * Price- and radius-axis fibs use `baseline: \"middle\"`; time-axis fibs\n * pass `baseline: \"top\"`.\n */\nfunction fibLabel(\n text: string,\n x: number,\n y: number,\n color: string,\n baseline: \"middle\" | \"top\",\n): DrawPrimitive {\n return { kind: \"text\", x, y, text, color, font: LABEL_FONT, align: \"left\", baseline };\n}\n\n/**\n * Decompose a `fib-retracement` drawing — one horizontal level line per\n * Fibonacci ratio between `anchors[0].price` and `anchors[1].price`,\n * each honouring `style.extendLeft` / `style.extendRight` via\n * {@link extendLineSegment}. `style.levels` overrides {@link FIB_LEVELS};\n * `style.showLabels === true` appends a right-edge `formatLevel` label\n * per rail.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: FibRetracementState;\n * declare const v: Viewport;\n * const prims = decomposeFibRetracement(s, v);\n * void prims;\n */\nexport function decomposeFibRetracement(\n state: FibRetracementState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const a = worldPointToPixel(state.anchors[0], view);\n const b = worldPointToPixel(state.anchors[1], view);\n const color = state.style.color ?? DEFAULT_COLOR;\n const levels = state.style.levels ?? FIB_LEVELS;\n const fromPrice = state.anchors[0].price;\n const toPrice = state.anchors[1].price;\n const out: DrawPrimitive[] = [];\n for (const level of levels) {\n const levelPrice = fromPrice + level * (toPrice - fromPrice);\n const levelY = priceToY(levelPrice, view);\n const { from, to } = extendLineSegment(\n { x: a.x, y: levelY },\n { x: b.x, y: levelY },\n { extendLeft: state.style.extendLeft, extendRight: state.style.extendRight },\n view,\n );\n out.push({\n kind: \"polyline\",\n points: [\n { x: from.x, y: levelY },\n { x: to.x, y: levelY },\n ],\n closed: false,\n stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },\n });\n if (state.style.showLabels === true) {\n out.push(fibLabel(formatLevel(level), to.x + LABEL_OFFSET_PX, levelY, color, \"middle\"));\n }\n }\n return out;\n}\n\n/**\n * Decompose a `fib-trend-extension` drawing — projects fib-ratio\n * extensions from `anchors[2].price` using the A→B leg's price delta\n * (`anchors[1].price − anchors[0].price`). Each projected price is one\n * horizontal line from `timeToX(anchors[2].time)` rightward to the\n * viewport edge. `style.levels` overrides {@link FIB_LEVELS};\n * `showLabels` appends a label past the right edge.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: FibTrendExtensionState;\n * declare const v: Viewport;\n * const prims = decomposeFibTrendExtension(s, v);\n * void prims;\n */\nexport function decomposeFibTrendExtension(\n state: FibTrendExtensionState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const [A, B, C] = state.anchors;\n const color = state.style.color ?? DEFAULT_COLOR;\n const levels = state.style.levels ?? FIB_LEVELS;\n const priceDelta = B.price - A.price;\n const startX = timeToX(C.time, view);\n const endX = view.pxWidth;\n const out: DrawPrimitive[] = [];\n for (const level of levels) {\n const levelPrice = C.price + level * priceDelta;\n const levelY = priceToY(levelPrice, view);\n out.push({\n kind: \"polyline\",\n points: [\n { x: startX, y: levelY },\n { x: endX, y: levelY },\n ],\n closed: false,\n stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },\n });\n if (state.style.showLabels === true) {\n out.push(fibLabel(formatLevel(level), endX + LABEL_OFFSET_PX, levelY, color, \"middle\"));\n }\n }\n return out;\n}\n\n/**\n * Decompose a `fib-channel` drawing — one parallel rail per Fibonacci\n * ratio: each rail translates the primary `(anchors[0], anchors[1])`\n * line by `level · (anchors[2].y − anchors[0].y)` in pixel space.\n * `style.levels` overrides {@link FIB_LEVELS}; `showLabels` appends a\n * label at the rail's right endpoint.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: FibChannelState;\n * declare const v: Viewport;\n * const prims = decomposeFibChannel(s, v);\n * void prims;\n */\nexport function decomposeFibChannel(\n state: FibChannelState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const a = worldPointToPixel(state.anchors[0], view);\n const b = worldPointToPixel(state.anchors[1], view);\n const c = worldPointToPixel(state.anchors[2], view);\n const color = state.style.color ?? DEFAULT_COLOR;\n const levels = state.style.levels ?? FIB_LEVELS;\n const offsetUnit = c.y - a.y;\n const out: DrawPrimitive[] = [];\n for (const level of levels) {\n const offsetY = level * offsetUnit;\n const fromY = a.y + offsetY;\n const toY = b.y + offsetY;\n out.push({\n kind: \"polyline\",\n points: [\n { x: a.x, y: fromY },\n { x: b.x, y: toY },\n ],\n closed: false,\n stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },\n });\n if (state.style.showLabels === true) {\n out.push(fibLabel(formatLevel(level), b.x + LABEL_OFFSET_PX, toY, color, \"middle\"));\n }\n }\n return out;\n}\n\n/**\n * Decompose a `fib-time-zone` drawing — vertical lines at fib-ratio\n * spaced times `anchors[0].time + level · (anchors[1].time −\n * anchors[0].time)`, each spanning the full viewport height.\n * `style.levels` overrides {@link FIB_LEVELS}; `showLabels` appends a\n * top-anchored label.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: FibTimeZoneState;\n * declare const v: Viewport;\n * const prims = decomposeFibTimeZone(s, v);\n * void prims;\n */\nexport function decomposeFibTimeZone(\n state: FibTimeZoneState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const [A, B] = state.anchors;\n const color = state.style.color ?? DEFAULT_COLOR;\n const levels = state.style.levels ?? FIB_LEVELS;\n const timeDelta = B.time - A.time;\n const out: DrawPrimitive[] = [];\n for (const level of levels) {\n const tx = timeToX(A.time + level * timeDelta, view);\n out.push({\n kind: \"polyline\",\n points: [\n { x: tx, y: 0 },\n { x: tx, y: view.pxHeight },\n ],\n closed: false,\n stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },\n });\n if (state.style.showLabels === true) {\n out.push(\n fibLabel(formatLevel(level), tx + LABEL_OFFSET_PX, LABEL_TOP_PX, color, \"top\"),\n );\n }\n }\n return out;\n}\n\n/**\n * Decompose a `fib-trend-time` drawing — vertical lines at fib-spaced\n * times anchored at `anchors[2]`: `t = C.time + level · (B.time −\n * A.time)`. Mirrors `fib-time-zone` but uses the A→B leg as the\n * time-delta unit projected from C. `showLabels` appends a top label.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: FibTrendTimeState;\n * declare const v: Viewport;\n * const prims = decomposeFibTrendTime(s, v);\n * void prims;\n */\nexport function decomposeFibTrendTime(\n state: FibTrendTimeState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const [A, B, C] = state.anchors;\n const color = state.style.color ?? DEFAULT_COLOR;\n const levels = state.style.levels ?? FIB_LEVELS;\n const timeDelta = B.time - A.time;\n const out: DrawPrimitive[] = [];\n for (const level of levels) {\n const tx = timeToX(C.time + level * timeDelta, view);\n out.push({\n kind: \"polyline\",\n points: [\n { x: tx, y: 0 },\n { x: tx, y: view.pxHeight },\n ],\n closed: false,\n stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },\n });\n if (state.style.showLabels === true) {\n out.push(\n fibLabel(formatLevel(level), tx + LABEL_OFFSET_PX, LABEL_TOP_PX, color, \"top\"),\n );\n }\n }\n return out;\n}\n\n/**\n * Decompose a `fib-wedge` drawing — a fan of rays from `anchors[0]` (the\n * pivot) at fib-ratio-interpolated angles between the pivot→`anchors[1]`\n * and pivot→`anchors[2]` direction vectors. Ray length is\n * `max(pxWidth, pxHeight) · 2` so strokes always exit the viewport; a\n * degenerate (zero-magnitude) direction skips that level. `showLabels`\n * appends a label a quarter of the way along each ray.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: FibWedgeState;\n * declare const v: Viewport;\n * const prims = decomposeFibWedge(s, v);\n * void prims;\n */\nexport function decomposeFibWedge(\n state: FibWedgeState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const pivot = worldPointToPixel(state.anchors[0], view);\n const r1 = worldPointToPixel(state.anchors[1], view);\n const r2 = worldPointToPixel(state.anchors[2], view);\n const color = state.style.color ?? DEFAULT_COLOR;\n const levels = state.style.levels ?? FIB_LEVELS;\n const d1x = r1.x - pivot.x;\n const d1y = r1.y - pivot.y;\n const d2x = r2.x - pivot.x;\n const d2y = r2.y - pivot.y;\n const rayLength = Math.max(view.pxWidth, view.pxHeight) * 2;\n const out: DrawPrimitive[] = [];\n for (const level of levels) {\n const dx = d1x + level * (d2x - d1x);\n const dy = d1y + level * (d2y - d1y);\n const mag = Math.hypot(dx, dy);\n if (mag === 0) continue;\n const ux = dx / mag;\n const uy = dy / mag;\n out.push({\n kind: \"polyline\",\n points: [pivot, { x: pivot.x + ux * rayLength, y: pivot.y + uy * rayLength }],\n closed: false,\n stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },\n });\n if (state.style.showLabels === true) {\n out.push(\n fibLabel(\n formatLevel(level),\n pivot.x + ux * rayLength * LABEL_OFFSET_FRACTION,\n pivot.y + uy * rayLength * LABEL_OFFSET_FRACTION,\n color,\n \"middle\",\n ),\n );\n }\n }\n return out;\n}\n\n/**\n * Decompose a `fib-speed-fan` drawing — a fan of rays from `anchors[0]`.\n * Each ray scales the A→B y-delta by a fib ratio while keeping the\n * x-delta constant. Ray length is `max(pxWidth, pxHeight) · 2`; a\n * degenerate direction skips that level. `showLabels` appends a label a\n * quarter of the way along each ray.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: FibSpeedFanState;\n * declare const v: Viewport;\n * const prims = decomposeFibSpeedFan(s, v);\n * void prims;\n */\nexport function decomposeFibSpeedFan(\n state: FibSpeedFanState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const from = worldPointToPixel(state.anchors[0], view);\n const to = worldPointToPixel(state.anchors[1], view);\n const color = state.style.color ?? DEFAULT_COLOR;\n const levels = state.style.levels ?? FIB_LEVELS;\n const dx = to.x - from.x;\n const dy = to.y - from.y;\n const rayLength = Math.max(view.pxWidth, view.pxHeight) * 2;\n const out: DrawPrimitive[] = [];\n for (const level of levels) {\n const rdy = level * dy;\n const mag = Math.hypot(dx, rdy);\n if (mag === 0) continue;\n const ux = dx / mag;\n const uy = rdy / mag;\n out.push({\n kind: \"polyline\",\n points: [from, { x: from.x + ux * rayLength, y: from.y + uy * rayLength }],\n closed: false,\n stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },\n });\n if (state.style.showLabels === true) {\n out.push(\n fibLabel(\n formatLevel(level),\n from.x + ux * rayLength * LABEL_OFFSET_FRACTION,\n from.y + uy * rayLength * LABEL_OFFSET_FRACTION,\n color,\n \"middle\",\n ),\n );\n }\n }\n return out;\n}\n\n/**\n * Decompose a `fib-speed-arcs` drawing — concentric full circles centred\n * at `anchors[0]` with radii `level · R₀`, `R₀ = |anchors[1] −\n * anchors[0]|` in pixel space. Always-full-circle (half-disk variant\n * deferred). `showLabels` appends a label to the right of each arc.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: FibSpeedArcsState;\n * declare const v: Viewport;\n * const prims = decomposeFibSpeedArcs(s, v);\n * void prims;\n */\nexport function decomposeFibSpeedArcs(\n state: FibSpeedArcsState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const centre = worldPointToPixel(state.anchors[0], view);\n const edge = worldPointToPixel(state.anchors[1], view);\n const color = state.style.color ?? DEFAULT_COLOR;\n const levels = state.style.levels ?? FIB_LEVELS;\n const r0 = Math.hypot(edge.x - centre.x, edge.y - centre.y);\n return concentricArcs(centre, r0, levels, color, state.style.showLabels === true);\n}\n\n/**\n * Decompose a `fib-circles` drawing — concentric full circles centred at\n * `anchors[0]` with radii `level · R₀`, `R₀ = |anchors[1] − anchors[0]|`\n * (the radius-point distance) in pixel space. Uses fib ratios (not the\n * integer Fibonacci sequence). `showLabels` appends a label to the right\n * of each circle.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: FibCirclesState;\n * declare const v: Viewport;\n * const prims = decomposeFibCircles(s, v);\n * void prims;\n */\nexport function decomposeFibCircles(\n state: FibCirclesState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const centre = worldPointToPixel(state.anchors[0], view);\n const radiusPoint = worldPointToPixel(state.anchors[1], view);\n const color = state.style.color ?? DEFAULT_COLOR;\n const levels = state.style.levels ?? FIB_LEVELS;\n const r0 = Math.hypot(radiusPoint.x - centre.x, radiusPoint.y - centre.y);\n return concentricArcs(centre, r0, levels, color, state.style.showLabels === true);\n}\n\n/**\n * Shared concentric-arc builder for `fib-speed-arcs` / `fib-circles`:\n * one full `arc` primitive per level at radius `level · r0`, plus an\n * optional right-edge label. Matches the canvas2d source, which emits a\n * (possibly zero-radius) arc per level without an early return.\n */\nfunction concentricArcs(\n centre: Point2,\n r0: number,\n levels: ReadonlyArray<number>,\n color: string,\n showLabels: boolean,\n): ReadonlyArray<DrawPrimitive> {\n const out: DrawPrimitive[] = [];\n for (const level of levels) {\n const radius = level * r0;\n out.push({\n kind: \"arc\",\n cx: centre.x,\n cy: centre.y,\n r: radius,\n start: 0,\n end: TAU,\n closed: false,\n stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },\n });\n if (showLabels) {\n out.push(\n fibLabel(\n formatLevel(level),\n centre.x + radius + LABEL_OFFSET_PX,\n centre.y,\n color,\n \"middle\",\n ),\n );\n }\n }\n return out;\n}\n\n// Number of quarter-turns sampled = 8 → 2 full rotations.\nconst SPIRAL_QUARTERS = 8;\n// Samples per quarter for the cubic Bezier approximation.\nconst SPIRAL_SAMPLES_PER_QUARTER = 16;\n// φ ≈ 1.618. Each quarter scales the spiral radius by 1/φ inward.\nconst PHI = (1 + Math.sqrt(5)) / 2;\n// Classical Bezier-arc factor for a 90° quadrant: k = 4(√2 − 1)/3.\nconst SPIRAL_K = (4 * (Math.sqrt(2) - 1)) / 3;\n\n/**\n * Decompose a `fib-spiral` drawing — a chained cubic-Bezier\n * approximation of a golden spiral as one open polyline. Each\n * quarter-turn is one cubic Bezier with the classical `k ≈ 0.5523` arc\n * factor; the radius shrinks by `1/φ` per quarter. Centre =\n * `anchors[0]`; initial radius `|anchors[1] − anchors[0]|` in pixel\n * space. A zero initial radius returns `[]` (matching the source's\n * `if (r === 0) return`).\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: FibSpiralState;\n * declare const v: Viewport;\n * const prims = decomposeFibSpiral(s, v);\n * void prims;\n */\nexport function decomposeFibSpiral(\n state: FibSpiralState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const centre = worldPointToPixel(state.anchors[0], view);\n const edge = worldPointToPixel(state.anchors[1], view);\n const color = state.style.color ?? DEFAULT_COLOR;\n let r = Math.hypot(edge.x - centre.x, edge.y - centre.y);\n if (r === 0) return [];\n const points: Point2[] = [{ x: centre.x + r, y: centre.y }];\n for (let q = 0; q < SPIRAL_QUARTERS; q++) {\n const baseAngle = q * (Math.PI / 2);\n const r1 = r;\n const r2 = r / PHI;\n const cos0 = Math.cos(baseAngle);\n const sin0 = Math.sin(baseAngle);\n const cos1 = Math.cos(baseAngle + Math.PI / 2);\n const sin1 = Math.sin(baseAngle + Math.PI / 2);\n const p0: Point2 = { x: centre.x + r1 * cos0, y: centre.y + r1 * sin0 };\n const p3: Point2 = { x: centre.x + r2 * cos1, y: centre.y + r2 * sin1 };\n const p1: Point2 = { x: p0.x + SPIRAL_K * r1 * cos1, y: p0.y + SPIRAL_K * r1 * sin1 };\n const p2: Point2 = { x: p3.x + SPIRAL_K * r2 * cos0, y: p3.y + SPIRAL_K * r2 * sin0 };\n const samples = sampleCubic(p0, p1, p2, p3, SPIRAL_SAMPLES_PER_QUARTER);\n // Skip the first sample (the previous quarter's endpoint / the\n // initial start point) to avoid a duplicate vertex.\n for (let i = 1; i < samples.length; i++) points.push(samples[i]);\n r = r2;\n }\n return [\n {\n kind: \"polyline\",\n points,\n closed: false,\n stroke: { color, width: DEFAULT_LINE_WIDTH, dash: SOLID_DASH },\n },\n ];\n}\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { BrushState, HighlighterState, PenState } from "@invinite-org/chartlang-core";
|
|
2
|
+
import type { DrawPrimitive, Viewport } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Decompose a `pen` drawing — a freehand stroke as one open polyline
|
|
5
|
+
* through the projected anchors, stroke-only with a `LineDrawStyle`.
|
|
6
|
+
*
|
|
7
|
+
* @since 1.3
|
|
8
|
+
* @stable
|
|
9
|
+
* @example
|
|
10
|
+
* declare const s: PenState;
|
|
11
|
+
* declare const v: Viewport;
|
|
12
|
+
* const prims = decomposePen(s, v);
|
|
13
|
+
* // prims[0].kind === "polyline"; prims[0].closed === false
|
|
14
|
+
* void prims;
|
|
15
|
+
*/
|
|
16
|
+
export declare function decomposePen(state: PenState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
17
|
+
/**
|
|
18
|
+
* Decompose a `highlighter` drawing — a thick translucent freehand
|
|
19
|
+
* stroke as one open polyline. The translucency rides on the IR
|
|
20
|
+
* `StrokeStyle.alpha` (set to `style.alpha`); the painter brackets the
|
|
21
|
+
* `stroke()` in `globalAlpha`, scoping it to this drawing only — exactly
|
|
22
|
+
* the canvas2d source's `globalAlpha` bracket. Width is the fixed
|
|
23
|
+
* {@link HIGHLIGHTER_LINE_WIDTH}; both `color` and `alpha` are required
|
|
24
|
+
* by `HighlighterStyle`.
|
|
25
|
+
*
|
|
26
|
+
* @since 1.3
|
|
27
|
+
* @stable
|
|
28
|
+
* @example
|
|
29
|
+
* declare const s: HighlighterState;
|
|
30
|
+
* declare const v: Viewport;
|
|
31
|
+
* const prims = decomposeHighlighter(s, v);
|
|
32
|
+
* // prims[0].kind === "polyline"; prims[0].stroke?.alpha is set
|
|
33
|
+
* void prims;
|
|
34
|
+
*/
|
|
35
|
+
export declare function decomposeHighlighter(state: HighlighterState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
36
|
+
/**
|
|
37
|
+
* Decompose a `brush` drawing — a freehand region as one closed polyline
|
|
38
|
+
* carrying both a `fill` (`style.fill` at full opacity) and a `stroke`
|
|
39
|
+
* (`style.stroke`, width 1). The painter fills before stroking, so the
|
|
40
|
+
* outline draws on top of the filled region. Both colours are required
|
|
41
|
+
* by `BrushStyle`.
|
|
42
|
+
*
|
|
43
|
+
* @since 1.3
|
|
44
|
+
* @stable
|
|
45
|
+
* @example
|
|
46
|
+
* declare const s: BrushState;
|
|
47
|
+
* declare const v: Viewport;
|
|
48
|
+
* const prims = decomposeBrush(s, v);
|
|
49
|
+
* // prims[0].kind === "polyline"; prims[0].closed === true
|
|
50
|
+
* void prims;
|
|
51
|
+
*/
|
|
52
|
+
export declare function decomposeBrush(state: BrushState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
53
|
+
//# sourceMappingURL=freehand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"freehand.d.ts","sourceRoot":"","sources":["../../../src/geometry/kinds/freehand.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAI3F,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAkB3D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,GAAG,aAAa,CAAC,aAAa,CAAC,CAa1F;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAChC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAc9B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,aAAa,CAAC,aAAa,CAAC,CAc9F"}
|