insomni-plot 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/LICENSE.md +674 -0
  2. package/README.md +81 -0
  3. package/dist/core.d.mts +340 -0
  4. package/dist/core.mjs +1047 -0
  5. package/dist/index.d.mts +3426 -0
  6. package/dist/index.mjs +12762 -0
  7. package/dist/interactions-DEFL_F4E.mjs +5395 -0
  8. package/dist/range-presets-CzECsu3V.d.mts +1523 -0
  9. package/package.json +34 -0
  10. package/src/annotations.d.ts +121 -0
  11. package/src/annotations.ts +438 -0
  12. package/src/axis.d.ts +184 -0
  13. package/src/axis.test.ts +131 -0
  14. package/src/axis.ts +765 -0
  15. package/src/colorbar.d.ts +69 -0
  16. package/src/colorbar.ts +294 -0
  17. package/src/colors.d.ts +57 -0
  18. package/src/colors.test.ts +28 -0
  19. package/src/colors.ts +486 -0
  20. package/src/core.ts +299 -0
  21. package/src/format.d.ts +54 -0
  22. package/src/format.ts +138 -0
  23. package/src/grammar/accessibility.d.ts +147 -0
  24. package/src/grammar/accessibility.test.ts +199 -0
  25. package/src/grammar/accessibility.ts +443 -0
  26. package/src/grammar/aes.d.ts +35 -0
  27. package/src/grammar/aes.test.ts +75 -0
  28. package/src/grammar/aes.ts +120 -0
  29. package/src/grammar/annotations.d.ts +86 -0
  30. package/src/grammar/annotations.test.ts +68 -0
  31. package/src/grammar/annotations.ts +336 -0
  32. package/src/grammar/attach-brush.d.ts +44 -0
  33. package/src/grammar/attach-brush.test.ts +214 -0
  34. package/src/grammar/attach-brush.ts +111 -0
  35. package/src/grammar/attach-presets.d.ts +33 -0
  36. package/src/grammar/attach-presets.test.ts +106 -0
  37. package/src/grammar/attach-presets.ts +215 -0
  38. package/src/grammar/chart.d.ts +952 -0
  39. package/src/grammar/chart.test.ts +118 -0
  40. package/src/grammar/chart.ts +1172 -0
  41. package/src/grammar/color-utils.d.ts +29 -0
  42. package/src/grammar/color-utils.test.ts +53 -0
  43. package/src/grammar/color-utils.ts +66 -0
  44. package/src/grammar/constants.d.ts +45 -0
  45. package/src/grammar/constants.ts +61 -0
  46. package/src/grammar/coord.d.ts +183 -0
  47. package/src/grammar/coord.test.ts +355 -0
  48. package/src/grammar/coord.ts +619 -0
  49. package/src/grammar/data/pivot.d.ts +57 -0
  50. package/src/grammar/data/pivot.ts +107 -0
  51. package/src/grammar/emphasis-driver.d.ts +69 -0
  52. package/src/grammar/emphasis-driver.test.ts +199 -0
  53. package/src/grammar/emphasis-driver.ts +205 -0
  54. package/src/grammar/equality.d.ts +3 -0
  55. package/src/grammar/equality.ts +40 -0
  56. package/src/grammar/facet.d.ts +63 -0
  57. package/src/grammar/facet.test.ts +60 -0
  58. package/src/grammar/facet.ts +175 -0
  59. package/src/grammar/geoms/_categorical.d.ts +94 -0
  60. package/src/grammar/geoms/_categorical.ts +0 -0
  61. package/src/grammar/geoms/_distribution.d.ts +52 -0
  62. package/src/grammar/geoms/_distribution.ts +125 -0
  63. package/src/grammar/geoms/_mark.d.ts +69 -0
  64. package/src/grammar/geoms/_mark.ts +136 -0
  65. package/src/grammar/geoms/_shape.d.ts +41 -0
  66. package/src/grammar/geoms/_shape.ts +74 -0
  67. package/src/grammar/geoms/aggregate.d.ts +95 -0
  68. package/src/grammar/geoms/aggregate.test.ts +554 -0
  69. package/src/grammar/geoms/aggregate.ts +840 -0
  70. package/src/grammar/geoms/area.d.ts +32 -0
  71. package/src/grammar/geoms/area.test.ts +165 -0
  72. package/src/grammar/geoms/area.ts +578 -0
  73. package/src/grammar/geoms/band.d.ts +27 -0
  74. package/src/grammar/geoms/band.test.ts +57 -0
  75. package/src/grammar/geoms/band.ts +126 -0
  76. package/src/grammar/geoms/bar.d.ts +56 -0
  77. package/src/grammar/geoms/bar.test.ts +367 -0
  78. package/src/grammar/geoms/bar.ts +1054 -0
  79. package/src/grammar/geoms/boxplot.d.ts +129 -0
  80. package/src/grammar/geoms/boxplot.test.ts +299 -0
  81. package/src/grammar/geoms/boxplot.ts +834 -0
  82. package/src/grammar/geoms/connected-scatter.d.ts +27 -0
  83. package/src/grammar/geoms/connected-scatter.test.ts +157 -0
  84. package/src/grammar/geoms/connected-scatter.ts +63 -0
  85. package/src/grammar/geoms/emphasis.d.ts +76 -0
  86. package/src/grammar/geoms/emphasis.test.ts +135 -0
  87. package/src/grammar/geoms/emphasis.ts +162 -0
  88. package/src/grammar/geoms/histogram.d.ts +75 -0
  89. package/src/grammar/geoms/histogram.test.ts +262 -0
  90. package/src/grammar/geoms/histogram.ts +740 -0
  91. package/src/grammar/geoms/index.d.ts +20 -0
  92. package/src/grammar/geoms/index.ts +77 -0
  93. package/src/grammar/geoms/interval.d.ts +31 -0
  94. package/src/grammar/geoms/interval.test.ts +154 -0
  95. package/src/grammar/geoms/interval.ts +342 -0
  96. package/src/grammar/geoms/line.d.ts +38 -0
  97. package/src/grammar/geoms/line.test.ts +247 -0
  98. package/src/grammar/geoms/line.ts +659 -0
  99. package/src/grammar/geoms/point.d.ts +57 -0
  100. package/src/grammar/geoms/point.test.ts +163 -0
  101. package/src/grammar/geoms/point.ts +545 -0
  102. package/src/grammar/geoms/polar.test.ts +216 -0
  103. package/src/grammar/geoms/ribbon.d.ts +21 -0
  104. package/src/grammar/geoms/ribbon.test.ts +170 -0
  105. package/src/grammar/geoms/ribbon.ts +87 -0
  106. package/src/grammar/geoms/ridgeline.d.ts +89 -0
  107. package/src/grammar/geoms/ridgeline.test.ts +247 -0
  108. package/src/grammar/geoms/ridgeline.ts +1164 -0
  109. package/src/grammar/geoms/rolling.d.ts +43 -0
  110. package/src/grammar/geoms/rolling.test.ts +217 -0
  111. package/src/grammar/geoms/rolling.ts +387 -0
  112. package/src/grammar/geoms/rug.d.ts +28 -0
  113. package/src/grammar/geoms/rug.test.ts +126 -0
  114. package/src/grammar/geoms/rug.ts +214 -0
  115. package/src/grammar/geoms/rule.d.ts +23 -0
  116. package/src/grammar/geoms/rule.test.ts +69 -0
  117. package/src/grammar/geoms/rule.ts +212 -0
  118. package/src/grammar/geoms/smooth.d.ts +54 -0
  119. package/src/grammar/geoms/smooth.test.ts +78 -0
  120. package/src/grammar/geoms/smooth.ts +337 -0
  121. package/src/grammar/geoms/text.d.ts +29 -0
  122. package/src/grammar/geoms/text.test.ts +64 -0
  123. package/src/grammar/geoms/text.ts +234 -0
  124. package/src/grammar/geoms/tile.d.ts +61 -0
  125. package/src/grammar/geoms/tile.test.ts +157 -0
  126. package/src/grammar/geoms/tile.ts +621 -0
  127. package/src/grammar/geoms/types.d.ts +319 -0
  128. package/src/grammar/geoms/types.ts +362 -0
  129. package/src/grammar/geoms/violin.d.ts +85 -0
  130. package/src/grammar/geoms/violin.test.ts +187 -0
  131. package/src/grammar/geoms/violin.ts +672 -0
  132. package/src/grammar/index.d.ts +22 -0
  133. package/src/grammar/index.ts +269 -0
  134. package/src/grammar/interactions/_disposable.d.ts +5 -0
  135. package/src/grammar/interactions/_disposable.ts +23 -0
  136. package/src/grammar/interactions/_z.d.ts +4 -0
  137. package/src/grammar/interactions/_z.ts +16 -0
  138. package/src/grammar/interactions/brush-selection.test.ts +262 -0
  139. package/src/grammar/interactions/brush.d.ts +63 -0
  140. package/src/grammar/interactions/brush.test.ts +483 -0
  141. package/src/grammar/interactions/brush.ts +452 -0
  142. package/src/grammar/interactions/crosshair.d.ts +19 -0
  143. package/src/grammar/interactions/crosshair.test.ts +127 -0
  144. package/src/grammar/interactions/crosshair.ts +76 -0
  145. package/src/grammar/interactions/hit-layer.d.ts +64 -0
  146. package/src/grammar/interactions/hit-layer.ts +246 -0
  147. package/src/grammar/interactions/legend.d.ts +19 -0
  148. package/src/grammar/interactions/legend.ts +101 -0
  149. package/src/grammar/interactions/menu.d.ts +93 -0
  150. package/src/grammar/interactions/menu.test.ts +373 -0
  151. package/src/grammar/interactions/menu.ts +342 -0
  152. package/src/grammar/interactions/selection.d.ts +25 -0
  153. package/src/grammar/interactions/selection.test.ts +289 -0
  154. package/src/grammar/interactions/selection.ts +142 -0
  155. package/src/grammar/interactions/series-readout.d.ts +91 -0
  156. package/src/grammar/interactions/series-readout.test.ts +668 -0
  157. package/src/grammar/interactions/series-readout.ts +422 -0
  158. package/src/grammar/interactions/series-snap.d.ts +70 -0
  159. package/src/grammar/interactions/series-snap.test.ts +214 -0
  160. package/src/grammar/interactions/series-snap.ts +218 -0
  161. package/src/grammar/interactions/tooltip-axis.test.ts +176 -0
  162. package/src/grammar/interactions/tooltip-touch.browser.test.ts +49 -0
  163. package/src/grammar/interactions/tooltip-touch.test.ts +161 -0
  164. package/src/grammar/interactions/tooltip.d.ts +140 -0
  165. package/src/grammar/interactions/tooltip.test.ts +406 -0
  166. package/src/grammar/interactions/tooltip.ts +622 -0
  167. package/src/grammar/interactions/transitions.d.ts +34 -0
  168. package/src/grammar/interactions/transitions.test.ts +172 -0
  169. package/src/grammar/interactions/transitions.ts +160 -0
  170. package/src/grammar/layout.d.ts +68 -0
  171. package/src/grammar/layout.ts +186 -0
  172. package/src/grammar/legend-merge.test.ts +332 -0
  173. package/src/grammar/mount.d.ts +78 -0
  174. package/src/grammar/mount.test.ts +479 -0
  175. package/src/grammar/mount.ts +2112 -0
  176. package/src/grammar/palettes.d.ts +54 -0
  177. package/src/grammar/palettes.test.ts +80 -0
  178. package/src/grammar/palettes.ts +167 -0
  179. package/src/grammar/pan-zoom.test.ts +398 -0
  180. package/src/grammar/phylo.d.ts +65 -0
  181. package/src/grammar/phylo.test.ts +59 -0
  182. package/src/grammar/phylo.ts +112 -0
  183. package/src/grammar/pipeline.auto-ticks.test.ts +40 -0
  184. package/src/grammar/pipeline.d.ts +158 -0
  185. package/src/grammar/pipeline.test.ts +463 -0
  186. package/src/grammar/pipeline.ts +1233 -0
  187. package/src/grammar/profiling.d.ts +8 -0
  188. package/src/grammar/profiling.ts +24 -0
  189. package/src/grammar/scales.d.ts +188 -0
  190. package/src/grammar/scales.test.ts +181 -0
  191. package/src/grammar/scales.ts +800 -0
  192. package/src/grammar/svg.d.ts +3 -0
  193. package/src/grammar/svg.ts +39 -0
  194. package/src/grammar/theme.d.ts +261 -0
  195. package/src/grammar/theme.test.ts +105 -0
  196. package/src/grammar/theme.ts +490 -0
  197. package/src/heatmap/cpu.ts +109 -0
  198. package/src/heatmap/gpu.ts +565 -0
  199. package/src/heatmap/types.ts +177 -0
  200. package/src/heatmap.browser.test.ts +308 -0
  201. package/src/heatmap.test.ts +320 -0
  202. package/src/heatmap.ts +123 -0
  203. package/src/index.d.ts +1 -0
  204. package/src/index.ts +8 -0
  205. package/src/interactions.d.ts +48 -0
  206. package/src/interactions.test.ts +226 -0
  207. package/src/interactions.ts +394 -0
  208. package/src/layout/box.d.ts +48 -0
  209. package/src/layout/box.test.ts +107 -0
  210. package/src/layout/box.ts +143 -0
  211. package/src/legend.d.ts +115 -0
  212. package/src/legend.ts +422 -0
  213. package/src/marks/curve.d.ts +43 -0
  214. package/src/marks/curve.ts +244 -0
  215. package/src/marks/stack.d.ts +53 -0
  216. package/src/marks/stack.ts +184 -0
  217. package/src/marks.d.ts +273 -0
  218. package/src/marks.test.ts +541 -0
  219. package/src/marks.ts +1292 -0
  220. package/src/navigator.test.ts +174 -0
  221. package/src/navigator.ts +393 -0
  222. package/src/range-presets.d.ts +113 -0
  223. package/src/range-presets.test.ts +345 -0
  224. package/src/range-presets.ts +349 -0
  225. package/src/scales.d.ts +98 -0
  226. package/src/scales.test.ts +103 -0
  227. package/src/scales.ts +695 -0
  228. package/src/stats/index.d.ts +200 -0
  229. package/src/stats/index.test.ts +349 -0
  230. package/src/stats/index.ts +740 -0
  231. package/src/stats/regression.d.ts +38 -0
  232. package/src/stats/regression.test.ts +56 -0
  233. package/src/stats/regression.ts +396 -0
  234. package/src/stats/rolling-window.d.ts +55 -0
  235. package/src/stats/rolling-window.test.ts +237 -0
  236. package/src/stats/rolling-window.ts +256 -0
  237. package/src/test-setup.ts +19 -0
  238. package/src/viewport/axis-state.d.ts +72 -0
  239. package/src/viewport/axis-state.ts +476 -0
  240. package/src/viewport.d.ts +170 -0
  241. package/src/viewport.test.ts +363 -0
  242. package/src/viewport.ts +510 -0
