@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,219 @@
|
|
|
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
|
+
// Annotation geometry moved from the canvas2d adapter's per-kind
|
|
5
|
+
// renderers
|
|
6
|
+
// examples/canvas2d-adapter/src/render/draw/{text,arrow,arrowMarker,
|
|
7
|
+
// arrowMarkUp,arrowMarkDown}.ts.
|
|
8
|
+
// The originating math is invinite's text / arrow / arrow-marker /
|
|
9
|
+
// arrow-mark-up / arrow-mark-down tools (commit
|
|
10
|
+
// 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite); re-licensed
|
|
11
|
+
// MIT for chartlang.
|
|
12
|
+
import { arrowheadPolygon } from "../_lib/arrowhead.js";
|
|
13
|
+
import { chevronPolygon } from "../_lib/chevron.js";
|
|
14
|
+
import { dashPattern } from "../_lib/dash.js";
|
|
15
|
+
import { resolveTextOpts } from "../_lib/textStyle.js";
|
|
16
|
+
import { worldPointToPixel } from "../project.js";
|
|
17
|
+
const DEFAULT_LINE_COLOR = "#000000";
|
|
18
|
+
const DEFAULT_LINE_WIDTH = 1;
|
|
19
|
+
const DEFAULT_ARROW_MARKER_COLOR = "#3b82f6"; // invinite toolbar blue
|
|
20
|
+
const DEFAULT_MARK_UP_COLOR = "#22c55e";
|
|
21
|
+
const DEFAULT_MARK_DOWN_COLOR = "#ef4444";
|
|
22
|
+
const SOLID_FILL_ALPHA = 1;
|
|
23
|
+
const ARROW_LABEL_FONT = "12px sans-serif";
|
|
24
|
+
const ARROW_LABEL_VERTICAL_OFFSET = 4;
|
|
25
|
+
const MARKER_DOT_RADIUS = 3;
|
|
26
|
+
const MARKER_STUB_DX = 16;
|
|
27
|
+
const MARKER_STUB_DY = -8;
|
|
28
|
+
const MARKER_TEXT_OFFSET_X = 6;
|
|
29
|
+
const MARKER_TEXT_FONT = "12px sans-serif";
|
|
30
|
+
const TWO_PI = Math.PI * 2;
|
|
31
|
+
/**
|
|
32
|
+
* Decompose a `text` drawing — a single label at the projected anchor,
|
|
33
|
+
* its font / alignment / colour resolved from `TextOpts`. `bgColor` is
|
|
34
|
+
* carried through onto the IR `text` primitive (adapters that can paint
|
|
35
|
+
* a background rect may use it; the canvas sink ignores it).
|
|
36
|
+
*
|
|
37
|
+
* @since 1.3
|
|
38
|
+
* @stable
|
|
39
|
+
* @example
|
|
40
|
+
* declare const s: TextState;
|
|
41
|
+
* declare const v: Viewport;
|
|
42
|
+
* const prims = decomposeText(s, v);
|
|
43
|
+
* // prims[0].kind === "text"
|
|
44
|
+
* void prims;
|
|
45
|
+
*/
|
|
46
|
+
export function decomposeText(state, view) {
|
|
47
|
+
const anchor = worldPointToPixel(state.anchor, view);
|
|
48
|
+
const resolved = resolveTextOpts(state.style);
|
|
49
|
+
return [
|
|
50
|
+
{
|
|
51
|
+
kind: "text",
|
|
52
|
+
x: anchor.x,
|
|
53
|
+
y: anchor.y,
|
|
54
|
+
text: state.body,
|
|
55
|
+
color: resolved.color,
|
|
56
|
+
font: resolved.font,
|
|
57
|
+
align: resolved.align,
|
|
58
|
+
baseline: resolved.baseline,
|
|
59
|
+
...(state.style.bgColor === undefined ? {} : { bgColor: state.style.bgColor }),
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Decompose an `arrow` drawing — a stroked shaft, a filled arrowhead
|
|
65
|
+
* triangle at the head anchor, and an optional label at the shaft
|
|
66
|
+
* midpoint. Stroke and arrowhead fill share `style.color`.
|
|
67
|
+
*
|
|
68
|
+
* @since 1.3
|
|
69
|
+
* @stable
|
|
70
|
+
* @example
|
|
71
|
+
* declare const s: ArrowState;
|
|
72
|
+
* declare const v: Viewport;
|
|
73
|
+
* const prims = decomposeArrow(s, v);
|
|
74
|
+
* // prims[0].kind === "polyline"; prims[1].kind === "polyline"
|
|
75
|
+
* void prims;
|
|
76
|
+
*/
|
|
77
|
+
export function decomposeArrow(state, view) {
|
|
78
|
+
const from = worldPointToPixel(state.anchors[0], view);
|
|
79
|
+
const to = worldPointToPixel(state.anchors[1], view);
|
|
80
|
+
const color = state.style.color ?? DEFAULT_LINE_COLOR;
|
|
81
|
+
const out = [
|
|
82
|
+
{
|
|
83
|
+
kind: "polyline",
|
|
84
|
+
points: [from, to],
|
|
85
|
+
closed: false,
|
|
86
|
+
stroke: {
|
|
87
|
+
color,
|
|
88
|
+
width: state.style.lineWidth ?? DEFAULT_LINE_WIDTH,
|
|
89
|
+
dash: dashPattern(state.style.lineStyle ?? "solid"),
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
kind: "polyline",
|
|
94
|
+
points: arrowheadPolygon(from, to),
|
|
95
|
+
closed: true,
|
|
96
|
+
fill: { color, alpha: SOLID_FILL_ALPHA },
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
if (state.style.label !== undefined) {
|
|
100
|
+
out.push({
|
|
101
|
+
kind: "text",
|
|
102
|
+
x: (from.x + to.x) / 2,
|
|
103
|
+
y: (from.y + to.y) / 2 - ARROW_LABEL_VERTICAL_OFFSET,
|
|
104
|
+
text: state.style.label,
|
|
105
|
+
color,
|
|
106
|
+
font: ARROW_LABEL_FONT,
|
|
107
|
+
align: "center",
|
|
108
|
+
baseline: "bottom",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Decompose an `arrow-marker` drawing — a self-contained compact glyph
|
|
115
|
+
* at the anchor: a filled dot, a short stub up + right, a filled
|
|
116
|
+
* arrowhead at the stub end, and optional text to the right. Default
|
|
117
|
+
* colour is `"#3b82f6"` (invinite toolbar blue).
|
|
118
|
+
*
|
|
119
|
+
* @since 1.3
|
|
120
|
+
* @stable
|
|
121
|
+
* @example
|
|
122
|
+
* declare const s: ArrowMarkerState;
|
|
123
|
+
* declare const v: Viewport;
|
|
124
|
+
* const prims = decomposeArrowMarker(s, v);
|
|
125
|
+
* void prims;
|
|
126
|
+
*/
|
|
127
|
+
export function decomposeArrowMarker(state, view) {
|
|
128
|
+
const anchor = worldPointToPixel(state.anchor, view);
|
|
129
|
+
const color = state.style.color ?? DEFAULT_ARROW_MARKER_COLOR;
|
|
130
|
+
const stubEnd = { x: anchor.x + MARKER_STUB_DX, y: anchor.y + MARKER_STUB_DY };
|
|
131
|
+
const out = [
|
|
132
|
+
{
|
|
133
|
+
kind: "arc",
|
|
134
|
+
cx: anchor.x,
|
|
135
|
+
cy: anchor.y,
|
|
136
|
+
r: MARKER_DOT_RADIUS,
|
|
137
|
+
start: 0,
|
|
138
|
+
end: TWO_PI,
|
|
139
|
+
closed: false,
|
|
140
|
+
fill: { color, alpha: SOLID_FILL_ALPHA },
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
kind: "polyline",
|
|
144
|
+
points: [anchor, stubEnd],
|
|
145
|
+
closed: false,
|
|
146
|
+
stroke: { color, width: DEFAULT_LINE_WIDTH, dash: dashPattern("solid") },
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
kind: "polyline",
|
|
150
|
+
points: arrowheadPolygon(anchor, stubEnd),
|
|
151
|
+
closed: true,
|
|
152
|
+
fill: { color, alpha: SOLID_FILL_ALPHA },
|
|
153
|
+
},
|
|
154
|
+
];
|
|
155
|
+
if (state.style.text !== undefined) {
|
|
156
|
+
out.push({
|
|
157
|
+
kind: "text",
|
|
158
|
+
x: anchor.x + MARKER_TEXT_OFFSET_X,
|
|
159
|
+
y: anchor.y,
|
|
160
|
+
text: state.style.text,
|
|
161
|
+
color,
|
|
162
|
+
font: MARKER_TEXT_FONT,
|
|
163
|
+
align: "left",
|
|
164
|
+
baseline: "middle",
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Decompose an `arrow-mark-up` drawing — a filled up-chevron glyph at
|
|
171
|
+
* the anchor. Default fill colour is `"#22c55e"` (green); an explicit
|
|
172
|
+
* `style.color` overrides.
|
|
173
|
+
*
|
|
174
|
+
* @since 1.3
|
|
175
|
+
* @stable
|
|
176
|
+
* @example
|
|
177
|
+
* declare const s: ArrowMarkUpState;
|
|
178
|
+
* declare const v: Viewport;
|
|
179
|
+
* const prims = decomposeArrowMarkUp(s, v);
|
|
180
|
+
* void prims;
|
|
181
|
+
*/
|
|
182
|
+
export function decomposeArrowMarkUp(state, view) {
|
|
183
|
+
const anchor = worldPointToPixel(state.anchor, view);
|
|
184
|
+
const color = state.style.color ?? DEFAULT_MARK_UP_COLOR;
|
|
185
|
+
return [
|
|
186
|
+
{
|
|
187
|
+
kind: "polyline",
|
|
188
|
+
points: chevronPolygon(anchor, "up"),
|
|
189
|
+
closed: true,
|
|
190
|
+
fill: { color, alpha: SOLID_FILL_ALPHA },
|
|
191
|
+
},
|
|
192
|
+
];
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Decompose an `arrow-mark-down` drawing — a filled down-chevron glyph
|
|
196
|
+
* at the anchor. Default fill colour is `"#ef4444"` (red); an explicit
|
|
197
|
+
* `style.color` overrides.
|
|
198
|
+
*
|
|
199
|
+
* @since 1.3
|
|
200
|
+
* @stable
|
|
201
|
+
* @example
|
|
202
|
+
* declare const s: ArrowMarkDownState;
|
|
203
|
+
* declare const v: Viewport;
|
|
204
|
+
* const prims = decomposeArrowMarkDown(s, v);
|
|
205
|
+
* void prims;
|
|
206
|
+
*/
|
|
207
|
+
export function decomposeArrowMarkDown(state, view) {
|
|
208
|
+
const anchor = worldPointToPixel(state.anchor, view);
|
|
209
|
+
const color = state.style.color ?? DEFAULT_MARK_DOWN_COLOR;
|
|
210
|
+
return [
|
|
211
|
+
{
|
|
212
|
+
kind: "polyline",
|
|
213
|
+
points: chevronPolygon(anchor, "down"),
|
|
214
|
+
closed: true,
|
|
215
|
+
fill: { color, alpha: SOLID_FILL_ALPHA },
|
|
216
|
+
},
|
|
217
|
+
];
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=annotations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annotations.js","sourceRoot":"","sources":["../../../src/geometry/kinds/annotations.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAC/D,EAAE;AACF,iEAAiE;AACjE,YAAY;AACZ,uEAAuE;AACvE,mCAAmC;AACnC,mEAAmE;AACnE,gDAAgD;AAChD,qEAAqE;AACrE,qBAAqB;AAUrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,MAAM,kBAAkB,GAAG,SAAS,CAAC;AACrC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAC7B,MAAM,0BAA0B,GAAG,SAAS,CAAC,CAAC,wBAAwB;AACtE,MAAM,qBAAqB,GAAG,SAAS,CAAC;AACxC,MAAM,uBAAuB,GAAG,SAAS,CAAC;AAC1C,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAC3C,MAAM,2BAA2B,GAAG,CAAC,CAAC;AACtC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAC5B,MAAM,cAAc,GAAG,EAAE,CAAC;AAC1B,MAAM,cAAc,GAAG,CAAC,CAAC,CAAC;AAC1B,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAC/B,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;AAE3B;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,aAAa,CAAC,KAAgB,EAAE,IAAc;IAC1D,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;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,KAAiB,EAAE,IAAc;IAC5D,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACvD,MAAM,EAAE,GAAG,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,kBAAkB,CAAC;IACtD,MAAM,GAAG,GAAoB;QACzB;YACI,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;YAClB,MAAM,EAAE,KAAK;YACb,MAAM,EAAE;gBACJ,KAAK;gBACL,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,SAAS,IAAI,kBAAkB;gBAClD,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,IAAI,OAAO,CAAC;aACtD;SACJ;QACD;YACI,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC;YAClC,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE;SAC3C;KACJ,CAAC;IACF,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAClC,GAAG,CAAC,IAAI,CAAC;YACL,IAAI,EAAE,MAAM;YACZ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;YACtB,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,2BAA2B;YACpD,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK;YACvB,KAAK;YACL,IAAI,EAAE,gBAAgB;YACtB,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,QAAQ;SACrB,CAAC,CAAC;IACP,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAChC,KAAuB,EACvB,IAAc;IAEd,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,0BAA0B,CAAC;IAC9D,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,cAAc,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,cAAc,EAAE,CAAC;IAC/E,MAAM,GAAG,GAAoB;QACzB;YACI,IAAI,EAAE,KAAK;YACX,EAAE,EAAE,MAAM,CAAC,CAAC;YACZ,EAAE,EAAE,MAAM,CAAC,CAAC;YACZ,CAAC,EAAE,iBAAiB;YACpB,KAAK,EAAE,CAAC;YACR,GAAG,EAAE,MAAM;YACX,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE;SAC3C;QACD;YACI,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;YACzB,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE;SAC3E;QACD;YACI,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC;YACzC,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE;SAC3C;KACJ,CAAC;IACF,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC;YACL,IAAI,EAAE,MAAM;YACZ,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,oBAAoB;YAClC,CAAC,EAAE,MAAM,CAAC,CAAC;YACX,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI;YACtB,KAAK;YACL,IAAI,EAAE,gBAAgB;YACtB,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,QAAQ;SACrB,CAAC,CAAC;IACP,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAChC,KAAuB,EACvB,IAAc;IAEd,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,qBAAqB,CAAC;IACzD,OAAO;QACH;YACI,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC;YACpC,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE;SAC3C;KACJ,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,sBAAsB,CAClC,KAAyB,EACzB,IAAc;IAEd,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,uBAAuB,CAAC;IAC3D,OAAO;QACH;YACI,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC;YACtC,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE;SAC3C;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// Annotation geometry moved from the canvas2d adapter's per-kind\n// renderers\n// examples/canvas2d-adapter/src/render/draw/{text,arrow,arrowMarker,\n// arrowMarkUp,arrowMarkDown}.ts.\n// The originating math is invinite's text / arrow / arrow-marker /\n// arrow-mark-up / arrow-mark-down tools (commit\n// 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite); re-licensed\n// MIT for chartlang.\n\nimport type {\n ArrowMarkDownState,\n ArrowMarkUpState,\n ArrowMarkerState,\n ArrowState,\n TextState,\n} from \"@invinite-org/chartlang-core\";\n\nimport { arrowheadPolygon } from \"../_lib/arrowhead.js\";\nimport { chevronPolygon } from \"../_lib/chevron.js\";\nimport { dashPattern } from \"../_lib/dash.js\";\nimport { resolveTextOpts } from \"../_lib/textStyle.js\";\nimport { worldPointToPixel } from \"../project.js\";\nimport type { DrawPrimitive, Viewport } from \"../types.js\";\n\nconst DEFAULT_LINE_COLOR = \"#000000\";\nconst DEFAULT_LINE_WIDTH = 1;\nconst DEFAULT_ARROW_MARKER_COLOR = \"#3b82f6\"; // invinite toolbar blue\nconst DEFAULT_MARK_UP_COLOR = \"#22c55e\";\nconst DEFAULT_MARK_DOWN_COLOR = \"#ef4444\";\nconst SOLID_FILL_ALPHA = 1;\nconst ARROW_LABEL_FONT = \"12px sans-serif\";\nconst ARROW_LABEL_VERTICAL_OFFSET = 4;\nconst MARKER_DOT_RADIUS = 3;\nconst MARKER_STUB_DX = 16;\nconst MARKER_STUB_DY = -8;\nconst MARKER_TEXT_OFFSET_X = 6;\nconst MARKER_TEXT_FONT = \"12px sans-serif\";\nconst TWO_PI = Math.PI * 2;\n\n/**\n * Decompose a `text` drawing — a single label at the projected anchor,\n * its font / alignment / colour resolved from `TextOpts`. `bgColor` is\n * carried through onto the IR `text` primitive (adapters that can paint\n * a background rect may use it; the canvas sink ignores it).\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: TextState;\n * declare const v: Viewport;\n * const prims = decomposeText(s, v);\n * // prims[0].kind === \"text\"\n * void prims;\n */\nexport function decomposeText(state: TextState, view: Viewport): ReadonlyArray<DrawPrimitive> {\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.body,\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\n/**\n * Decompose an `arrow` drawing — a stroked shaft, a filled arrowhead\n * triangle at the head anchor, and an optional label at the shaft\n * midpoint. Stroke and arrowhead fill share `style.color`.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: ArrowState;\n * declare const v: Viewport;\n * const prims = decomposeArrow(s, v);\n * // prims[0].kind === \"polyline\"; prims[1].kind === \"polyline\"\n * void prims;\n */\nexport function decomposeArrow(state: ArrowState, view: Viewport): 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_LINE_COLOR;\n const out: DrawPrimitive[] = [\n {\n kind: \"polyline\",\n points: [from, to],\n closed: false,\n stroke: {\n color,\n width: state.style.lineWidth ?? DEFAULT_LINE_WIDTH,\n dash: dashPattern(state.style.lineStyle ?? \"solid\"),\n },\n },\n {\n kind: \"polyline\",\n points: arrowheadPolygon(from, to),\n closed: true,\n fill: { color, alpha: SOLID_FILL_ALPHA },\n },\n ];\n if (state.style.label !== undefined) {\n out.push({\n kind: \"text\",\n x: (from.x + to.x) / 2,\n y: (from.y + to.y) / 2 - ARROW_LABEL_VERTICAL_OFFSET,\n text: state.style.label,\n color,\n font: ARROW_LABEL_FONT,\n align: \"center\",\n baseline: \"bottom\",\n });\n }\n return out;\n}\n\n/**\n * Decompose an `arrow-marker` drawing — a self-contained compact glyph\n * at the anchor: a filled dot, a short stub up + right, a filled\n * arrowhead at the stub end, and optional text to the right. Default\n * colour is `\"#3b82f6\"` (invinite toolbar blue).\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: ArrowMarkerState;\n * declare const v: Viewport;\n * const prims = decomposeArrowMarker(s, v);\n * void prims;\n */\nexport function decomposeArrowMarker(\n state: ArrowMarkerState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const anchor = worldPointToPixel(state.anchor, view);\n const color = state.style.color ?? DEFAULT_ARROW_MARKER_COLOR;\n const stubEnd = { x: anchor.x + MARKER_STUB_DX, y: anchor.y + MARKER_STUB_DY };\n const out: DrawPrimitive[] = [\n {\n kind: \"arc\",\n cx: anchor.x,\n cy: anchor.y,\n r: MARKER_DOT_RADIUS,\n start: 0,\n end: TWO_PI,\n closed: false,\n fill: { color, alpha: SOLID_FILL_ALPHA },\n },\n {\n kind: \"polyline\",\n points: [anchor, stubEnd],\n closed: false,\n stroke: { color, width: DEFAULT_LINE_WIDTH, dash: dashPattern(\"solid\") },\n },\n {\n kind: \"polyline\",\n points: arrowheadPolygon(anchor, stubEnd),\n closed: true,\n fill: { color, alpha: SOLID_FILL_ALPHA },\n },\n ];\n if (state.style.text !== undefined) {\n out.push({\n kind: \"text\",\n x: anchor.x + MARKER_TEXT_OFFSET_X,\n y: anchor.y,\n text: state.style.text,\n color,\n font: MARKER_TEXT_FONT,\n align: \"left\",\n baseline: \"middle\",\n });\n }\n return out;\n}\n\n/**\n * Decompose an `arrow-mark-up` drawing — a filled up-chevron glyph at\n * the anchor. Default fill colour is `\"#22c55e\"` (green); an explicit\n * `style.color` overrides.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: ArrowMarkUpState;\n * declare const v: Viewport;\n * const prims = decomposeArrowMarkUp(s, v);\n * void prims;\n */\nexport function decomposeArrowMarkUp(\n state: ArrowMarkUpState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const anchor = worldPointToPixel(state.anchor, view);\n const color = state.style.color ?? DEFAULT_MARK_UP_COLOR;\n return [\n {\n kind: \"polyline\",\n points: chevronPolygon(anchor, \"up\"),\n closed: true,\n fill: { color, alpha: SOLID_FILL_ALPHA },\n },\n ];\n}\n\n/**\n * Decompose an `arrow-mark-down` drawing — a filled down-chevron glyph\n * at the anchor. Default fill colour is `\"#ef4444\"` (red); an explicit\n * `style.color` overrides.\n *\n * @since 1.3\n * @stable\n * @example\n * declare const s: ArrowMarkDownState;\n * declare const v: Viewport;\n * const prims = decomposeArrowMarkDown(s, v);\n * void prims;\n */\nexport function decomposeArrowMarkDown(\n state: ArrowMarkDownState,\n view: Viewport,\n): ReadonlyArray<DrawPrimitive> {\n const anchor = worldPointToPixel(state.anchor, view);\n const color = state.style.color ?? DEFAULT_MARK_DOWN_COLOR;\n return [\n {\n kind: \"polyline\",\n points: chevronPolygon(anchor, \"down\"),\n closed: true,\n fill: { color, alpha: SOLID_FILL_ALPHA },\n },\n ];\n}\n"]}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { CircleState, EllipseState, FillBetweenState, PathState, PolylineState, RectangleState, RotatedRectangleState, TriangleState } from "@invinite-org/chartlang-core";
|
|
2
|
+
import type { DrawPrimitive, Viewport } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Decompose a `rectangle` drawing — a closed 4-corner polygon derived
|
|
5
|
+
* from the axis-aligned bounding box of the two projected anchors.
|
|
6
|
+
*
|
|
7
|
+
* @since 1.3
|
|
8
|
+
* @stable
|
|
9
|
+
* @example
|
|
10
|
+
* declare const s: RectangleState;
|
|
11
|
+
* declare const v: Viewport;
|
|
12
|
+
* const prims = decomposeRectangle(s, v);
|
|
13
|
+
* // prims[0].kind === "polyline"; prims[0].closed === true
|
|
14
|
+
* void prims;
|
|
15
|
+
*/
|
|
16
|
+
export declare function decomposeRectangle(state: RectangleState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
17
|
+
/**
|
|
18
|
+
* Decompose a `rotated-rectangle` drawing — a closed polygon through
|
|
19
|
+
* the four projected anchors (carried in stroke order, so no matrix
|
|
20
|
+
* math is needed).
|
|
21
|
+
*
|
|
22
|
+
* @since 1.3
|
|
23
|
+
* @stable
|
|
24
|
+
* @example
|
|
25
|
+
* declare const s: RotatedRectangleState;
|
|
26
|
+
* declare const v: Viewport;
|
|
27
|
+
* const prims = decomposeRotatedRectangle(s, v);
|
|
28
|
+
* void prims;
|
|
29
|
+
*/
|
|
30
|
+
export declare function decomposeRotatedRectangle(state: RotatedRectangleState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
31
|
+
/**
|
|
32
|
+
* Decompose a `triangle` drawing — a closed 3-vertex polygon.
|
|
33
|
+
*
|
|
34
|
+
* @since 1.3
|
|
35
|
+
* @stable
|
|
36
|
+
* @example
|
|
37
|
+
* declare const s: TriangleState;
|
|
38
|
+
* declare const v: Viewport;
|
|
39
|
+
* const prims = decomposeTriangle(s, v);
|
|
40
|
+
* void prims;
|
|
41
|
+
*/
|
|
42
|
+
export declare function decomposeTriangle(state: TriangleState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
43
|
+
/**
|
|
44
|
+
* Decompose a `polyline` drawing — a closed N-vertex polyline carrying
|
|
45
|
+
* a `LineDrawStyle` (no fill).
|
|
46
|
+
*
|
|
47
|
+
* @since 1.3
|
|
48
|
+
* @stable
|
|
49
|
+
* @example
|
|
50
|
+
* declare const s: PolylineState;
|
|
51
|
+
* declare const v: Viewport;
|
|
52
|
+
* const prims = decomposePolyline(s, v);
|
|
53
|
+
* // prims[0].closed === true
|
|
54
|
+
* void prims;
|
|
55
|
+
*/
|
|
56
|
+
export declare function decomposePolyline(state: PolylineState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
57
|
+
/**
|
|
58
|
+
* Decompose a `circle` drawing — an arc whose radius is the projected
|
|
59
|
+
* pixel distance between the centre anchor and the radius anchor (so
|
|
60
|
+
* the stroke keeps the same apparent thickness across zoom changes).
|
|
61
|
+
*
|
|
62
|
+
* @since 1.3
|
|
63
|
+
* @stable
|
|
64
|
+
* @example
|
|
65
|
+
* declare const s: CircleState;
|
|
66
|
+
* declare const v: Viewport;
|
|
67
|
+
* const prims = decomposeCircle(s, v);
|
|
68
|
+
* // prims[0].kind === "arc"
|
|
69
|
+
* void prims;
|
|
70
|
+
*/
|
|
71
|
+
export declare function decomposeCircle(state: CircleState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
72
|
+
/**
|
|
73
|
+
* Decompose an axis-aligned `ellipse` drawing — a closed
|
|
74
|
+
* {@link ELLIPSE_SEGMENTS}-segment polyline inscribed in the bounding
|
|
75
|
+
* box of the two anchors. Rotated ellipses are out of scope.
|
|
76
|
+
*
|
|
77
|
+
* @since 1.3
|
|
78
|
+
* @stable
|
|
79
|
+
* @example
|
|
80
|
+
* declare const s: EllipseState;
|
|
81
|
+
* declare const v: Viewport;
|
|
82
|
+
* const prims = decomposeEllipse(s, v);
|
|
83
|
+
* void prims;
|
|
84
|
+
*/
|
|
85
|
+
export declare function decomposeEllipse(state: EllipseState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
86
|
+
/**
|
|
87
|
+
* Decompose a `path` drawing — an OPEN N-vertex polyline (unless
|
|
88
|
+
* `style.closed === true`) carrying a `PathOpts` style (no fill).
|
|
89
|
+
*
|
|
90
|
+
* @since 1.3
|
|
91
|
+
* @stable
|
|
92
|
+
* @example
|
|
93
|
+
* declare const s: PathState;
|
|
94
|
+
* declare const v: Viewport;
|
|
95
|
+
* const prims = decomposePath(s, v);
|
|
96
|
+
* void prims;
|
|
97
|
+
*/
|
|
98
|
+
export declare function decomposePath(state: PathState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
99
|
+
/**
|
|
100
|
+
* Decompose a `fill-between` drawing — a closed filled polygon walking
|
|
101
|
+
* `edgeA` forward then `edgeB` in reverse. The optional outline strokes
|
|
102
|
+
* only when `style.color` is set; the band fills only when `style.fill`
|
|
103
|
+
* is set. A degenerate edge (`< 1` point) or a non-finite mapped anchor
|
|
104
|
+
* is a silent no-op (returns `[]`), matching the source renderer's
|
|
105
|
+
* warmup behaviour.
|
|
106
|
+
*
|
|
107
|
+
* @since 1.3
|
|
108
|
+
* @stable
|
|
109
|
+
* @example
|
|
110
|
+
* declare const s: FillBetweenState;
|
|
111
|
+
* declare const v: Viewport;
|
|
112
|
+
* const prims = decomposeFillBetween(s, v);
|
|
113
|
+
* void prims;
|
|
114
|
+
*/
|
|
115
|
+
export declare function decomposeFillBetween(state: FillBetweenState, view: Viewport): ReadonlyArray<DrawPrimitive>;
|
|
116
|
+
//# sourceMappingURL=boxes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boxes.d.ts","sourceRoot":"","sources":["../../../src/geometry/kinds/boxes.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACR,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,aAAa,EAChB,MAAM,8BAA8B,CAAC;AAKtC,OAAO,KAAK,EAAE,aAAa,EAAU,QAAQ,EAAE,MAAM,aAAa,CAAC;AAcnE;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAsB9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CACrC,KAAK,EAAE,qBAAqB,EAC5B,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAY9B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAY9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAc9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,GAAG,aAAa,CAAC,aAAa,CAAC,CAkBhG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC5B,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CAsB9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,GAAG,aAAa,CAAC,aAAa,CAAC,CAc5F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAChC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,QAAQ,GACf,aAAa,CAAC,aAAa,CAAC,CA4B9B"}
|
|
@@ -0,0 +1,285 @@
|
|
|
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
|
+
// Stroke + fill geometry moved from the canvas2d adapter's per-kind
|
|
5
|
+
// shape renderers
|
|
6
|
+
// examples/canvas2d-adapter/src/render/draw/{rectangle,
|
|
7
|
+
// rotatedRectangle,triangle,polyline,circle,ellipse,path,
|
|
8
|
+
// fillBetween}.ts.
|
|
9
|
+
// The originating math is invinite's rectangle / rotated-rectangle /
|
|
10
|
+
// triangle / polyline / circle / ellipse / path tools (commit
|
|
11
|
+
// 078f41fe2569d659d5aba726da8bcb5d3e2ced02, © Invinite); re-licensed
|
|
12
|
+
// MIT for chartlang.
|
|
13
|
+
import { dashPattern } from "../_lib/dash.js";
|
|
14
|
+
import { resolveShapeStyle } from "../_lib/shapeStyle.js";
|
|
15
|
+
import { worldPointToPixel } from "../project.js";
|
|
16
|
+
const DEFAULT_LINE_WIDTH = 1;
|
|
17
|
+
const DEFAULT_FILL_ALPHA = 1;
|
|
18
|
+
const TWO_PI = Math.PI * 2;
|
|
19
|
+
/**
|
|
20
|
+
* Number of polyline segments used to approximate an `ellipse`. 64
|
|
21
|
+
* segments give visually smooth strokes at typical viewport widths
|
|
22
|
+
* (≈800 px) while keeping the primitive list bounded — matching the
|
|
23
|
+
* canvas2d source renderer exactly.
|
|
24
|
+
*/
|
|
25
|
+
const ELLIPSE_SEGMENTS = 64;
|
|
26
|
+
/**
|
|
27
|
+
* Decompose a `rectangle` drawing — a closed 4-corner polygon derived
|
|
28
|
+
* from the axis-aligned bounding box of the two projected anchors.
|
|
29
|
+
*
|
|
30
|
+
* @since 1.3
|
|
31
|
+
* @stable
|
|
32
|
+
* @example
|
|
33
|
+
* declare const s: RectangleState;
|
|
34
|
+
* declare const v: Viewport;
|
|
35
|
+
* const prims = decomposeRectangle(s, v);
|
|
36
|
+
* // prims[0].kind === "polyline"; prims[0].closed === true
|
|
37
|
+
* void prims;
|
|
38
|
+
*/
|
|
39
|
+
export function decomposeRectangle(state, view) {
|
|
40
|
+
const a = worldPointToPixel(state.anchors[0], view);
|
|
41
|
+
const b = worldPointToPixel(state.anchors[1], view);
|
|
42
|
+
const xMin = Math.min(a.x, b.x);
|
|
43
|
+
const xMax = Math.max(a.x, b.x);
|
|
44
|
+
const yMin = Math.min(a.y, b.y);
|
|
45
|
+
const yMax = Math.max(a.y, b.y);
|
|
46
|
+
const { stroke, fill } = resolveShapeStyle(state.style);
|
|
47
|
+
return [
|
|
48
|
+
{
|
|
49
|
+
kind: "polyline",
|
|
50
|
+
points: [
|
|
51
|
+
{ x: xMin, y: yMin },
|
|
52
|
+
{ x: xMax, y: yMin },
|
|
53
|
+
{ x: xMax, y: yMax },
|
|
54
|
+
{ x: xMin, y: yMax },
|
|
55
|
+
],
|
|
56
|
+
closed: true,
|
|
57
|
+
stroke,
|
|
58
|
+
...(fill === undefined ? {} : { fill }),
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Decompose a `rotated-rectangle` drawing — a closed polygon through
|
|
64
|
+
* the four projected anchors (carried in stroke order, so no matrix
|
|
65
|
+
* math is needed).
|
|
66
|
+
*
|
|
67
|
+
* @since 1.3
|
|
68
|
+
* @stable
|
|
69
|
+
* @example
|
|
70
|
+
* declare const s: RotatedRectangleState;
|
|
71
|
+
* declare const v: Viewport;
|
|
72
|
+
* const prims = decomposeRotatedRectangle(s, v);
|
|
73
|
+
* void prims;
|
|
74
|
+
*/
|
|
75
|
+
export function decomposeRotatedRectangle(state, view) {
|
|
76
|
+
const points = state.anchors.map((p) => worldPointToPixel(p, view));
|
|
77
|
+
const { stroke, fill } = resolveShapeStyle(state.style);
|
|
78
|
+
return [
|
|
79
|
+
{
|
|
80
|
+
kind: "polyline",
|
|
81
|
+
points,
|
|
82
|
+
closed: true,
|
|
83
|
+
stroke,
|
|
84
|
+
...(fill === undefined ? {} : { fill }),
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Decompose a `triangle` drawing — a closed 3-vertex polygon.
|
|
90
|
+
*
|
|
91
|
+
* @since 1.3
|
|
92
|
+
* @stable
|
|
93
|
+
* @example
|
|
94
|
+
* declare const s: TriangleState;
|
|
95
|
+
* declare const v: Viewport;
|
|
96
|
+
* const prims = decomposeTriangle(s, v);
|
|
97
|
+
* void prims;
|
|
98
|
+
*/
|
|
99
|
+
export function decomposeTriangle(state, view) {
|
|
100
|
+
const points = state.anchors.map((p) => worldPointToPixel(p, view));
|
|
101
|
+
const { stroke, fill } = resolveShapeStyle(state.style);
|
|
102
|
+
return [
|
|
103
|
+
{
|
|
104
|
+
kind: "polyline",
|
|
105
|
+
points,
|
|
106
|
+
closed: true,
|
|
107
|
+
stroke,
|
|
108
|
+
...(fill === undefined ? {} : { fill }),
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Decompose a `polyline` drawing — a closed N-vertex polyline carrying
|
|
114
|
+
* a `LineDrawStyle` (no fill).
|
|
115
|
+
*
|
|
116
|
+
* @since 1.3
|
|
117
|
+
* @stable
|
|
118
|
+
* @example
|
|
119
|
+
* declare const s: PolylineState;
|
|
120
|
+
* declare const v: Viewport;
|
|
121
|
+
* const prims = decomposePolyline(s, v);
|
|
122
|
+
* // prims[0].closed === true
|
|
123
|
+
* void prims;
|
|
124
|
+
*/
|
|
125
|
+
export function decomposePolyline(state, view) {
|
|
126
|
+
const points = state.anchors.map((p) => worldPointToPixel(p, view));
|
|
127
|
+
return [
|
|
128
|
+
{
|
|
129
|
+
kind: "polyline",
|
|
130
|
+
points,
|
|
131
|
+
closed: true,
|
|
132
|
+
stroke: {
|
|
133
|
+
color: state.style.color ?? "#000000",
|
|
134
|
+
width: state.style.lineWidth ?? DEFAULT_LINE_WIDTH,
|
|
135
|
+
dash: dashPattern(state.style.lineStyle ?? "solid"),
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
];
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Decompose a `circle` drawing — an arc whose radius is the projected
|
|
142
|
+
* pixel distance between the centre anchor and the radius anchor (so
|
|
143
|
+
* the stroke keeps the same apparent thickness across zoom changes).
|
|
144
|
+
*
|
|
145
|
+
* @since 1.3
|
|
146
|
+
* @stable
|
|
147
|
+
* @example
|
|
148
|
+
* declare const s: CircleState;
|
|
149
|
+
* declare const v: Viewport;
|
|
150
|
+
* const prims = decomposeCircle(s, v);
|
|
151
|
+
* // prims[0].kind === "arc"
|
|
152
|
+
* void prims;
|
|
153
|
+
*/
|
|
154
|
+
export function decomposeCircle(state, view) {
|
|
155
|
+
const centre = worldPointToPixel(state.anchors[0], view);
|
|
156
|
+
const edge = worldPointToPixel(state.anchors[1], view);
|
|
157
|
+
const radius = Math.hypot(edge.x - centre.x, edge.y - centre.y);
|
|
158
|
+
const { stroke, fill } = resolveShapeStyle(state.style);
|
|
159
|
+
return [
|
|
160
|
+
{
|
|
161
|
+
kind: "arc",
|
|
162
|
+
cx: centre.x,
|
|
163
|
+
cy: centre.y,
|
|
164
|
+
r: radius,
|
|
165
|
+
start: 0,
|
|
166
|
+
end: TWO_PI,
|
|
167
|
+
closed: true,
|
|
168
|
+
stroke,
|
|
169
|
+
...(fill === undefined ? {} : { fill }),
|
|
170
|
+
},
|
|
171
|
+
];
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Decompose an axis-aligned `ellipse` drawing — a closed
|
|
175
|
+
* {@link ELLIPSE_SEGMENTS}-segment polyline inscribed in the bounding
|
|
176
|
+
* box of the two anchors. Rotated ellipses are out of scope.
|
|
177
|
+
*
|
|
178
|
+
* @since 1.3
|
|
179
|
+
* @stable
|
|
180
|
+
* @example
|
|
181
|
+
* declare const s: EllipseState;
|
|
182
|
+
* declare const v: Viewport;
|
|
183
|
+
* const prims = decomposeEllipse(s, v);
|
|
184
|
+
* void prims;
|
|
185
|
+
*/
|
|
186
|
+
export function decomposeEllipse(state, view) {
|
|
187
|
+
const a = worldPointToPixel(state.anchors[0], view);
|
|
188
|
+
const b = worldPointToPixel(state.anchors[1], view);
|
|
189
|
+
const cx = (a.x + b.x) / 2;
|
|
190
|
+
const cy = (a.y + b.y) / 2;
|
|
191
|
+
const rx = Math.abs(b.x - a.x) / 2;
|
|
192
|
+
const ry = Math.abs(b.y - a.y) / 2;
|
|
193
|
+
const points = [{ x: cx + rx, y: cy }];
|
|
194
|
+
for (let i = 1; i < ELLIPSE_SEGMENTS; i++) {
|
|
195
|
+
const theta = (i / ELLIPSE_SEGMENTS) * TWO_PI;
|
|
196
|
+
points.push({ x: cx + rx * Math.cos(theta), y: cy + ry * Math.sin(theta) });
|
|
197
|
+
}
|
|
198
|
+
const { stroke, fill } = resolveShapeStyle(state.style);
|
|
199
|
+
return [
|
|
200
|
+
{
|
|
201
|
+
kind: "polyline",
|
|
202
|
+
points,
|
|
203
|
+
closed: true,
|
|
204
|
+
stroke,
|
|
205
|
+
...(fill === undefined ? {} : { fill }),
|
|
206
|
+
},
|
|
207
|
+
];
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Decompose a `path` drawing — an OPEN N-vertex polyline (unless
|
|
211
|
+
* `style.closed === true`) carrying a `PathOpts` style (no fill).
|
|
212
|
+
*
|
|
213
|
+
* @since 1.3
|
|
214
|
+
* @stable
|
|
215
|
+
* @example
|
|
216
|
+
* declare const s: PathState;
|
|
217
|
+
* declare const v: Viewport;
|
|
218
|
+
* const prims = decomposePath(s, v);
|
|
219
|
+
* void prims;
|
|
220
|
+
*/
|
|
221
|
+
export function decomposePath(state, view) {
|
|
222
|
+
const points = state.anchors.map((p) => worldPointToPixel(p, view));
|
|
223
|
+
return [
|
|
224
|
+
{
|
|
225
|
+
kind: "polyline",
|
|
226
|
+
points,
|
|
227
|
+
closed: state.style.closed === true,
|
|
228
|
+
stroke: {
|
|
229
|
+
color: state.style.color ?? "#000000",
|
|
230
|
+
width: state.style.lineWidth ?? DEFAULT_LINE_WIDTH,
|
|
231
|
+
dash: dashPattern(state.style.lineStyle ?? "solid"),
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
];
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Decompose a `fill-between` drawing — a closed filled polygon walking
|
|
238
|
+
* `edgeA` forward then `edgeB` in reverse. The optional outline strokes
|
|
239
|
+
* only when `style.color` is set; the band fills only when `style.fill`
|
|
240
|
+
* is set. A degenerate edge (`< 1` point) or a non-finite mapped anchor
|
|
241
|
+
* is a silent no-op (returns `[]`), matching the source renderer's
|
|
242
|
+
* warmup behaviour.
|
|
243
|
+
*
|
|
244
|
+
* @since 1.3
|
|
245
|
+
* @stable
|
|
246
|
+
* @example
|
|
247
|
+
* declare const s: FillBetweenState;
|
|
248
|
+
* declare const v: Viewport;
|
|
249
|
+
* const prims = decomposeFillBetween(s, v);
|
|
250
|
+
* void prims;
|
|
251
|
+
*/
|
|
252
|
+
export function decomposeFillBetween(state, view) {
|
|
253
|
+
const a = state.edgeA.map((p) => worldPointToPixel(p, view));
|
|
254
|
+
const b = state.edgeB.map((p) => worldPointToPixel(p, view));
|
|
255
|
+
if (a.length < 1 || b.length < 1)
|
|
256
|
+
return [];
|
|
257
|
+
if (a.some((p) => !Number.isFinite(p.x) || !Number.isFinite(p.y)))
|
|
258
|
+
return [];
|
|
259
|
+
if (b.some((p) => !Number.isFinite(p.x) || !Number.isFinite(p.y)))
|
|
260
|
+
return [];
|
|
261
|
+
const points = [...a];
|
|
262
|
+
for (let i = b.length - 1; i >= 0; i--)
|
|
263
|
+
points.push(b[i]);
|
|
264
|
+
const { color, fill } = state.style;
|
|
265
|
+
return [
|
|
266
|
+
{
|
|
267
|
+
kind: "polyline",
|
|
268
|
+
points,
|
|
269
|
+
closed: true,
|
|
270
|
+
...(color === undefined
|
|
271
|
+
? {}
|
|
272
|
+
: {
|
|
273
|
+
stroke: {
|
|
274
|
+
color,
|
|
275
|
+
width: state.style.lineWidth ?? DEFAULT_LINE_WIDTH,
|
|
276
|
+
dash: dashPattern(state.style.lineStyle ?? "solid"),
|
|
277
|
+
},
|
|
278
|
+
}),
|
|
279
|
+
...(fill === undefined
|
|
280
|
+
? {}
|
|
281
|
+
: { fill: { color: fill, alpha: state.style.fillAlpha ?? DEFAULT_FILL_ALPHA } }),
|
|
282
|
+
},
|
|
283
|
+
];
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=boxes.js.map
|