@invinite-org/chartlang-adapter-kit 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/README.md +7 -0
- package/dist/canvas/index.d.ts +5 -0
- package/dist/canvas/index.d.ts.map +1 -0
- package/dist/canvas/index.js +5 -0
- package/dist/canvas/index.js.map +1 -0
- package/dist/canvas/mockContext.d.ts +168 -0
- package/dist/canvas/mockContext.d.ts.map +1 -0
- package/dist/canvas/mockContext.js +198 -0
- package/dist/canvas/mockContext.js.map +1 -0
- package/dist/canvas/paintPrimitive.d.ts +35 -0
- package/dist/canvas/paintPrimitive.d.ts.map +1 -0
- package/dist/canvas/paintPrimitive.js +171 -0
- package/dist/canvas/paintPrimitive.js.map +1 -0
- package/dist/canvas/renderCtx.d.ts +40 -0
- package/dist/canvas/renderCtx.d.ts.map +1 -0
- package/dist/canvas/renderCtx.js +4 -0
- package/dist/canvas/renderCtx.js.map +1 -0
- package/dist/geometry/_lib/arrowhead.d.ts +18 -0
- package/dist/geometry/_lib/arrowhead.d.ts.map +1 -0
- package/dist/geometry/_lib/arrowhead.js +38 -0
- package/dist/geometry/_lib/arrowhead.js.map +1 -0
- package/dist/geometry/_lib/bezier.d.ts +57 -0
- package/dist/geometry/_lib/bezier.d.ts.map +1 -0
- package/dist/geometry/_lib/bezier.js +84 -0
- package/dist/geometry/_lib/bezier.js.map +1 -0
- package/dist/geometry/_lib/chevron.d.ts +29 -0
- package/dist/geometry/_lib/chevron.d.ts.map +1 -0
- package/dist/geometry/_lib/chevron.js +37 -0
- package/dist/geometry/_lib/chevron.js.map +1 -0
- package/dist/geometry/_lib/dash.d.ts +30 -0
- package/dist/geometry/_lib/dash.d.ts.map +1 -0
- package/dist/geometry/_lib/dash.js +40 -0
- package/dist/geometry/_lib/dash.js.map +1 -0
- package/dist/geometry/_lib/fibLevels.d.ts +36 -0
- package/dist/geometry/_lib/fibLevels.d.ts.map +1 -0
- package/dist/geometry/_lib/fibLevels.js +44 -0
- package/dist/geometry/_lib/fibLevels.js.map +1 -0
- package/dist/geometry/_lib/gannLevels.d.ts +54 -0
- package/dist/geometry/_lib/gannLevels.d.ts.map +1 -0
- package/dist/geometry/_lib/gannLevels.js +88 -0
- package/dist/geometry/_lib/gannLevels.js.map +1 -0
- package/dist/geometry/_lib/lineExtend.d.ts +31 -0
- package/dist/geometry/_lib/lineExtend.d.ts.map +1 -0
- package/dist/geometry/_lib/lineExtend.js +48 -0
- package/dist/geometry/_lib/lineExtend.js.map +1 -0
- package/dist/geometry/_lib/namedPolyline.d.ts +25 -0
- package/dist/geometry/_lib/namedPolyline.d.ts.map +1 -0
- package/dist/geometry/_lib/namedPolyline.js +64 -0
- package/dist/geometry/_lib/namedPolyline.js.map +1 -0
- package/dist/geometry/_lib/pitchforkGeom.d.ts +46 -0
- package/dist/geometry/_lib/pitchforkGeom.d.ts.map +1 -0
- package/dist/geometry/_lib/pitchforkGeom.js +70 -0
- package/dist/geometry/_lib/pitchforkGeom.js.map +1 -0
- package/dist/geometry/_lib/shapeStyle.d.ts +21 -0
- package/dist/geometry/_lib/shapeStyle.d.ts.map +1 -0
- package/dist/geometry/_lib/shapeStyle.js +41 -0
- package/dist/geometry/_lib/shapeStyle.js.map +1 -0
- package/dist/geometry/_lib/strokeStyle.d.ts +34 -0
- package/dist/geometry/_lib/strokeStyle.d.ts.map +1 -0
- package/dist/geometry/_lib/strokeStyle.js +26 -0
- package/dist/geometry/_lib/strokeStyle.js.map +1 -0
- package/dist/geometry/_lib/textStyle.d.ts +70 -0
- package/dist/geometry/_lib/textStyle.d.ts.map +1 -0
- package/dist/geometry/_lib/textStyle.js +78 -0
- package/dist/geometry/_lib/textStyle.js.map +1 -0
- package/dist/geometry/decompose.d.ts +28 -0
- package/dist/geometry/decompose.d.ts.map +1 -0
- package/dist/geometry/decompose.js +176 -0
- package/dist/geometry/decompose.js.map +1 -0
- package/dist/geometry/index.d.ts +4 -0
- package/dist/geometry/index.d.ts.map +1 -0
- package/dist/geometry/index.js +5 -0
- package/dist/geometry/index.js.map +1 -0
- package/dist/geometry/kinds/annotations.d.ts +77 -0
- package/dist/geometry/kinds/annotations.d.ts.map +1 -0
- package/dist/geometry/kinds/annotations.js +219 -0
- package/dist/geometry/kinds/annotations.js.map +1 -0
- package/dist/geometry/kinds/boxes.d.ts +116 -0
- package/dist/geometry/kinds/boxes.d.ts.map +1 -0
- package/dist/geometry/kinds/boxes.js +285 -0
- package/dist/geometry/kinds/boxes.js.map +1 -0
- package/dist/geometry/kinds/channels.d.ts +72 -0
- package/dist/geometry/kinds/channels.d.ts.map +1 -0
- package/dist/geometry/kinds/channels.js +148 -0
- package/dist/geometry/kinds/channels.js.map +1 -0
- package/dist/geometry/kinds/containers.d.ts +54 -0
- package/dist/geometry/kinds/containers.d.ts.map +1 -0
- package/dist/geometry/kinds/containers.js +268 -0
- package/dist/geometry/kinds/containers.js.map +1 -0
- package/dist/geometry/kinds/curves.d.ts +53 -0
- package/dist/geometry/kinds/curves.d.ts.map +1 -0
- package/dist/geometry/kinds/curves.js +110 -0
- package/dist/geometry/kinds/curves.js.map +1 -0
- package/dist/geometry/kinds/cycles.d.ts +52 -0
- package/dist/geometry/kinds/cycles.d.ts.map +1 -0
- package/dist/geometry/kinds/cycles.js +158 -0
- package/dist/geometry/kinds/cycles.js.map +1 -0
- package/dist/geometry/kinds/elliott.d.ts +73 -0
- package/dist/geometry/kinds/elliott.d.ts.map +1 -0
- package/dist/geometry/kinds/elliott.js +116 -0
- package/dist/geometry/kinds/elliott.js.map +1 -0
- package/dist/geometry/kinds/fibonacci.d.ts +166 -0
- package/dist/geometry/kinds/fibonacci.d.ts.map +1 -0
- package/dist/geometry/kinds/fibonacci.js +458 -0
- package/dist/geometry/kinds/fibonacci.js.map +1 -0
- package/dist/geometry/kinds/freehand.d.ts +53 -0
- package/dist/geometry/kinds/freehand.d.ts.map +1 -0
- package/dist/geometry/kinds/freehand.js +115 -0
- package/dist/geometry/kinds/freehand.js.map +1 -0
- package/dist/geometry/kinds/gann.d.ts +63 -0
- package/dist/geometry/kinds/gann.d.ts.map +1 -0
- package/dist/geometry/kinds/gann.js +153 -0
- package/dist/geometry/kinds/gann.js.map +1 -0
- package/dist/geometry/kinds/lines.d.ts +90 -0
- package/dist/geometry/kinds/lines.d.ts.map +1 -0
- package/dist/geometry/kinds/lines.js +201 -0
- package/dist/geometry/kinds/lines.js.map +1 -0
- package/dist/geometry/kinds/marker.d.ts +21 -0
- package/dist/geometry/kinds/marker.d.ts.map +1 -0
- package/dist/geometry/kinds/marker.js +47 -0
- package/dist/geometry/kinds/marker.js.map +1 -0
- package/dist/geometry/kinds/patterns.d.ts +85 -0
- package/dist/geometry/kinds/patterns.d.ts.map +1 -0
- package/dist/geometry/kinds/patterns.js +133 -0
- package/dist/geometry/kinds/patterns.js.map +1 -0
- package/dist/geometry/kinds/pitchforks.d.ts +36 -0
- package/dist/geometry/kinds/pitchforks.d.ts.map +1 -0
- package/dist/geometry/kinds/pitchforks.js +109 -0
- package/dist/geometry/kinds/pitchforks.js.map +1 -0
- package/dist/geometry/project.d.ts +50 -0
- package/dist/geometry/project.d.ts.map +1 -0
- package/dist/geometry/project.js +62 -0
- package/dist/geometry/project.js.map +1 -0
- package/dist/geometry/types.d.ts +146 -0
- package/dist/geometry/types.d.ts.map +1 -0
- package/dist/geometry/types.js +4 -0
- package/dist/geometry/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +8 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lines.js","sourceRoot":"","sources":["../../../src/geometry/kinds/lines.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// Stroke + extension geometry moved from the canvas2d adapter's\n// per-kind line renderers\n// examples/canvas2d-adapter/src/render/draw/{line,horizontalLine,\n// horizontalRay,verticalLine,crossLine,trendAngle}.ts.\n// The originating math is invinite's line / ray / extended-line /\n// horizontal-line / horizontal-ray / vertical-line / cross-line /\n// trend-angle tools (commit 078f41fe2569d659d5aba726da8bcb5d3e2ced02,\n// © Invinite); re-licensed MIT for chartlang.\n\nimport type {\n CrossLineState,\n HorizontalLineState,\n HorizontalRayState,\n LineState,\n TrendAngleState,\n VerticalLineState,\n} from \"@invinite-org/chartlang-core\";\n\nimport { dashPattern } from \"../_lib/dash.js\";\nimport { extendLineSegment } from \"../_lib/lineExtend.js\";\nimport { strokeOf } from \"../_lib/strokeStyle.js\";\nimport { priceToY, timeToX, worldPointToPixel } from \"../project.js\";\nimport type { DrawPrimitive, Viewport } from \"../types.js\";\n\nconst DEFAULT_COLOR = \"#000000\";\nconst ANGLE_ARC_RADIUS_PX = 24;\nconst ANGLE_TEXT_FONT = \"12px sans-serif\";\nconst ANGLE_TEXT_OFFSET_PX = 6;\n\n/**\n * Decompose a `line` drawing — a single segment, optionally extended to\n * the viewport edges via {@link extendLineSegment} (the `ray` /\n * `extended-line` collapse).\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: LineState;\n * declare const v: Viewport;\n * const prims = decomposeLine(s, v);\n * // prims[0].kind === \"polyline\"\n * void prims;\n */\nexport function decomposeLine(state: LineState, view: Viewport): ReadonlyArray<DrawPrimitive> {\n const a = worldPointToPixel(state.anchors[0], view);\n const b = worldPointToPixel(state.anchors[1], view);\n const { from, to } = extendLineSegment(\n a,\n b,\n { extendLeft: state.style.extendLeft, extendRight: state.style.extendRight },\n view,\n );\n return [{ kind: \"polyline\", points: [from, to], closed: false, stroke: strokeOf(state.style) }];\n}\n\n/**\n * Decompose a `horizontal-line` drawing — a segment from `x = 0` to\n * `x = view.pxWidth` at `priceToY(state.price)`.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: HorizontalLineState;\n * declare const v: Viewport;\n * const prims = decomposeHorizontalLine(s, v);\n * void prims;\n */\nexport function decomposeHorizontalLine(\n state: HorizontalLineState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const y = priceToY(state.price, view);\n return [\n {\n kind: \"polyline\",\n points: [\n { x: 0, y },\n { x: view.pxWidth, y },\n ],\n closed: false,\n stroke: strokeOf(state.style),\n },\n ];\n}\n\n/**\n * Decompose a `horizontal-ray` drawing — a segment from the projected\n * anchor across the right edge at constant y.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: HorizontalRayState;\n * declare const v: Viewport;\n * const prims = decomposeHorizontalRay(s, v);\n * void prims;\n */\nexport function decomposeHorizontalRay(\n state: HorizontalRayState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const origin = worldPointToPixel(state.anchor, view);\n return [\n {\n kind: \"polyline\",\n points: [origin, { x: view.pxWidth, y: origin.y }],\n closed: false,\n stroke: strokeOf(state.style),\n },\n ];\n}\n\n/**\n * Decompose a `vertical-line` drawing — a segment from `y = 0` to\n * `y = view.pxHeight` at `timeToX(state.time)`.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: VerticalLineState;\n * declare const v: Viewport;\n * const prims = decomposeVerticalLine(s, v);\n * void prims;\n */\nexport function decomposeVerticalLine(\n state: VerticalLineState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const x = timeToX(state.time, view);\n return [\n {\n kind: \"polyline\",\n points: [\n { x, y: 0 },\n { x, y: view.pxHeight },\n ],\n closed: false,\n stroke: strokeOf(state.style),\n },\n ];\n}\n\n/**\n * Decompose a `cross-line` drawing — a horizontal segment and a\n * vertical segment crossing at the projected anchor. Two polylines\n * sharing one stroke style.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: CrossLineState;\n * declare const v: Viewport;\n * const prims = decomposeCrossLine(s, v);\n * // prims.length === 2\n * void prims;\n */\nexport function decomposeCrossLine(\n state: CrossLineState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const p = worldPointToPixel(state.anchor, view);\n const stroke = strokeOf(state.style);\n return [\n {\n kind: \"polyline\",\n points: [\n { x: 0, y: p.y },\n { x: view.pxWidth, y: p.y },\n ],\n closed: false,\n stroke,\n },\n {\n kind: \"polyline\",\n points: [\n { x: p.x, y: 0 },\n { x: p.x, y: view.pxHeight },\n ],\n closed: false,\n stroke,\n },\n ];\n}\n\n/**\n * Decompose a `trend-angle` drawing — the main segment, a small arc\n * spanning the screen-space angle off the first anchor, and the angle\n * label in degrees. The arc is solid regardless of `lineStyle` so it\n * reads cleanly; the angle is measured in screen-pixel space with the\n * canvas y-axis flipped (`-dy`) so a positive angle reads \"upward to\n * the right\" (matching the source renderer's convention).\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: TrendAngleState;\n * declare const v: Viewport;\n * const prims = decomposeTrendAngle(s, v);\n * // prims[0].kind === \"polyline\"; prims[1].kind === \"arc\"; prims[2].kind === \"text\"\n * void prims;\n */\nexport function decomposeTrendAngle(\n state: TrendAngleState,\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 stroke = strokeOf(state.style);\n const angleRad = Math.atan2(-(b.y - a.y), b.x - a.x);\n const degrees = (angleRad * 180) / Math.PI;\n return [\n { kind: \"polyline\", points: [a, b], closed: false, stroke },\n {\n kind: \"arc\",\n cx: a.x,\n cy: a.y,\n r: ANGLE_ARC_RADIUS_PX,\n start: -angleRad,\n end: 0,\n closed: false,\n stroke: { color, width: stroke.width, dash: dashPattern(\"solid\") },\n },\n {\n kind: \"text\",\n x: a.x + ANGLE_ARC_RADIUS_PX + ANGLE_TEXT_OFFSET_PX,\n y: a.y,\n text: `${degrees.toFixed(1)}°`,\n color,\n font: ANGLE_TEXT_FONT,\n align: \"left\",\n baseline: \"middle\",\n },\n ];\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MarkerState } from "@invinite-org/chartlang-core";
|
|
2
|
+
import type { DrawPrimitive, Viewport } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Decompose a `marker` drawing. The reference adapter paints a marker's
|
|
5
|
+
* `text` label only (no glyph) — so this emits a single `text`
|
|
6
|
+
* primitive when `state.text` is a non-empty string, and `[]`
|
|
7
|
+
* otherwise. (The IR `marker` primitive exists for adapters / future
|
|
8
|
+
* kinds; no basic kind emits it.) `style.bgColor` is preserved on the
|
|
9
|
+
* IR `text` primitive but the canvas sink does not paint a background
|
|
10
|
+
* rect, matching the source renderer.
|
|
11
|
+
*
|
|
12
|
+
* @since 1.3
|
|
13
|
+
* @stable
|
|
14
|
+
* @example
|
|
15
|
+
* declare const s: MarkerState;
|
|
16
|
+
* declare const v: Viewport;
|
|
17
|
+
* const prims = decomposeMarker(s, v);
|
|
18
|
+
* void prims;
|
|
19
|
+
*/
|
|
20
|
+
export declare function decomposeMarker(state: MarkerState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
21
|
+
//# sourceMappingURL=marker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marker.d.ts","sourceRoot":"","sources":["../../../src/geometry/kinds/marker.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAIhE,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,GAAG,aAAa,CAAC,aAAa,CAAC,CAiBhG"}
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
// Marker geometry moved from the canvas2d adapter's per-kind renderer
|
|
5
|
+
// examples/canvas2d-adapter/src/render/draw/marker.ts.
|
|
6
|
+
// The originating math is invinite's marker tool (commit
|
|
7
|
+
// 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite); re-licensed
|
|
8
|
+
// MIT for chartlang.
|
|
9
|
+
import { resolveTextOpts } from "../_lib/textStyle.js";
|
|
10
|
+
import { worldPointToPixel } from "../project.js";
|
|
11
|
+
/**
|
|
12
|
+
* Decompose a `marker` drawing. The reference adapter paints a marker's
|
|
13
|
+
* `text` label only (no glyph) — so this emits a single `text`
|
|
14
|
+
* primitive when `state.text` is a non-empty string, and `[]`
|
|
15
|
+
* otherwise. (The IR `marker` primitive exists for adapters / future
|
|
16
|
+
* kinds; no basic kind emits it.) `style.bgColor` is preserved on the
|
|
17
|
+
* IR `text` primitive but the canvas sink does not paint a background
|
|
18
|
+
* rect, matching the source renderer.
|
|
19
|
+
*
|
|
20
|
+
* @since 1.3
|
|
21
|
+
* @stable
|
|
22
|
+
* @example
|
|
23
|
+
* declare const s: MarkerState;
|
|
24
|
+
* declare const v: Viewport;
|
|
25
|
+
* const prims = decomposeMarker(s, v);
|
|
26
|
+
* void prims;
|
|
27
|
+
*/
|
|
28
|
+
export function decomposeMarker(state, view) {
|
|
29
|
+
if (state.text === undefined || state.text.length === 0)
|
|
30
|
+
return [];
|
|
31
|
+
const anchor = worldPointToPixel(state.anchor, view);
|
|
32
|
+
const resolved = resolveTextOpts(state.style);
|
|
33
|
+
return [
|
|
34
|
+
{
|
|
35
|
+
kind: "text",
|
|
36
|
+
x: anchor.x,
|
|
37
|
+
y: anchor.y,
|
|
38
|
+
text: state.text,
|
|
39
|
+
color: resolved.color,
|
|
40
|
+
font: resolved.font,
|
|
41
|
+
align: resolved.align,
|
|
42
|
+
baseline: resolved.baseline,
|
|
43
|
+
...(state.style.bgColor === undefined ? {} : { bgColor: state.style.bgColor }),
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=marker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marker.js","sourceRoot":"","sources":["../../../src/geometry/kinds/marker.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAC/D,EAAE;AACF,sEAAsE;AACtE,yDAAyD;AACzD,yDAAyD;AACzD,qEAAqE;AACrE,qBAAqB;AAIrB,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe,CAAC,KAAkB,EAAE,IAAc;IAC9D,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACnE,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9C,OAAO;QACH;YACI,IAAI,EAAE,MAAM;YACZ,CAAC,EAAE,MAAM,CAAC,CAAC;YACX,CAAC,EAAE,MAAM,CAAC,CAAC;YACX,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;SACjF;KACJ,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// Marker geometry moved from the canvas2d adapter's per-kind renderer\n// examples/canvas2d-adapter/src/render/draw/marker.ts.\n// The originating math is invinite's marker tool (commit\n// 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite); re-licensed\n// MIT for chartlang.\n\nimport type { MarkerState } from \"@invinite-org/chartlang-core\";\n\nimport { resolveTextOpts } from \"../_lib/textStyle.js\";\nimport { worldPointToPixel } from \"../project.js\";\nimport type { DrawPrimitive, Viewport } from \"../types.js\";\n\n/**\n * Decompose a `marker` drawing. The reference adapter paints a marker's\n * `text` label only (no glyph) — so this emits a single `text`\n * primitive when `state.text` is a non-empty string, and `[]`\n * otherwise. (The IR `marker` primitive exists for adapters / future\n * kinds; no basic kind emits it.) `style.bgColor` is preserved on the\n * IR `text` primitive but the canvas sink does not paint a background\n * rect, matching the source renderer.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: MarkerState;\n * declare const v: Viewport;\n * const prims = decomposeMarker(s, v);\n * void prims;\n */\nexport function decomposeMarker(state: MarkerState, view: Viewport): ReadonlyArray<DrawPrimitive> {\n if (state.text === undefined || state.text.length === 0) return [];\n const anchor = worldPointToPixel(state.anchor, view);\n const resolved = resolveTextOpts(state.style);\n return [\n {\n kind: \"text\",\n x: anchor.x,\n y: anchor.y,\n text: state.text,\n color: resolved.color,\n font: resolved.font,\n align: resolved.align,\n baseline: resolved.baseline,\n ...(state.style.bgColor === undefined ? {} : { bgColor: state.style.bgColor }),\n },\n ];\n}\n"]}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { AbcdPatternState, CypherPatternState, HeadAndShouldersState, ThreeDrivesPatternState, TrianglePatternState, XabcdPatternState } from "@invinite-org/chartlang-core";
|
|
2
|
+
import type { DrawPrimitive, Viewport } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Decompose an `xabcd-pattern` drawing — a 4-leg labelled open polyline
|
|
5
|
+
* through the 5 anchors (X-A-B-C-D), one `text` per pivot.
|
|
6
|
+
*
|
|
7
|
+
* @since 1.3
|
|
8
|
+
* @stable
|
|
9
|
+
* @example
|
|
10
|
+
* declare const s: XabcdPatternState;
|
|
11
|
+
* declare const v: Viewport;
|
|
12
|
+
* const prims = decomposeXabcdPattern(s, v);
|
|
13
|
+
* void prims;
|
|
14
|
+
*/
|
|
15
|
+
export declare function decomposeXabcdPattern(state: XabcdPatternState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
16
|
+
/**
|
|
17
|
+
* Decompose a `cypher-pattern` drawing — structurally identical to
|
|
18
|
+
* `xabcd-pattern`: a 4-leg labelled open polyline through the 5 anchors
|
|
19
|
+
* (X-A-B-C-D). The cypher fib-ratio invariants are a script-author
|
|
20
|
+
* concern, not a geometry one.
|
|
21
|
+
*
|
|
22
|
+
* @since 1.3
|
|
23
|
+
* @stable
|
|
24
|
+
* @example
|
|
25
|
+
* declare const s: CypherPatternState;
|
|
26
|
+
* declare const v: Viewport;
|
|
27
|
+
* const prims = decomposeCypherPattern(s, v);
|
|
28
|
+
* void prims;
|
|
29
|
+
*/
|
|
30
|
+
export declare function decomposeCypherPattern(state: CypherPatternState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
31
|
+
/**
|
|
32
|
+
* Decompose a `head-and-shoulders` drawing — a 4-leg labelled open
|
|
33
|
+
* polyline through the 5 anchors (LS-LL-H-RL-RS) plus a neckline
|
|
34
|
+
* polyline between the two trough anchors (LL → RL).
|
|
35
|
+
*
|
|
36
|
+
* @since 1.3
|
|
37
|
+
* @stable
|
|
38
|
+
* @example
|
|
39
|
+
* declare const s: HeadAndShouldersState;
|
|
40
|
+
* declare const v: Viewport;
|
|
41
|
+
* const prims = decomposeHeadAndShoulders(s, v);
|
|
42
|
+
* void prims;
|
|
43
|
+
*/
|
|
44
|
+
export declare function decomposeHeadAndShoulders(state: HeadAndShouldersState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
45
|
+
/**
|
|
46
|
+
* Decompose an `abcd-pattern` drawing — a 3-leg labelled open polyline
|
|
47
|
+
* through the 4 anchors (A-B-C-D).
|
|
48
|
+
*
|
|
49
|
+
* @since 1.3
|
|
50
|
+
* @stable
|
|
51
|
+
* @example
|
|
52
|
+
* declare const s: AbcdPatternState;
|
|
53
|
+
* declare const v: Viewport;
|
|
54
|
+
* const prims = decomposeAbcdPattern(s, v);
|
|
55
|
+
* void prims;
|
|
56
|
+
*/
|
|
57
|
+
export declare function decomposeAbcdPattern(state: AbcdPatternState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
58
|
+
/**
|
|
59
|
+
* Decompose a `triangle-pattern` drawing — a 2-leg labelled open
|
|
60
|
+
* polyline through the 3 anchors (A-B-C). Distinct from `draw.triangle`:
|
|
61
|
+
* this is a `LineDrawStyle` harmonic outline, not a filled shape.
|
|
62
|
+
*
|
|
63
|
+
* @since 1.3
|
|
64
|
+
* @stable
|
|
65
|
+
* @example
|
|
66
|
+
* declare const s: TrianglePatternState;
|
|
67
|
+
* declare const v: Viewport;
|
|
68
|
+
* const prims = decomposeTrianglePattern(s, v);
|
|
69
|
+
* void prims;
|
|
70
|
+
*/
|
|
71
|
+
export declare function decomposeTrianglePattern(state: TrianglePatternState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
72
|
+
/**
|
|
73
|
+
* Decompose a `three-drives-pattern` drawing — a 6-leg labelled open
|
|
74
|
+
* polyline through the 7 anchors (start → d1 → r1 → d2 → r2 → d3 → end).
|
|
75
|
+
*
|
|
76
|
+
* @since 1.3
|
|
77
|
+
* @stable
|
|
78
|
+
* @example
|
|
79
|
+
* declare const s: ThreeDrivesPatternState;
|
|
80
|
+
* declare const v: Viewport;
|
|
81
|
+
* const prims = decomposeThreeDrivesPattern(s, v);
|
|
82
|
+
* void prims;
|
|
83
|
+
*/
|
|
84
|
+
export declare function decomposeThreeDrivesPattern(state: ThreeDrivesPatternState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
85
|
+
//# sourceMappingURL=patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../../src/geometry/kinds/patterns.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACR,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,iBAAiB,EACpB,MAAM,8BAA8B,CAAC;AAKtC,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAW3D;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACjC,KAAK,EAAE,iBAAiB,EACxB,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAG9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAClC,KAAK,EAAE,kBAAkB,EACzB,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAG9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CACrC,KAAK,EAAE,qBAAqB,EAC5B,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAc9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAChC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAG9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CACpC,KAAK,EAAE,oBAAoB,EAC3B,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAG9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACvC,KAAK,EAAE,uBAAuB,EAC9B,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAG9B"}
|
|
@@ -0,0 +1,133 @@
|
|
|
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
|
+
// Harmonic-pattern geometry moved from the canvas2d adapter's per-kind
|
|
5
|
+
// renderers
|
|
6
|
+
// examples/canvas2d-adapter/src/render/draw/{xabcdPattern,
|
|
7
|
+
// cypherPattern,headAndShoulders,abcdPattern,trianglePattern,
|
|
8
|
+
// threeDrivesPattern}.ts.
|
|
9
|
+
// The originating math is invinite's pattern tools (commit
|
|
10
|
+
// 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite); re-licensed
|
|
11
|
+
// MIT for chartlang.
|
|
12
|
+
import { dashPattern } from "../_lib/dash.js";
|
|
13
|
+
import { namedPolylinePrimitives } from "../_lib/namedPolyline.js";
|
|
14
|
+
import { worldPointToPixel } from "../project.js";
|
|
15
|
+
const XABCD_LABELS = ["X", "A", "B", "C", "D"];
|
|
16
|
+
const HEAD_AND_SHOULDERS_LABELS = ["LS", "LL", "H", "RL", "RS"];
|
|
17
|
+
const ABCD_LABELS = ["A", "B", "C", "D"];
|
|
18
|
+
const TRIANGLE_LABELS = ["A", "B", "C"];
|
|
19
|
+
const THREE_DRIVES_LABELS = ["S", "D1", "R1", "D2", "R2", "D3", "E"];
|
|
20
|
+
const HEAD_AND_SHOULDERS_DEFAULT_COLOR = "#f59e0b";
|
|
21
|
+
const NECKLINE_WIDTH = 1;
|
|
22
|
+
/**
|
|
23
|
+
* Decompose an `xabcd-pattern` drawing — a 4-leg labelled open polyline
|
|
24
|
+
* through the 5 anchors (X-A-B-C-D), one `text` per pivot.
|
|
25
|
+
*
|
|
26
|
+
* @since 1.3
|
|
27
|
+
* @stable
|
|
28
|
+
* @example
|
|
29
|
+
* declare const s: XabcdPatternState;
|
|
30
|
+
* declare const v: Viewport;
|
|
31
|
+
* const prims = decomposeXabcdPattern(s, v);
|
|
32
|
+
* void prims;
|
|
33
|
+
*/
|
|
34
|
+
export function decomposeXabcdPattern(state, view) {
|
|
35
|
+
const points = state.anchors.map((p) => worldPointToPixel(p, view));
|
|
36
|
+
return namedPolylinePrimitives(points, XABCD_LABELS, state.style);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Decompose a `cypher-pattern` drawing — structurally identical to
|
|
40
|
+
* `xabcd-pattern`: a 4-leg labelled open polyline through the 5 anchors
|
|
41
|
+
* (X-A-B-C-D). The cypher fib-ratio invariants are a script-author
|
|
42
|
+
* concern, not a geometry one.
|
|
43
|
+
*
|
|
44
|
+
* @since 1.3
|
|
45
|
+
* @stable
|
|
46
|
+
* @example
|
|
47
|
+
* declare const s: CypherPatternState;
|
|
48
|
+
* declare const v: Viewport;
|
|
49
|
+
* const prims = decomposeCypherPattern(s, v);
|
|
50
|
+
* void prims;
|
|
51
|
+
*/
|
|
52
|
+
export function decomposeCypherPattern(state, view) {
|
|
53
|
+
const points = state.anchors.map((p) => worldPointToPixel(p, view));
|
|
54
|
+
return namedPolylinePrimitives(points, XABCD_LABELS, state.style);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Decompose a `head-and-shoulders` drawing — a 4-leg labelled open
|
|
58
|
+
* polyline through the 5 anchors (LS-LL-H-RL-RS) plus a neckline
|
|
59
|
+
* polyline between the two trough anchors (LL → RL).
|
|
60
|
+
*
|
|
61
|
+
* @since 1.3
|
|
62
|
+
* @stable
|
|
63
|
+
* @example
|
|
64
|
+
* declare const s: HeadAndShouldersState;
|
|
65
|
+
* declare const v: Viewport;
|
|
66
|
+
* const prims = decomposeHeadAndShoulders(s, v);
|
|
67
|
+
* void prims;
|
|
68
|
+
*/
|
|
69
|
+
export function decomposeHeadAndShoulders(state, view) {
|
|
70
|
+
const points = state.anchors.map((p) => worldPointToPixel(p, view));
|
|
71
|
+
const out = [...namedPolylinePrimitives(points, HEAD_AND_SHOULDERS_LABELS, state.style)];
|
|
72
|
+
out.push({
|
|
73
|
+
kind: "polyline",
|
|
74
|
+
points: [points[1], points[3]],
|
|
75
|
+
closed: false,
|
|
76
|
+
stroke: {
|
|
77
|
+
color: state.style.color ?? HEAD_AND_SHOULDERS_DEFAULT_COLOR,
|
|
78
|
+
width: NECKLINE_WIDTH,
|
|
79
|
+
dash: dashPattern("solid"),
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Decompose an `abcd-pattern` drawing — a 3-leg labelled open polyline
|
|
86
|
+
* through the 4 anchors (A-B-C-D).
|
|
87
|
+
*
|
|
88
|
+
* @since 1.3
|
|
89
|
+
* @stable
|
|
90
|
+
* @example
|
|
91
|
+
* declare const s: AbcdPatternState;
|
|
92
|
+
* declare const v: Viewport;
|
|
93
|
+
* const prims = decomposeAbcdPattern(s, v);
|
|
94
|
+
* void prims;
|
|
95
|
+
*/
|
|
96
|
+
export function decomposeAbcdPattern(state, view) {
|
|
97
|
+
const points = state.anchors.map((p) => worldPointToPixel(p, view));
|
|
98
|
+
return namedPolylinePrimitives(points, ABCD_LABELS, state.style);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Decompose a `triangle-pattern` drawing — a 2-leg labelled open
|
|
102
|
+
* polyline through the 3 anchors (A-B-C). Distinct from `draw.triangle`:
|
|
103
|
+
* this is a `LineDrawStyle` harmonic outline, not a filled shape.
|
|
104
|
+
*
|
|
105
|
+
* @since 1.3
|
|
106
|
+
* @stable
|
|
107
|
+
* @example
|
|
108
|
+
* declare const s: TrianglePatternState;
|
|
109
|
+
* declare const v: Viewport;
|
|
110
|
+
* const prims = decomposeTrianglePattern(s, v);
|
|
111
|
+
* void prims;
|
|
112
|
+
*/
|
|
113
|
+
export function decomposeTrianglePattern(state, view) {
|
|
114
|
+
const points = state.anchors.map((p) => worldPointToPixel(p, view));
|
|
115
|
+
return namedPolylinePrimitives(points, TRIANGLE_LABELS, state.style);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Decompose a `three-drives-pattern` drawing — a 6-leg labelled open
|
|
119
|
+
* polyline through the 7 anchors (start → d1 → r1 → d2 → r2 → d3 → end).
|
|
120
|
+
*
|
|
121
|
+
* @since 1.3
|
|
122
|
+
* @stable
|
|
123
|
+
* @example
|
|
124
|
+
* declare const s: ThreeDrivesPatternState;
|
|
125
|
+
* declare const v: Viewport;
|
|
126
|
+
* const prims = decomposeThreeDrivesPattern(s, v);
|
|
127
|
+
* void prims;
|
|
128
|
+
*/
|
|
129
|
+
export function decomposeThreeDrivesPattern(state, view) {
|
|
130
|
+
const points = state.anchors.map((p) => worldPointToPixel(p, view));
|
|
131
|
+
return namedPolylinePrimitives(points, THREE_DRIVES_LABELS, state.style);
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../../src/geometry/kinds/patterns.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// Harmonic-pattern geometry moved from the canvas2d adapter's per-kind\n// renderers\n// examples/canvas2d-adapter/src/render/draw/{xabcdPattern,\n// cypherPattern,headAndShoulders,abcdPattern,trianglePattern,\n// threeDrivesPattern}.ts.\n// The originating math is invinite's pattern tools (commit\n// 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite); re-licensed\n// MIT for chartlang.\n\nimport type {\n AbcdPatternState,\n CypherPatternState,\n HeadAndShouldersState,\n ThreeDrivesPatternState,\n TrianglePatternState,\n XabcdPatternState,\n} from \"@invinite-org/chartlang-core\";\n\nimport { dashPattern } from \"../_lib/dash.js\";\nimport { namedPolylinePrimitives } from \"../_lib/namedPolyline.js\";\nimport { worldPointToPixel } from \"../project.js\";\nimport type { DrawPrimitive, Viewport } from \"../types.js\";\n\nconst XABCD_LABELS: ReadonlyArray<string> = [\"X\", \"A\", \"B\", \"C\", \"D\"];\nconst HEAD_AND_SHOULDERS_LABELS: ReadonlyArray<string> = [\"LS\", \"LL\", \"H\", \"RL\", \"RS\"];\nconst ABCD_LABELS: ReadonlyArray<string> = [\"A\", \"B\", \"C\", \"D\"];\nconst TRIANGLE_LABELS: ReadonlyArray<string> = [\"A\", \"B\", \"C\"];\nconst THREE_DRIVES_LABELS: ReadonlyArray<string> = [\"S\", \"D1\", \"R1\", \"D2\", \"R2\", \"D3\", \"E\"];\n\nconst HEAD_AND_SHOULDERS_DEFAULT_COLOR = \"#f59e0b\";\nconst NECKLINE_WIDTH = 1;\n\n/**\n * Decompose an `xabcd-pattern` drawing — a 4-leg labelled open polyline\n * through the 5 anchors (X-A-B-C-D), one `text` per pivot.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: XabcdPatternState;\n * declare const v: Viewport;\n * const prims = decomposeXabcdPattern(s, v);\n * void prims;\n */\nexport function decomposeXabcdPattern(\n state: XabcdPatternState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const points = state.anchors.map((p) => worldPointToPixel(p, view));\n return namedPolylinePrimitives(points, XABCD_LABELS, state.style);\n}\n\n/**\n * Decompose a `cypher-pattern` drawing — structurally identical to\n * `xabcd-pattern`: a 4-leg labelled open polyline through the 5 anchors\n * (X-A-B-C-D). The cypher fib-ratio invariants are a script-author\n * concern, not a geometry one.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: CypherPatternState;\n * declare const v: Viewport;\n * const prims = decomposeCypherPattern(s, v);\n * void prims;\n */\nexport function decomposeCypherPattern(\n state: CypherPatternState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const points = state.anchors.map((p) => worldPointToPixel(p, view));\n return namedPolylinePrimitives(points, XABCD_LABELS, state.style);\n}\n\n/**\n * Decompose a `head-and-shoulders` drawing — a 4-leg labelled open\n * polyline through the 5 anchors (LS-LL-H-RL-RS) plus a neckline\n * polyline between the two trough anchors (LL → RL).\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: HeadAndShouldersState;\n * declare const v: Viewport;\n * const prims = decomposeHeadAndShoulders(s, v);\n * void prims;\n */\nexport function decomposeHeadAndShoulders(\n state: HeadAndShouldersState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const points = state.anchors.map((p) => worldPointToPixel(p, view));\n const out = [...namedPolylinePrimitives(points, HEAD_AND_SHOULDERS_LABELS, state.style)];\n out.push({\n kind: \"polyline\",\n points: [points[1], points[3]],\n closed: false,\n stroke: {\n color: state.style.color ?? HEAD_AND_SHOULDERS_DEFAULT_COLOR,\n width: NECKLINE_WIDTH,\n dash: dashPattern(\"solid\"),\n },\n });\n return out;\n}\n\n/**\n * Decompose an `abcd-pattern` drawing — a 3-leg labelled open polyline\n * through the 4 anchors (A-B-C-D).\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: AbcdPatternState;\n * declare const v: Viewport;\n * const prims = decomposeAbcdPattern(s, v);\n * void prims;\n */\nexport function decomposeAbcdPattern(\n state: AbcdPatternState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const points = state.anchors.map((p) => worldPointToPixel(p, view));\n return namedPolylinePrimitives(points, ABCD_LABELS, state.style);\n}\n\n/**\n * Decompose a `triangle-pattern` drawing — a 2-leg labelled open\n * polyline through the 3 anchors (A-B-C). Distinct from `draw.triangle`:\n * this is a `LineDrawStyle` harmonic outline, not a filled shape.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: TrianglePatternState;\n * declare const v: Viewport;\n * const prims = decomposeTrianglePattern(s, v);\n * void prims;\n */\nexport function decomposeTrianglePattern(\n state: TrianglePatternState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const points = state.anchors.map((p) => worldPointToPixel(p, view));\n return namedPolylinePrimitives(points, TRIANGLE_LABELS, state.style);\n}\n\n/**\n * Decompose a `three-drives-pattern` drawing — a 6-leg labelled open\n * polyline through the 7 anchors (start → d1 → r1 → d2 → r2 → d3 → end).\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: ThreeDrivesPatternState;\n * declare const v: Viewport;\n * const prims = decomposeThreeDrivesPattern(s, v);\n * void prims;\n */\nexport function decomposeThreeDrivesPattern(\n state: ThreeDrivesPatternState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const points = state.anchors.map((p) => worldPointToPixel(p, view));\n return namedPolylinePrimitives(points, THREE_DRIVES_LABELS, state.style);\n}\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { PitchfanState, PitchforkState } from "@invinite-org/chartlang-core";
|
|
2
|
+
import type { DrawPrimitive, Viewport } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Decompose a `pitchfork` drawing — three line segments: a median rail
|
|
5
|
+
* from the per-variant `medianOrigin` through `medianTarget`, extended
|
|
6
|
+
* one fork vector (`target − origin`) past the target, plus two
|
|
7
|
+
* parallel handle rails through `anchors[1]` / `anchors[2]` offset by
|
|
8
|
+
* that same extension vector. The `variant` discriminator selects one
|
|
9
|
+
* of the four median-origin formulas via {@link medianOriginFor}.
|
|
10
|
+
*
|
|
11
|
+
* @since 1.3
|
|
12
|
+
* @stable
|
|
13
|
+
* @example
|
|
14
|
+
* declare const s: PitchforkState;
|
|
15
|
+
* declare const v: Viewport;
|
|
16
|
+
* const prims = decomposePitchfork(s, v);
|
|
17
|
+
* // prims.length === 3
|
|
18
|
+
* void prims;
|
|
19
|
+
*/
|
|
20
|
+
export declare function decomposePitchfork(state: PitchforkState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
21
|
+
/**
|
|
22
|
+
* Decompose a `pitchfan` drawing — three rays from `anchors[0]` passing
|
|
23
|
+
* through `anchors[1]`, `mid(anchors[1], anchors[2])`, and `anchors[2]`.
|
|
24
|
+
* Each ray extends to `max(pxWidth, pxHeight) · 2`; a zero-magnitude ray
|
|
25
|
+
* is skipped (matching the source `continue`).
|
|
26
|
+
*
|
|
27
|
+
* @since 1.3
|
|
28
|
+
* @stable
|
|
29
|
+
* @example
|
|
30
|
+
* declare const s: PitchfanState;
|
|
31
|
+
* declare const v: Viewport;
|
|
32
|
+
* const prims = decomposePitchfan(s, v);
|
|
33
|
+
* void prims;
|
|
34
|
+
*/
|
|
35
|
+
export declare function decomposePitchfan(state: PitchfanState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
36
|
+
//# sourceMappingURL=pitchforks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pitchforks.d.ts","sourceRoot":"","sources":["../../../src/geometry/kinds/pitchforks.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAKlF,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAK3D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAiC9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CA2B9B"}
|
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
// Pitchfork geometry moved from the canvas2d adapter's per-kind
|
|
5
|
+
// renderers
|
|
6
|
+
// examples/canvas2d-adapter/src/render/draw/{pitchfork,pitchfan}.ts.
|
|
7
|
+
// The originating math is invinite's pitchfork / pitchfan tools (commit
|
|
8
|
+
// 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite); re-licensed
|
|
9
|
+
// MIT for chartlang.
|
|
10
|
+
import { SOLID_DASH } from "../_lib/dash.js";
|
|
11
|
+
import { medianOriginFor, medianTargetFor } from "../_lib/pitchforkGeom.js";
|
|
12
|
+
import { worldPointToPixel } from "../project.js";
|
|
13
|
+
const DEFAULT_COLOR = "#ec4899";
|
|
14
|
+
const DEFAULT_LINE_WIDTH = 1;
|
|
15
|
+
/**
|
|
16
|
+
* Decompose a `pitchfork` drawing — three line segments: a median rail
|
|
17
|
+
* from the per-variant `medianOrigin` through `medianTarget`, extended
|
|
18
|
+
* one fork vector (`target − origin`) past the target, plus two
|
|
19
|
+
* parallel handle rails through `anchors[1]` / `anchors[2]` offset by
|
|
20
|
+
* that same extension vector. The `variant` discriminator selects one
|
|
21
|
+
* of the four median-origin formulas via {@link medianOriginFor}.
|
|
22
|
+
*
|
|
23
|
+
* @since 1.3
|
|
24
|
+
* @stable
|
|
25
|
+
* @example
|
|
26
|
+
* declare const s: PitchforkState;
|
|
27
|
+
* declare const v: Viewport;
|
|
28
|
+
* const prims = decomposePitchfork(s, v);
|
|
29
|
+
* // prims.length === 3
|
|
30
|
+
* void prims;
|
|
31
|
+
*/
|
|
32
|
+
export function decomposePitchfork(state, view) {
|
|
33
|
+
const a = worldPointToPixel(state.anchors[0], view);
|
|
34
|
+
const b = worldPointToPixel(state.anchors[1], view);
|
|
35
|
+
const c = worldPointToPixel(state.anchors[2], view);
|
|
36
|
+
const origin = medianOriginFor(state.variant, a, b, c);
|
|
37
|
+
const target = medianTargetFor(state.variant, a, b, c);
|
|
38
|
+
const dx = target.x - origin.x;
|
|
39
|
+
const dy = target.y - origin.y;
|
|
40
|
+
const stroke = {
|
|
41
|
+
color: state.style.color ?? DEFAULT_COLOR,
|
|
42
|
+
width: state.style.lineWidth ?? DEFAULT_LINE_WIDTH,
|
|
43
|
+
dash: SOLID_DASH,
|
|
44
|
+
};
|
|
45
|
+
return [
|
|
46
|
+
{
|
|
47
|
+
kind: "polyline",
|
|
48
|
+
points: [origin, { x: target.x + dx, y: target.y + dy }],
|
|
49
|
+
closed: false,
|
|
50
|
+
stroke,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
kind: "polyline",
|
|
54
|
+
points: [b, { x: b.x + dx, y: b.y + dy }],
|
|
55
|
+
closed: false,
|
|
56
|
+
stroke,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
kind: "polyline",
|
|
60
|
+
points: [c, { x: c.x + dx, y: c.y + dy }],
|
|
61
|
+
closed: false,
|
|
62
|
+
stroke,
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Decompose a `pitchfan` drawing — three rays from `anchors[0]` passing
|
|
68
|
+
* through `anchors[1]`, `mid(anchors[1], anchors[2])`, and `anchors[2]`.
|
|
69
|
+
* Each ray extends to `max(pxWidth, pxHeight) · 2`; a zero-magnitude ray
|
|
70
|
+
* is skipped (matching the source `continue`).
|
|
71
|
+
*
|
|
72
|
+
* @since 1.3
|
|
73
|
+
* @stable
|
|
74
|
+
* @example
|
|
75
|
+
* declare const s: PitchfanState;
|
|
76
|
+
* declare const v: Viewport;
|
|
77
|
+
* const prims = decomposePitchfan(s, v);
|
|
78
|
+
* void prims;
|
|
79
|
+
*/
|
|
80
|
+
export function decomposePitchfan(state, view) {
|
|
81
|
+
const a = worldPointToPixel(state.anchors[0], view);
|
|
82
|
+
const b = worldPointToPixel(state.anchors[1], view);
|
|
83
|
+
const c = worldPointToPixel(state.anchors[2], view);
|
|
84
|
+
const midBC = { x: (b.x + c.x) / 2, y: (b.y + c.y) / 2 };
|
|
85
|
+
const stroke = {
|
|
86
|
+
color: state.style.color ?? DEFAULT_COLOR,
|
|
87
|
+
width: state.style.lineWidth ?? DEFAULT_LINE_WIDTH,
|
|
88
|
+
dash: SOLID_DASH,
|
|
89
|
+
};
|
|
90
|
+
const rayLength = Math.max(view.pxWidth, view.pxHeight) * 2;
|
|
91
|
+
const out = [];
|
|
92
|
+
for (const target of [b, midBC, c]) {
|
|
93
|
+
const dx = target.x - a.x;
|
|
94
|
+
const dy = target.y - a.y;
|
|
95
|
+
const mag = Math.hypot(dx, dy);
|
|
96
|
+
if (mag === 0)
|
|
97
|
+
continue;
|
|
98
|
+
const ux = dx / mag;
|
|
99
|
+
const uy = dy / mag;
|
|
100
|
+
out.push({
|
|
101
|
+
kind: "polyline",
|
|
102
|
+
points: [a, { x: a.x + ux * rayLength, y: a.y + uy * rayLength }],
|
|
103
|
+
closed: false,
|
|
104
|
+
stroke,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=pitchforks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pitchforks.js","sourceRoot":"","sources":["../../../src/geometry/kinds/pitchforks.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// Pitchfork geometry moved from the canvas2d adapter's per-kind\n// renderers\n// examples/canvas2d-adapter/src/render/draw/{pitchfork,pitchfan}.ts.\n// The originating math is invinite's pitchfork / pitchfan tools (commit\n// 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite); re-licensed\n// MIT for chartlang.\n\nimport type { PitchfanState, PitchforkState } from \"@invinite-org/chartlang-core\";\n\nimport { SOLID_DASH } from \"../_lib/dash.js\";\nimport { medianOriginFor, medianTargetFor } from \"../_lib/pitchforkGeom.js\";\nimport { worldPointToPixel } from \"../project.js\";\nimport type { DrawPrimitive, Viewport } from \"../types.js\";\n\nconst DEFAULT_COLOR = \"#ec4899\";\nconst DEFAULT_LINE_WIDTH = 1;\n\n/**\n * Decompose a `pitchfork` drawing — three line segments: a median rail\n * from the per-variant `medianOrigin` through `medianTarget`, extended\n * one fork vector (`target − origin`) past the target, plus two\n * parallel handle rails through `anchors[1]` / `anchors[2]` offset by\n * that same extension vector. The `variant` discriminator selects one\n * of the four median-origin formulas via {@link medianOriginFor}.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: PitchforkState;\n * declare const v: Viewport;\n * const prims = decomposePitchfork(s, v);\n * // prims.length === 3\n * void prims;\n */\nexport function decomposePitchfork(\n state: PitchforkState,\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 origin = medianOriginFor(state.variant, a, b, c);\n const target = medianTargetFor(state.variant, a, b, c);\n const dx = target.x - origin.x;\n const dy = target.y - origin.y;\n const stroke = {\n color: state.style.color ?? DEFAULT_COLOR,\n width: state.style.lineWidth ?? DEFAULT_LINE_WIDTH,\n dash: SOLID_DASH,\n };\n return [\n {\n kind: \"polyline\",\n points: [origin, { x: target.x + dx, y: target.y + dy }],\n closed: false,\n stroke,\n },\n {\n kind: \"polyline\",\n points: [b, { x: b.x + dx, y: b.y + dy }],\n closed: false,\n stroke,\n },\n {\n kind: \"polyline\",\n points: [c, { x: c.x + dx, y: c.y + dy }],\n closed: false,\n stroke,\n },\n ];\n}\n\n/**\n * Decompose a `pitchfan` drawing — three rays from `anchors[0]` passing\n * through `anchors[1]`, `mid(anchors[1], anchors[2])`, and `anchors[2]`.\n * Each ray extends to `max(pxWidth, pxHeight) · 2`; a zero-magnitude ray\n * is skipped (matching the source `continue`).\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: PitchfanState;\n * declare const v: Viewport;\n * const prims = decomposePitchfan(s, v);\n * void prims;\n */\nexport function decomposePitchfan(\n state: PitchfanState,\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 midBC = { x: (b.x + c.x) / 2, y: (b.y + c.y) / 2 };\n const stroke = {\n color: state.style.color ?? DEFAULT_COLOR,\n width: state.style.lineWidth ?? DEFAULT_LINE_WIDTH,\n dash: SOLID_DASH,\n };\n const rayLength = Math.max(view.pxWidth, view.pxHeight) * 2;\n const out: DrawPrimitive[] = [];\n for (const target of [b, midBC, c]) {\n const dx = target.x - a.x;\n const dy = target.y - a.y;\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: [a, { x: a.x + ux * rayLength, y: a.y + uy * rayLength }],\n closed: false,\n stroke,\n });\n }\n return out;\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { WorldPoint } from "@invinite-org/chartlang-core";
|
|
2
|
+
import type { Point2, Viewport } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Map a world time (UTC ms) to an x pixel coordinate. When `xMin ===
|
|
5
|
+
* xMax` (single-bar viewport) the result pins to the canvas centre —
|
|
6
|
+
* no NaN propagation. Ported verbatim from the canvas2d adapter's
|
|
7
|
+
* `render/coords.ts` so every adapter projects time identically.
|
|
8
|
+
*
|
|
9
|
+
* @since 1.3
|
|
10
|
+
* @stable
|
|
11
|
+
* @example
|
|
12
|
+
* const x = timeToX(5, { xMin: 0, xMax: 10, yMin: 0, yMax: 1, pxWidth: 100, pxHeight: 1 });
|
|
13
|
+
* // x === 50
|
|
14
|
+
* void x;
|
|
15
|
+
*/
|
|
16
|
+
export declare function timeToX(time: number, view: Viewport): number;
|
|
17
|
+
/**
|
|
18
|
+
* Map a world price to a y pixel coordinate. The y axis is flipped
|
|
19
|
+
* (canvas y grows downward, prices grow upward), so a price at
|
|
20
|
+
* `view.yMax` lands at `y = 0` and `view.yMin` lands at `y = pxHeight`.
|
|
21
|
+
* The viewport is assumed non-degenerate (`yMax > yMin`); callers feed a
|
|
22
|
+
* non-empty bar window. Ported verbatim from the canvas2d adapter's
|
|
23
|
+
* `render/coords.ts`.
|
|
24
|
+
*
|
|
25
|
+
* @since 1.3
|
|
26
|
+
* @stable
|
|
27
|
+
* @example
|
|
28
|
+
* const y = priceToY(105, { xMin: 0, xMax: 1, yMin: 100, yMax: 110, pxWidth: 1, pxHeight: 100 });
|
|
29
|
+
* // y === 50
|
|
30
|
+
* void y;
|
|
31
|
+
*/
|
|
32
|
+
export declare function priceToY(price: number, view: Viewport): number;
|
|
33
|
+
/**
|
|
34
|
+
* Project a world `(time, price)` point to pixel `(x, y)` space by
|
|
35
|
+
* composing {@link timeToX} and {@link priceToY}. Supersedes the
|
|
36
|
+
* canvas2d adapter's `worldPointToCanvas`. Off-screen points are NOT
|
|
37
|
+
* clipped — finite world inputs map to finite (possibly out-of-range)
|
|
38
|
+
* pixels and the renderer clips at the stroke / fill boundary.
|
|
39
|
+
*
|
|
40
|
+
* @since 1.3
|
|
41
|
+
* @stable
|
|
42
|
+
* @example
|
|
43
|
+
* declare const view: Viewport;
|
|
44
|
+
* const anchor: WorldPoint = { time: 1_700_000_000_000, price: 105 };
|
|
45
|
+
* const px = worldPointToPixel(anchor, view);
|
|
46
|
+
* // px.x === timeToX(anchor.time, view); px.y === priceToY(anchor.price, view)
|
|
47
|
+
* void px;
|
|
48
|
+
*/
|
|
49
|
+
export declare function worldPointToPixel(p: WorldPoint, view: Viewport): Point2;
|
|
50
|
+
//# sourceMappingURL=project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/geometry/project.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAK5D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAI9D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAEvE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
* Map a world time (UTC ms) to an x pixel coordinate. When `xMin ===
|
|
5
|
+
* xMax` (single-bar viewport) the result pins to the canvas centre —
|
|
6
|
+
* no NaN propagation. Ported verbatim from the canvas2d adapter's
|
|
7
|
+
* `render/coords.ts` so every adapter projects time identically.
|
|
8
|
+
*
|
|
9
|
+
* @since 1.3
|
|
10
|
+
* @stable
|
|
11
|
+
* @example
|
|
12
|
+
* const x = timeToX(5, { xMin: 0, xMax: 10, yMin: 0, yMax: 1, pxWidth: 100, pxHeight: 1 });
|
|
13
|
+
* // x === 50
|
|
14
|
+
* void x;
|
|
15
|
+
*/
|
|
16
|
+
export function timeToX(time, view) {
|
|
17
|
+
const span = view.xMax - view.xMin;
|
|
18
|
+
if (span === 0)
|
|
19
|
+
return view.pxWidth / 2;
|
|
20
|
+
const normalised = (time - view.xMin) / span;
|
|
21
|
+
return normalised * view.pxWidth;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Map a world price to a y pixel coordinate. The y axis is flipped
|
|
25
|
+
* (canvas y grows downward, prices grow upward), so a price at
|
|
26
|
+
* `view.yMax` lands at `y = 0` and `view.yMin` lands at `y = pxHeight`.
|
|
27
|
+
* The viewport is assumed non-degenerate (`yMax > yMin`); callers feed a
|
|
28
|
+
* non-empty bar window. Ported verbatim from the canvas2d adapter's
|
|
29
|
+
* `render/coords.ts`.
|
|
30
|
+
*
|
|
31
|
+
* @since 1.3
|
|
32
|
+
* @stable
|
|
33
|
+
* @example
|
|
34
|
+
* const y = priceToY(105, { xMin: 0, xMax: 1, yMin: 100, yMax: 110, pxWidth: 1, pxHeight: 100 });
|
|
35
|
+
* // y === 50
|
|
36
|
+
* void y;
|
|
37
|
+
*/
|
|
38
|
+
export function priceToY(price, view) {
|
|
39
|
+
const span = view.yMax - view.yMin;
|
|
40
|
+
const normalised = (price - view.yMin) / span;
|
|
41
|
+
return view.pxHeight - normalised * view.pxHeight;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Project a world `(time, price)` point to pixel `(x, y)` space by
|
|
45
|
+
* composing {@link timeToX} and {@link priceToY}. Supersedes the
|
|
46
|
+
* canvas2d adapter's `worldPointToCanvas`. Off-screen points are NOT
|
|
47
|
+
* clipped — finite world inputs map to finite (possibly out-of-range)
|
|
48
|
+
* pixels and the renderer clips at the stroke / fill boundary.
|
|
49
|
+
*
|
|
50
|
+
* @since 1.3
|
|
51
|
+
* @stable
|
|
52
|
+
* @example
|
|
53
|
+
* declare const view: Viewport;
|
|
54
|
+
* const anchor: WorldPoint = { time: 1_700_000_000_000, price: 105 };
|
|
55
|
+
* const px = worldPointToPixel(anchor, view);
|
|
56
|
+
* // px.x === timeToX(anchor.time, view); px.y === priceToY(anchor.price, view)
|
|
57
|
+
* void px;
|
|
58
|
+
*/
|
|
59
|
+
export function worldPointToPixel(p, view) {
|
|
60
|
+
return { x: timeToX(p.time, view), y: priceToY(p.price, view) };
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/geometry/project.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAM/D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,IAAc;IAChD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACnC,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC7C,OAAO,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,IAAc;IAClD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACnC,MAAM,UAAU,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9C,OAAO,IAAI,CAAC,QAAQ,GAAG,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC;AACtD,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAAa,EAAE,IAAc;IAC3D,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;AACpE,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 { WorldPoint } from \"@invinite-org/chartlang-core\";\n\nimport type { Point2, Viewport } from \"./types.js\";\n\n/**\n * Map a world time (UTC ms) to an x pixel coordinate. When `xMin ===\n * xMax` (single-bar viewport) the result pins to the canvas centre —\n * no NaN propagation. Ported verbatim from the canvas2d adapter's\n * `render/coords.ts` so every adapter projects time identically.\n *\n * @since 1.3\n * @stable\n * @example\n * const x = timeToX(5, { xMin: 0, xMax: 10, yMin: 0, yMax: 1, pxWidth: 100, pxHeight: 1 });\n * // x === 50\n * void x;\n */\nexport function timeToX(time: number, view: Viewport): number {\n const span = view.xMax - view.xMin;\n if (span === 0) return view.pxWidth / 2;\n const normalised = (time - view.xMin) / span;\n return normalised * view.pxWidth;\n}\n\n/**\n * Map a world price to a y pixel coordinate. The y axis is flipped\n * (canvas y grows downward, prices grow upward), so a price at\n * `view.yMax` lands at `y = 0` and `view.yMin` lands at `y = pxHeight`.\n * The viewport is assumed non-degenerate (`yMax > yMin`); callers feed a\n * non-empty bar window. Ported verbatim from the canvas2d adapter's\n * `render/coords.ts`.\n *\n * @since 1.3\n * @stable\n * @example\n * const y = priceToY(105, { xMin: 0, xMax: 1, yMin: 100, yMax: 110, pxWidth: 1, pxHeight: 100 });\n * // y === 50\n * void y;\n */\nexport function priceToY(price: number, view: Viewport): number {\n const span = view.yMax - view.yMin;\n const normalised = (price - view.yMin) / span;\n return view.pxHeight - normalised * view.pxHeight;\n}\n\n/**\n * Project a world `(time, price)` point to pixel `(x, y)` space by\n * composing {@link timeToX} and {@link priceToY}. Supersedes the\n * canvas2d adapter's `worldPointToCanvas`. Off-screen points are NOT\n * clipped — finite world inputs map to finite (possibly out-of-range)\n * pixels and the renderer clips at the stroke / fill boundary.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const view: Viewport;\n * const anchor: WorldPoint = { time: 1_700_000_000_000, price: 105 };\n * const px = worldPointToPixel(anchor, view);\n * // px.x === timeToX(anchor.time, view); px.y === priceToY(anchor.price, view)\n * void px;\n */\nexport function worldPointToPixel(p: WorldPoint, view: Viewport): Point2 {\n return { x: timeToX(p.time, view), y: priceToY(p.price, view) };\n}\n"]}
|