@@ -0,0 +1,136 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Geom compile helpers
3
+ // ---------------------------------------------------------------------------
4
+
5
+ import type { Color, Layer } from "insomni";
6
+ import type { MarkBuilder, MarkOrigin } from "../../marks.ts";
7
+ import { coordCartesian, type Coord } from "../coord.ts";
8
+ import type { Theme } from "../theme.ts";
9
+ import type { CompileContext, GeomKind, HoveredHit } from "./types.ts";
10
+
11
+ /**
12
+ * Resolve `ctx.coord` to a concrete {@link Coord}. The interface flags `coord`
13
+ * as optional in {@link CompileContext} during the Phase 1 migration to the
14
+ * `Coord` API — geoms call this once at the top of their compile path to get
15
+ * a non-null projection, falling back to {@link coordCartesian} when the
16
+ * pipeline didn't supply one (e.g. legacy direct-compile call sites). Under
17
+ * Cartesian both `project` and `segment` are the identity, so this is a
18
+ * zero-pixel-diff drop-in for every existing geom.
19
+ */
20
+ export function resolveCoord<T>(ctx: CompileContext<T>): Coord {
21
+ return ctx.coord ?? coordCartesian();
22
+ }
23
+
24
+ /**
25
+ * Default alpha applied to non-selected marks while a selection is active.
26
+ * Lifted into a constant so geoms stay consistent without each importing the
27
+ * theme's selection config; per-mount overrides happen via the selection
28
+ * config (see chart.ts:SelectionConfig.dimAlpha).
29
+ */
30
+ export const SELECTION_DIM_ALPHA = 0.3;
31
+
32
+ /**
33
+ * Returns the set of selected `dataIndex`es that belong to *this* geom (kind
34
+ * matches and the data array reference matches), or `null` when no selection
35
+ * row matches. Geoms use this to push stroke rings on the matching rows.
36
+ */
37
+ export function selectedIndicesFor<T>(ctx: CompileContext<T>, kind: GeomKind): Set<number> | null {
38
+ const sel = ctx.selected;
39
+ if (!sel || sel.length === 0) return null;
40
+ const data = ctx.data as readonly unknown[];
41
+ const out = new Set<number>();
42
+ for (const h of sel as readonly HoveredHit[]) {
43
+ if (h.geomKind === kind && h.data === data) out.add(h.dataIndex);
44
+ }
45
+ return out.size > 0 ? out : null;
46
+ }
47
+
48
+ /** True when any selection is active anywhere in the chart. */
49
+ export function selectionActive<T>(ctx: CompileContext<T>): boolean {
50
+ return !!ctx.selected && ctx.selected.length > 0;
51
+ }
52
+
53
+ /**
54
+ * Multi-series equivalent of {@link selectedIndicesFor}: returns the list of
55
+ * `(dataIndex, seriesKey)` pairs selected for *this* geom. Used by stacked /
56
+ * dodged geoms where a single source row produces multiple visible segments
57
+ * and the ring must distinguish them by series key.
58
+ */
59
+ export function selectedSegmentsFor<T>(
60
+ ctx: CompileContext<T>,
61
+ kind: GeomKind,
62
+ ): Array<{ dataIndex: number; seriesKey?: string }> | null {
63
+ const sel = ctx.selected;
64
+ if (!sel || sel.length === 0) return null;
65
+ const data = ctx.data as readonly unknown[];
66
+ const out: Array<{ dataIndex: number; seriesKey?: string }> = [];
67
+ for (const h of sel as readonly HoveredHit[]) {
68
+ if (h.geomKind === kind && h.data === data) {
69
+ out.push({ dataIndex: h.dataIndex, seriesKey: h.seriesKey });
70
+ }
71
+ }
72
+ return out.length > 0 ? out : null;
73
+ }
74
+
75
+ /**
76
+ * Wrap a `MarkBuilder` so it composes into the `compile()` builder list with
77
+ * a fixed origin (typically the plot frame's top-left). Geoms collect these
78
+ * into the array returned from `compile`. Pass `length` to override the
79
+ * builder's reported length — used for label sub-marks where the visual
80
+ * count differs from the underlying mark's vertex count.
81
+ */
82
+ export function wrapMark(
83
+ mark: MarkBuilder,
84
+ origin: MarkOrigin,
85
+ length: number = mark.length,
86
+ ): { length: number; addTo: (layer: Layer) => Layer } {
87
+ return {
88
+ length,
89
+ addTo: (layer: Layer) => mark.addTo(layer, origin),
90
+ };
91
+ }
92
+
93
+ /**
94
+ * Build a `MarkBuilder` from a draw callback. Used for one-off shapes that
95
+ * don't fit a mark factory — currently the hover-highlight halo each geom
96
+ * pushes for `ctx.hovered`. Coordinates passed to `draw` are layer-local
97
+ * (the caller has already applied any plot-frame offset).
98
+ */
99
+ export function inlineMark(draw: (layer: Layer) => void, length: number = 1): MarkBuilder {
100
+ return {
101
+ length,
102
+ addTo(layer: Layer) {
103
+ draw(layer);
104
+ return layer;
105
+ },
106
+ };
107
+ }
108
+
109
+ export function resolveFillAlpha(selected: boolean, theme: Theme): number {
110
+ return selected ? theme.marks.fillAlpha * SELECTION_DIM_ALPHA : theme.marks.fillAlpha;
111
+ }
112
+
113
+ export function defaultMarkFill(theme: Theme): Color {
114
+ return theme.palettes.categorical(0);
115
+ }
116
+
117
+ export function selectChannels<X, Y>(
118
+ orientation: "x" | "y",
119
+ channels: { x: X; y: Y },
120
+ ): { categoryChannel: X | Y; valueChannel: X | Y } {
121
+ return orientation === "y"
122
+ ? { categoryChannel: channels.x, valueChannel: channels.y }
123
+ : { categoryChannel: channels.y, valueChannel: channels.x };
124
+ }
125
+
126
+ /** Highlight ring used by point/line/area on `ctx.hovered`. */
127
+ export function haloRing(
128
+ layer: Layer,
129
+ cx: number,
130
+ cy: number,
131
+ radius: number,
132
+ color: Color,
133
+ width: number = 2,
134
+ ): void {
135
+ layer.pushCircle({ cx, cy, radius, stroke: color, strokeWidth: width });
136
+ }
@@ -0,0 +1,41 @@
1
+ import type { Color, Layer } from "insomni";
2
+ import type { MarkOrigin } from "../../marks.ts";
3
+ /**
4
+ * Halo rect to be painted on top of a geom's main fills, so the active
5
+ * hover row's outline isn't occluded by adjacent cells. `color` is per-halo
6
+ * so multi-series geoms (histogram) can use per-cell highlight colors while
7
+ * single-series geoms (tile) just thread one color through every entry.
8
+ */
9
+ export interface Halo {
10
+ x: number;
11
+ y: number;
12
+ w: number;
13
+ h: number;
14
+ color: Color;
15
+ }
16
+ /**
17
+ * Push every halo rect as a stroke-only outline on top of `layer`. Caller
18
+ * supplies the shared stroke width (typically `emphasis.haloStrokeWidth`)
19
+ * and an optional corner radius matching the underlying fills.
20
+ */
21
+ export declare function paintHalos(layer: Layer, halos: readonly Halo[], options: {
22
+ strokeWidth: number;
23
+ cornerRadius?: number;
24
+ }): void;
25
+ /**
26
+ * Orientation-aware bar bbox: takes the band-axis start + bandwidth and the
27
+ * value-axis pixel + baseline, returns the axis-aligned rect in mark-local
28
+ * coordinates (pre-translated by `origin`).
29
+ *
30
+ * `orientation === "y"` means categories on the x-axis (vertical bars rising
31
+ * along y); `"x"` means categories on the y-axis (horizontal bars).
32
+ *
33
+ * Returns `null` when either input pixel isn't finite — callers should
34
+ * `continue` on null so NaN bands don't produce zero-area garbage rects.
35
+ */
36
+ export declare function barRect(orientation: "x" | "y", bandStart: number, bandwidth: number, valuePx: number, baseline: number, origin: MarkOrigin): {
37
+ x: number;
38
+ y: number;
39
+ width: number;
40
+ height: number;
41
+ } | null;
@@ -0,0 +1,74 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Shape-geom helpers — orientation-aware rect math + halo painting
3
+ // ---------------------------------------------------------------------------
4
+ // Shared by bar / histogram / tile. These geoms all compute axis-aligned
5
+ // rects from a band+value+baseline triple and overlay halo rings on the
6
+ // active hover row. The bbox math and the halo paint loop were copy-pasted
7
+ // across files; this module owns both.
8
+
9
+ import type { Color, Layer } from "insomni";
10
+ import type { MarkOrigin } from "../../marks.ts";
11
+
12
+ /**
13
+ * Halo rect to be painted on top of a geom's main fills, so the active
14
+ * hover row's outline isn't occluded by adjacent cells. `color` is per-halo
15
+ * so multi-series geoms (histogram) can use per-cell highlight colors while
16
+ * single-series geoms (tile) just thread one color through every entry.
17
+ */
18
+ export interface Halo {
19
+ x: number;
20
+ y: number;
21
+ w: number;
22
+ h: number;
23
+ color: Color;
24
+ }
25
+
26
+ /**
27
+ * Push every halo rect as a stroke-only outline on top of `layer`. Caller
28
+ * supplies the shared stroke width (typically `emphasis.haloStrokeWidth`)
29
+ * and an optional corner radius matching the underlying fills.
30
+ */
31
+ export function paintHalos(
32
+ layer: Layer,
33
+ halos: readonly Halo[],
34
+ options: { strokeWidth: number; cornerRadius?: number },
35
+ ): void {
36
+ for (const halo of halos) {
37
+ layer.pushRect({
38
+ x: halo.x,
39
+ y: halo.y,
40
+ width: halo.w,
41
+ height: halo.h,
42
+ cornerRadius: options.cornerRadius,
43
+ stroke: halo.color,
44
+ strokeWidth: options.strokeWidth,
45
+ });
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Orientation-aware bar bbox: takes the band-axis start + bandwidth and the
51
+ * value-axis pixel + baseline, returns the axis-aligned rect in mark-local
52
+ * coordinates (pre-translated by `origin`).
53
+ *
54
+ * `orientation === "y"` means categories on the x-axis (vertical bars rising
55
+ * along y); `"x"` means categories on the y-axis (horizontal bars).
56
+ *
57
+ * Returns `null` when either input pixel isn't finite — callers should
58
+ * `continue` on null so NaN bands don't produce zero-area garbage rects.
59
+ */
60
+ export function barRect(
61
+ orientation: "x" | "y",
62
+ bandStart: number,
63
+ bandwidth: number,
64
+ valuePx: number,
65
+ baseline: number,
66
+ origin: MarkOrigin,
67
+ ): { x: number; y: number; width: number; height: number } | null {
68
+ if (!Number.isFinite(bandStart) || !Number.isFinite(valuePx)) return null;
69
+ const x = (origin.x ?? 0) + (orientation === "y" ? bandStart : Math.min(baseline, valuePx));
70
+ const y = (origin.y ?? 0) + (orientation === "y" ? Math.min(baseline, valuePx) : bandStart);
71
+ const width = orientation === "y" ? bandwidth : Math.abs(valuePx - baseline);
72
+ const height = orientation === "y" ? Math.abs(valuePx - baseline) : bandwidth;
73
+ return { x, y, width, height };
74
+ }
@@ -0,0 +1,95 @@
1
+ import { type Color } from "insomni";
2
+ import { type LineCurve, type PointShapeKind } from "../../marks.ts";
3
+ import type { Aes } from "../aes.ts";
4
+ import type { Geom } from "./types.ts";
5
+ export type AggregateBinBy = "x" | "y";
6
+ export type AggregateBinSize = number | "auto" | ((info: AutoBinSizeInfo) => number);
7
+ export interface AutoBinSizeInfo {
8
+ /** Pixel span of the binned axis (positive). */
9
+ pixelSpan: number;
10
+ /** Domain span of the binned axis in axis units (positive). For time scales, ms. */
11
+ domainSpan: number;
12
+ /** `pixelSpan / domainSpan` — pixels per domain unit on the binned axis. */
13
+ pixelsPerUnit: number;
14
+ }
15
+ export type AggregateSummaryKind = "mean" | "median" | "count" | "sum" | "first" | "last";
16
+ export interface AggregateBinView<T> {
17
+ /** Values from the *non-binned* axis, in input order within this bin. */
18
+ values: readonly number[];
19
+ /** Source items inside this bin, in input order. */
20
+ items: readonly T[];
21
+ /** Count after filter. */
22
+ count: number;
23
+ /** Bin's lower edge on the binned axis (inclusive). */
24
+ lo: number;
25
+ /** Bin's upper edge on the binned axis (exclusive, except the final bin). */
26
+ hi: number;
27
+ }
28
+ export type AggregateSummary<T> = AggregateSummaryKind | ((bin: AggregateBinView<T>) => number);
29
+ /** Result of a bundle summary — one center + a [lo, hi] range per bin. */
30
+ export interface AggregateBundleResult {
31
+ center: number;
32
+ lo: number;
33
+ hi: number;
34
+ }
35
+ export type AggregateBundleSummaryKind = "mean+ci" | "median+iqr";
36
+ /**
37
+ * Bundle summaries emit `{ center, lo, hi }` per bin and pair with the
38
+ * `interval` or `ribbon` inner geom. Built-in kinds plus a quantile triple
39
+ * `{ quantiles: [loQ, centerQ, hiQ] }` (e.g. `[0.1, 0.5, 0.9]` for an 80%
40
+ * range) or a custom function returning the bundle directly.
41
+ */
42
+ export type AggregateBundleSummary<T> = AggregateBundleSummaryKind | {
43
+ quantiles: readonly [number, number, number];
44
+ } | ((bin: AggregateBinView<T>) => AggregateBundleResult);
45
+ export interface AggregateChannels<T> {
46
+ x: Aes<T, number | Date>;
47
+ y: Aes<T, number | Date>;
48
+ }
49
+ export type AggregateInnerGeom = "point" | "line" | "bar" | "interval" | "ribbon";
50
+ export interface AggregateOptions<T> {
51
+ /** Axis to slide along. Default `"x"`. */
52
+ binBy?: AggregateBinBy;
53
+ /** Bin width in domain units; `"auto"` targets `~autoTargetPx` px. Default `"auto"`. */
54
+ binSize?: AggregateBinSize;
55
+ /**
56
+ * Reduction applied per bin. Scalar kinds (`"mean"`, `"median"`, …) pair
57
+ * with `geom: "point" | "line" | "bar"`. Bundle kinds (`"mean+ci"`,
58
+ * `"median+iqr"`, `{ quantiles }`, function-returning-`{center, lo, hi}`)
59
+ * pair with `geom: "interval" | "ribbon"`. Default `"mean"`.
60
+ */
61
+ summary?: AggregateSummary<T> | AggregateBundleSummary<T>;
62
+ /** Row predicate. Rejected rows are excluded from both binning and the
63
+ * raw-fallback path. */
64
+ filter?: (datum: T, index: number) => boolean;
65
+ /** When `avg-points-per-bin < dissolveAt`, render raw geom instead.
66
+ * Default `1.2`. */
67
+ dissolveAt?: number;
68
+ /** Inner mark kind. Default `"point"`. */
69
+ geom?: AggregateInnerGeom;
70
+ /** Fill / stroke applied to every emitted mark. */
71
+ fill?: Color;
72
+ stroke?: Color;
73
+ strokeWidth?: number;
74
+ /** Point-specific. */
75
+ radius?: number;
76
+ shape?: PointShapeKind;
77
+ /** Line-specific. */
78
+ curve?: LineCurve;
79
+ /** Target pixels per bin for `"auto"` sizing. Default `7`. */
80
+ autoTargetPx?: number;
81
+ /** Display label for legend / hit-test (forwarded to inner mark). */
82
+ label?: string;
83
+ /**
84
+ * Confidence level for the `"mean+ci"` bundle summary. Default `0.95`.
85
+ * Ignored for other summaries.
86
+ */
87
+ ciLevel?: number;
88
+ /** Interval-specific: render perpendicular caps. Default `true`. */
89
+ caps?: boolean;
90
+ /** Interval-specific: cap length in pixels. Default `6`. */
91
+ capWidth?: number;
92
+ /** Ribbon-specific: fill alpha override (otherwise theme.marks.ribbonFillAlpha). */
93
+ fillAlpha?: number;
94
+ }
95
+ export declare function aggregate<T>(channels: AggregateChannels<T>, options?: AggregateOptions<T>): Geom<T>;