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,952 @@
1
+ import type { Color, Frame, FrameTiming, GlyphAtlas, Invalidator, Layer, Padding, Renderer2D } from "insomni";
2
+ import type { AxisTickFormatter, TickSpec } from "../axis.ts";
3
+ import type { AnnotationSpec } from "./annotations.ts";
4
+ import { type Coord } from "./coord.ts";
5
+ import type { FacetSpec } from "./facet.ts";
6
+ import type { Geom } from "./geoms/index.ts";
7
+ import type { HoveredHit } from "./geoms/types.ts";
8
+ import type { AlphaScaleOptions, Channel, ColorScaleOptions, PositionScaleOptions, ShapeScaleOptions, SizeScaleOptions } from "./scales.ts";
9
+ import type { Signal } from "insomni/reactivity";
10
+ import { type Theme } from "./theme.ts";
11
+ export type Row = Record<string, unknown>;
12
+ export interface PlotSpec<T> {
13
+ data: readonly T[] | Signal<readonly T[]>;
14
+ width?: number;
15
+ height?: number;
16
+ background?: Color;
17
+ padding?: Padding;
18
+ /**
19
+ * Inner padding inside the plot frame, in pixels. Adds slack between the
20
+ * axis lines and the data — as if the view were zoomed out a bit. Accepts a
21
+ * single number applied to all sides, or per-side overrides. Different from
22
+ * `padding`, which is the *outer* canvas inset before axes/legend/title.
23
+ */
24
+ framePadding?: number | {
25
+ top?: number;
26
+ right?: number;
27
+ bottom?: number;
28
+ left?: number;
29
+ };
30
+ device?: GPUDevice;
31
+ /** Initial theme; can be replaced via `.theme(...)`. */
32
+ theme?: Theme;
33
+ }
34
+ /**
35
+ * Per-axis options surfaced through `chart.axes({ ... })`. `title` accepts
36
+ * either a string or `{ text, maxWidth }`; `label.maxWidth` clips long tick
37
+ * labels with an ellipsis.
38
+ */
39
+ export type { AxisTickFormatter } from "../axis.ts";
40
+ export interface AxisSpec {
41
+ title?: string | {
42
+ text: string;
43
+ maxWidth?: number;
44
+ };
45
+ format?: AxisTickFormatter;
46
+ /**
47
+ * How many ticks to render:
48
+ * - `number` — target count (default 5).
49
+ * - `"auto"` — pick the count from the axis's pixel span (~80px/tick
50
+ * horizontal, ~50px/tick vertical). Useful for time-series so dense
51
+ * per-day ticks decay to weeks / months / quarters as the view widens.
52
+ * - `{ interval, step? }` — explicit time interval (time scales only).
53
+ * `interval: "quarter"` is sugar for `month, step: 3`.
54
+ */
55
+ ticks?: TickSpec;
56
+ gridLines?: boolean;
57
+ /** Draw the axis line itself (the spine along the plot frame). Default `true`. */
58
+ axisLine?: boolean;
59
+ label?: {
60
+ maxWidth?: number;
61
+ };
62
+ /**
63
+ * Auto-decimate tick labels until they no longer visually overlap.
64
+ * `"auto"` measures the formatted labels and inflates the effective
65
+ * `labelStep` accordingly. Useful for dense band axes (≥15 categories)
66
+ * and time axes whose density shifts under zoom. Default off — opt in
67
+ * per axis.
68
+ */
69
+ labelCollision?: "auto";
70
+ }
71
+ export interface AxesSpec {
72
+ x?: AxisSpec;
73
+ y?: AxisSpec;
74
+ }
75
+ /**
76
+ * Chart title / subtitle. Each accepts a string or `{ text, maxWidth }` —
77
+ * the object form clips with an ellipsis when the rendered text exceeds the
78
+ * given pixel width.
79
+ */
80
+ export interface TitleSpec {
81
+ title?: string | {
82
+ text: string;
83
+ maxWidth?: number;
84
+ };
85
+ subtitle?: string | {
86
+ text: string;
87
+ maxWidth?: number;
88
+ };
89
+ }
90
+ /**
91
+ * Float-over-plot position. `x` and `y` are normalized to the plot frame
92
+ * (`0..1`); `justify` controls which corner of the legend's bbox lands on
93
+ * that point. Inspired by ggplot2's `legend.position = c(x, y)`.
94
+ */
95
+ export interface LegendInsidePosition {
96
+ inside: {
97
+ x: number;
98
+ y: number;
99
+ };
100
+ /** Default `"start"` — top-left of legend lands on the point. */
101
+ justify?: {
102
+ x?: "start" | "center" | "end";
103
+ y?: "start" | "center" | "end";
104
+ };
105
+ }
106
+ export type LegendPosition = "top" | "right" | "bottom" | "left" | LegendInsidePosition;
107
+ /**
108
+ * Channels eligible for being merged into a single legend entry. When merged,
109
+ * each domain value's swatch shows the resolved value from every listed scale
110
+ * — e.g. `merge: ["color", "shape"]` produces one row per category whose
111
+ * swatch is colored by the color scale AND shaped by the shape scale.
112
+ *
113
+ * `size` participation is supported only when another categorical channel is
114
+ * also in the merge list (the entries are still iterated over the categorical
115
+ * domain; size is sampled from its numeric range at evenly-spaced positions).
116
+ */
117
+ export type LegendMergeChannel = "color" | "shape" | "size" | "borderStyle" | "overlayGlyph";
118
+ export interface LegendSpec {
119
+ /** Disable the auto-legend. */
120
+ show?: boolean;
121
+ /**
122
+ * Where the legend sits. Outer slots: `"top" | "right" | "bottom" | "left"`.
123
+ * For an over-plot legend, pass `{ inside: { x, y } }` with `x`/`y` in `0..1`
124
+ * (plot-frame coords). Default depends on legend type — `"right"` for
125
+ * continuous color bars, `"top"` for categorical swatches.
126
+ */
127
+ position?: LegendPosition;
128
+ /** Optional title rendered above the legend entries / color bar. */
129
+ title?: string;
130
+ /** Override color-bar long-axis pixel length. Default 160. */
131
+ length?: number;
132
+ /** Override color-bar thickness. Default 12. */
133
+ thickness?: number;
134
+ /** Continuous legend — major tick count target. Default `5`. */
135
+ ticks?: number;
136
+ /** Continuous legend — explicit major tick values (override `ticks`). */
137
+ tickValues?: readonly number[];
138
+ /**
139
+ * Continuous legend — minor (unlabeled) tick marks. Number subdivides each
140
+ * major interval (`2` = one minor halfway); array places ticks explicitly.
141
+ */
142
+ minorTicks?: number | readonly number[];
143
+ /**
144
+ * Continuous legend — render a tick label every `N`th major tick.
145
+ * Default `1`. Combine with `minorTicks` for "lines every 0.5, labels
146
+ * every 1.0" style guides.
147
+ */
148
+ labelStep?: number;
149
+ /** Continuous legend — tick label formatter. */
150
+ format?: (value: number) => string;
151
+ /**
152
+ * Continuous legend — override the color space used to interpolate the
153
+ * palette stops for the bar's gradient. Falls back to the chart's color
154
+ * scale (which itself defaults to `theme.paletteBlendSpace = "oklch"`).
155
+ */
156
+ blendSpace?: import("insomni").BlendSpace;
157
+ /**
158
+ * Merge the listed aesthetic channels into a single combined legend. When
159
+ * provided, every listed channel must encode the same field (the consumer
160
+ * is asserting this) and the merged legend iterates the primary scale's
161
+ * domain (priority: color → shape → borderStyle → overlayGlyph). Each
162
+ * entry's swatch combines the resolved values across every listed scale.
163
+ *
164
+ * Channels that are listed but have no active scale on the chart are
165
+ * silently skipped — they contribute nothing to the swatch. Omitting this
166
+ * option leaves the default behavior unchanged (color-only legend).
167
+ */
168
+ merge?: readonly LegendMergeChannel[];
169
+ }
170
+ export type ScaleOptionsByChannel<C extends Channel> = C extends "x" | "y" ? PositionScaleOptions : C extends "color" ? ColorScaleOptions<unknown> : C extends "size" ? SizeScaleOptions : C extends "alpha" ? AlphaScaleOptions : C extends "shape" ? ShapeScaleOptions : never;
171
+ export interface TransitionsConfig {
172
+ /** Duration in milliseconds. Default: theme.motion.data duration (240ms). */
173
+ duration?: number;
174
+ /** Stable key for matching rows across data refreshes. Required for enter animations. */
175
+ key?: (datum: unknown, index: number) => string | number;
176
+ }
177
+ /** Handle exposed on MountedPlot to request manual transitions. */
178
+ export interface TransitionsHandle {
179
+ /** Trigger a transition on the next draw (e.g. after a scale domain change). */
180
+ requestTransition(): void;
181
+ }
182
+ export interface MountPlotOptions<T> {
183
+ /**
184
+ * GPU device. Required when the mount has to create a `Renderer2D` or
185
+ * `GlyphAtlas` (i.e. when you don't pass them yourself). Either source
186
+ * works — `plot({ device })` or `mount(canvas, { device })`.
187
+ */
188
+ device?: GPUDevice;
189
+ /**
190
+ * Builder closure called on every `invalidate()`. Use this when chart
191
+ * settings live in module-scope state (controls, signals, etc.) and you
192
+ * want the chart to be re-derived on each draw. The closure should return
193
+ * a fresh `Chart<T>` (typically by calling the same `plot().layer()...`
194
+ * chain that produced this chart).
195
+ *
196
+ * If omitted, the mount renders the chart you mounted on, statically.
197
+ * Either way, `handle.update(newChart | newBuilder)` swaps it.
198
+ */
199
+ build?: () => Chart<T>;
200
+ /**
201
+ * Use an externally owned renderer. The mount won't call `setBackground`,
202
+ * `resize`, `setDpr`, or `destroy()` on it — those become the caller's
203
+ * responsibility. Useful for sharing a single renderer across multiple
204
+ * charts or compositing a chart over a world-space scene.
205
+ */
206
+ renderer?: Renderer2D;
207
+ /**
208
+ * External layers (axis under, marks middle, hud over). Mount won't clear
209
+ * them outside the pipeline. The optional `overlay` layer sits on top of the
210
+ * hud and carries the cursor-driven overlays (tooltip / crosshair / brush /
211
+ * menu); omit it and the mount creates its own.
212
+ */
213
+ layers?: {
214
+ axis: Layer;
215
+ marks: Layer;
216
+ hud: Layer;
217
+ overlay?: Layer;
218
+ };
219
+ /**
220
+ * Extra layers rendered alongside the chart's own layers. Called each draw
221
+ * to read the current list, so callers can lazy-create or swap layers
222
+ * without re-mounting. Layers returned here are NOT cleared by the chart
223
+ * pipeline — they persist across draws until the caller clears them
224
+ * themselves. Use this for retained, world-anchored content (large label
225
+ * sets that ride the camera, scatter overlays driven by a separate camera
226
+ * viewport, etc.) where per-frame re-emission would dominate CPU cost.
227
+ *
228
+ * Two slots:
229
+ * - `belowMarks`: rendered after axes, before chart marks. Behind data.
230
+ * - `aboveMarks`: rendered after chart marks, before the HUD. Above
231
+ * data but below tooltips / brushes / interactive overlays.
232
+ */
233
+ extraLayers?: () => {
234
+ belowMarks?: readonly Layer[];
235
+ aboveMarks?: readonly Layer[];
236
+ };
237
+ /** Fixed width (CSS px). When set with `height`, disables auto-resize by default. */
238
+ width?: number;
239
+ /** Fixed height (CSS px). When set with `width`, disables auto-resize by default. */
240
+ height?: number;
241
+ /** Override DPR. Default: `window.devicePixelRatio`. */
242
+ dpr?: number;
243
+ /** Track canvas size via `ResizeObserver`. Default: `true` unless `width` and `height` are both set. */
244
+ autoResize?: boolean;
245
+ /** Run an internal `requestAnimationFrame` loop. Default `true`. Set false to call `update()` from your own loop. */
246
+ autoFrame?: boolean;
247
+ /** Pause draws while `document.hidden`. Default `true`. */
248
+ pauseOnHidden?: boolean;
249
+ /** Background override. Falls back to `chart.background` then `theme.background`. */
250
+ background?: Color;
251
+ /** Per-frame CPU/GPU timing callback. Forwarded to the underlying `Renderer2D`. */
252
+ onFrameTiming?: (t: FrameTiming) => void;
253
+ /** Enable detailed GPU pipeline-level profiling. Forwarded to the underlying `Renderer2D`. */
254
+ enablePipelineProfiling?: boolean;
255
+ /**
256
+ * Default interactions wired into the chart. Pass `false` to disable all of
257
+ * them. Pass `true` (or omit) to enable the defaults: a hover tooltip on
258
+ * geoms that support hit-testing (`point` / `bar` / `line` / `area`) plus a
259
+ * snapping crosshair on continuous x-scale charts. Pass an object to enable
260
+ * a subset and tune options.
261
+ */
262
+ interactions?: boolean | InteractionsConfig;
263
+ /**
264
+ * Animated transitions when data or chart config changes. On by default
265
+ * (inherits `theme.motion.data` duration and easing). Pass `false` to disable.
266
+ */
267
+ transitions?: boolean | TransitionsConfig;
268
+ /**
269
+ * Wire up pan/zoom on the chart's x/y scales. Off by default. Pass `true`
270
+ * to enable with default zoom limits, or an object to override.
271
+ *
272
+ * Behavior when enabled:
273
+ * - The mount creates a `DataViewport` seeded from the chart's x/y scale
274
+ * domain options (the values you passed to `.scale("x", { domain })`).
275
+ * - Pointer events on the canvas pan/zoom the viewport.
276
+ * - The viewport's visible domains are written back into the chart's x/y
277
+ * scale options on every draw, so axes/ticks update automatically.
278
+ * - The viewport is exposed on `MountedPlot.viewport` for read-only
279
+ * introspection (e.g. a `build:` closure that re-bins data into the
280
+ * visible domain).
281
+ *
282
+ * Requires both x and y scales to be continuous (linear / log / sqrt /
283
+ * time). Throws if either scale is missing a numeric/date domain.
284
+ */
285
+ panZoom?: boolean | PanZoomConfig;
286
+ /**
287
+ * Clip marks to the inner plot panel rect. Default `true`. When on, the
288
+ * mount sets `marksLayer.setClipRect(plotFrame)` after each pipeline run
289
+ * so geom rects/lines/etc. don't bleed into axis / legend / title slots.
290
+ */
291
+ clipMarks?: boolean;
292
+ /**
293
+ * Damage-tracked partial redraw. On by default — set `false` to opt out,
294
+ * which renders byte-identically to the classic full-frame path.
295
+ *
296
+ * When on (and the mount owns its renderer), the renderer is given a
297
+ * persistent backbuffer and the static marks are baked to a texture, so
298
+ * cursor-driven overlays (tooltip / crosshair / brush / menu) repaint only
299
+ * their own damage rect instead of clearing + re-compiling the whole chart
300
+ * on every pointer move. View-changing events (data, pan/zoom, resize,
301
+ * selection, legend toggle, transitions) still run a full frame and re-bake.
302
+ *
303
+ * Silently ignored when an external `renderer` or `layers` is supplied (the
304
+ * mount can't reconfigure pieces it doesn't own); only an *explicit*
305
+ * `partialRedraw: true` in that situation logs a one-time warning.
306
+ */
307
+ partialRedraw?: boolean;
308
+ }
309
+ /**
310
+ * Per-axis pan / zoom enable. Either axis can be silenced independently.
311
+ * Sugar: `true` ≡ `"xy"`, `false` ≡ `"none"`.
312
+ */
313
+ export type PanZoomAxes = "x" | "y" | "xy" | "none";
314
+ /**
315
+ * Pan-bound margins, expressed as fractions of the visible span. A bare
316
+ * number applies to both axes. See `DataPanBoundsOptions` for the full
317
+ * `{ overshoot, drift }` shape inherited from the viewport.
318
+ */
319
+ export type ChartPanBounds = ChartPanBoundsOptions | false;
320
+ export interface ChartPanBoundsOptions {
321
+ /** Pan-past-content allowance when zoomed in (content > viewport). */
322
+ overshoot?: number | {
323
+ x?: number;
324
+ y?: number;
325
+ };
326
+ /** Drift allowance when zoomed out (content ≤ viewport). */
327
+ drift?: number | {
328
+ x?: number;
329
+ y?: number;
330
+ };
331
+ }
332
+ export interface PanZoomConfig {
333
+ /**
334
+ * Minimum zoom factor relative to the chart's base domain. `1` means the
335
+ * user cannot zoom *out* past the data extent — a sensible chart default.
336
+ * Smaller values (e.g. `0.1`) allow zooming out into empty space.
337
+ *
338
+ * Default `1` (zoom-out clamped to the data extent).
339
+ */
340
+ minZoom?: number;
341
+ /**
342
+ * Maximum zoom factor relative to the chart's base domain. `100` lets the
343
+ * user zoom in to 1% of the data range — usually a sane floor before axis
344
+ * ticks and labels collapse.
345
+ *
346
+ * Default `100`.
347
+ */
348
+ maxZoom?: number;
349
+ /**
350
+ * Pan-bound the visible domain to the chart's base (data) domain. When
351
+ * zoomed in, panning stops at content edges plus an `overshoot` margin;
352
+ * when zoomed out far enough that content fits in view, the viewport can
353
+ * still drift by `drift × visibleSpan`.
354
+ *
355
+ * Default `{ overshoot: 0.1 }` (the user can rubber-band 10% past the
356
+ * data edges but can't drag the chart fully off-screen). Pass `false`
357
+ * to opt out entirely.
358
+ */
359
+ panBounds?: ChartPanBounds;
360
+ /**
361
+ * Lock pan to a subset of axes. Default `"xy"` (both axes pan).
362
+ */
363
+ pan?: PanZoomAxes;
364
+ /**
365
+ * Lock zoom to a subset of axes. Default `"xy"` (both axes zoom).
366
+ */
367
+ zoom?: PanZoomAxes;
368
+ /**
369
+ * When set, the Y scale's domain is recomputed every frame from whatever
370
+ * data is currently visible along X (financial-chart "auto-Y" behavior).
371
+ * Implies `pan: "x"` and `zoom: "x"` — Y becomes read-only.
372
+ *
373
+ * `true` uses the default 5% padding around the visible Y extent; pass
374
+ * `{ padding }` to override (0..0.5).
375
+ *
376
+ * The Y scale must still declare an explicit `domain` (used as a fallback
377
+ * when no data is visible in the current X window).
378
+ */
379
+ yFit?: boolean | {
380
+ padding?: number;
381
+ };
382
+ }
383
+ export interface InteractionsConfig {
384
+ tooltip?: boolean | TooltipConfig;
385
+ /**
386
+ * Hover crosshair (guide line). Default: enabled on charts whose x-scale
387
+ * is continuous (`linear` / `log` / `sqrt` / `time`); auto-disabled on
388
+ * band x-scales. Pass `false` to disable, `true` for defaults, or an
389
+ * object to tune. Snaps to the same hit positions the tooltip uses.
390
+ */
391
+ crosshair?: boolean | CrosshairConfig;
392
+ /**
393
+ * Click-to-select. Off by default — selection has app-level semantics so
394
+ * the chart shouldn't claim it silently. Pass `true` to enable defaults
395
+ * (plain click replaces, shift toggles, meta/ctrl removes, click-empty
396
+ * clears) or an object to tune. The active selection is exposed on
397
+ * `MountedPlot.selected` and surfaces to geoms via `CompileContext.selected`
398
+ * — selected rows get a stroke ring and unselected rows dim while a
399
+ * selection is active.
400
+ */
401
+ selection?: boolean | SelectionConfig;
402
+ /**
403
+ * Drag-to-rect brush. Off by default — like click-selection, brush semantics
404
+ * are app-specific. Pass `true` to enable defaults (xy rect, dismiss on
405
+ * background tap) or an object to tune. The active brushed rows are exposed
406
+ * on `MountedPlot.brushed`. Brush populates a separate signal from
407
+ * click-selection so the two coexist with different semantics (range query
408
+ * vs. discrete pick).
409
+ */
410
+ brush?: boolean | BrushConfig;
411
+ /**
412
+ * Legend interactivity. Default: enabled when `interactions` is on.
413
+ * Enables click-to-toggle visibility of categorical series.
414
+ */
415
+ legend?: boolean | LegendInteractionConfig;
416
+ /**
417
+ * Context-menu trigger. Off by default — requires an `onTrigger` handler so
418
+ * the host app can render its own menu UI. Fires for right-click, touch
419
+ * long-press (≥500ms), and the keyboard ContextMenu / Shift+F10 keys. The
420
+ * library only emits the event; menu rendering / positioning stays the
421
+ * consumer's responsibility.
422
+ */
423
+ contextMenu?: ContextMenuConfig;
424
+ }
425
+ export interface ContextMenuConfig {
426
+ /**
427
+ * Resolution policy for the trigger point. Default `"nearest-point"`.
428
+ *
429
+ * - `"nearest-point"`: snap to the nearest mark within its `pickRadius`
430
+ * (skips region-based geoms like bars). When no mark is within range, the
431
+ * trigger is **suppressed entirely** — matches the behavior of the hover
432
+ * tooltip / crosshair (no popup unless something would be highlighted).
433
+ * - `"any-mark"`: include region-based geoms (bars, histograms, tiles).
434
+ * Same suppression behavior as `"nearest-point"` when no mark is hit.
435
+ * - `"background"`: never resolve — `hit`/`datum`/`mark` are always null,
436
+ * and the trigger always fires. Useful for "add a point here" menus.
437
+ */
438
+ hitMode?: "nearest-point" | "any-mark" | "background";
439
+ /** Touch long-press hold duration (ms). Default `500`. */
440
+ holdMs?: number;
441
+ /** Max pointer movement during long-press hold (CSS px). Default `5`. */
442
+ slopPx?: number;
443
+ /**
444
+ * Menu items. Static array or a per-trigger resolver. When provided, the
445
+ * library renders a GPU-drawn menu inside the canvas (no DOM, no host
446
+ * popover required) and routes clicks through `onAction`. When omitted the
447
+ * library only emits `onTrigger` and rendering is the consumer's problem.
448
+ */
449
+ items?: readonly ContextMenuItem[] | ((info: ContextMenuTriggerPayload) => readonly ContextMenuItem[]);
450
+ /** Called when an item in the rendered menu is clicked. */
451
+ onAction?(itemId: string, info: ContextMenuTriggerPayload): void;
452
+ /** Placement of the rendered menu relative to the trigger point. */
453
+ placement?: import("insomni").MenuPlacement;
454
+ /** Style overrides for the rendered menu. */
455
+ style?: import("insomni").MenuStyle;
456
+ /**
457
+ * Low-level trigger callback. Fires even when `items` is set, so consumers
458
+ * can hook telemetry / aria-live announcements alongside the rendered menu.
459
+ * Required only when `items` is omitted (otherwise the library has no idea
460
+ * what menu to show).
461
+ */
462
+ onTrigger?(info: ContextMenuTriggerPayload): void;
463
+ }
464
+ export interface ContextMenuItem {
465
+ /** Stable id passed to `onAction`. Ignored for separators. */
466
+ id: string;
467
+ /** Display label. Ignored for separators. */
468
+ label: string;
469
+ /** Renders as a thin separator line; non-interactive. */
470
+ separator?: boolean;
471
+ /** Greyed out; ignored by hover/click. */
472
+ disabled?: boolean;
473
+ /** Tinted with the menu's `dangerColor` (destructive actions). */
474
+ danger?: boolean;
475
+ /** Optional swatch dot at the start of the row. */
476
+ swatch?: Color;
477
+ /** Optional right-aligned shortcut hint (e.g. "⌘D"). */
478
+ kbd?: string;
479
+ }
480
+ export interface ContextMenuTriggerPayload {
481
+ /**
482
+ * Resolved hit at the trigger point, or `null` for a background trigger /
483
+ * `hitMode: "background"`.
484
+ */
485
+ hit: HoveredHit | null;
486
+ /** Convenience: the data row at `hit.dataIndex`, or `null` for background. */
487
+ datum: unknown | null;
488
+ /** Convenience: the geom kind that produced the hit. */
489
+ mark: HoveredHit["geomKind"] | null;
490
+ /** Element-local CSS px where the menu should anchor. */
491
+ screenX: number;
492
+ screenY: number;
493
+ source: "mouse" | "touch" | "pen" | "keyboard";
494
+ mods: import("insomni").Mods;
495
+ originalEvent: Event | null;
496
+ }
497
+ export interface LegendInteractionConfig {
498
+ /** Default `0.2` — alpha for hidden series labels/swatches. */
499
+ dimAlpha?: number;
500
+ }
501
+ /**
502
+ * Semantic accents for `TooltipShorthandRow.accent`. `positive` / `negative`
503
+ * resolve through `theme.interactions.tooltipAccents`. `neutral` is a
504
+ * no-op marker — the row uses the default text color. Passing a raw `Color`
505
+ * bypasses theme tokens entirely.
506
+ */
507
+ export type TooltipAccent = "positive" | "negative" | "neutral" | Color;
508
+ export interface TooltipShorthandRow {
509
+ label?: string;
510
+ /**
511
+ * Row value. Numbers / Dates / null / undefined are formatted through the
512
+ * library's default formatter; strings are emitted verbatim.
513
+ */
514
+ value: string | number | Date | boolean | null | undefined;
515
+ /** Optional swatch dot to the left of the row. */
516
+ swatch?: Color;
517
+ /**
518
+ * Semantic accent applied to the row's text color (positive/negative tint
519
+ * for diffs, deltas, status changes). `neutral` is a no-op.
520
+ */
521
+ accent?: TooltipAccent;
522
+ }
523
+ /**
524
+ * Shorthand object form of `TooltipContent`. The grammar normalizes this into
525
+ * the canvas-tooltip's full `TooltipContent` shape, applying default
526
+ * formatting to non-string values and resolving accents through the theme.
527
+ */
528
+ export interface TooltipContentShorthand {
529
+ title?: string;
530
+ rows: readonly TooltipShorthandRow[];
531
+ }
532
+ export interface TooltipContentInfo<T = unknown> {
533
+ /** The hovered datum (the row from the geom's data array). */
534
+ datum: T;
535
+ /** Index into the data array. */
536
+ dataIndex: number;
537
+ /** Geom kind (e.g. `"point"`, `"bar"`, `"line"`). */
538
+ mark: string;
539
+ /** Series key when the geom emits multiple segments per row (stacks, dodges). */
540
+ seriesKey?: string;
541
+ /**
542
+ * Resolved aesthetic accessors for the geom. Useful for advanced resolvers
543
+ * that need to read a channel's raw value or column name — most consumers
544
+ * can ignore this and just read fields off `datum`.
545
+ */
546
+ channels: Readonly<Record<string, unknown>>;
547
+ }
548
+ /**
549
+ * Override the auto-built tooltip content. Receives the hovered datum and
550
+ * returns either the canvas-tooltip's full `TooltipContent` (with
551
+ * `swatch`/`color`/`fontSize` per row), the shorthand `{ title, rows }` form
552
+ * with optional `accent` tokens, or a plain string (single-row body), or
553
+ * `null` to fall back to the default channel-driven content.
554
+ */
555
+ export type TooltipContentResolver<T = unknown> = (info: TooltipContentInfo<T>) => TooltipContentResult | null | undefined;
556
+ export type TooltipContentResult = TooltipContentShorthand | string;
557
+ /** One auto-built series row in axis-mode tooltips (mirrors SeriesReadoutRow). */
558
+ export interface AxisTooltipRow {
559
+ /** Series label (color-channel value, seriesKey, or layer label). */
560
+ label: string;
561
+ /** Formatted value at the snapped column. */
562
+ value: string;
563
+ /** Raw value at the snapped column (pre-format) for custom transforms. */
564
+ rawValue: unknown;
565
+ /** Series swatch color, when resolvable. */
566
+ color?: Color;
567
+ /** True for the row whose snapped position is closest to the cursor. */
568
+ active: boolean;
569
+ /** seriesKey when the row came from a stacked / dodged segment. */
570
+ seriesKey?: string;
571
+ }
572
+ /** Info handed to the axis-mode tooltip content hook. */
573
+ export interface AxisTooltipInfo {
574
+ /** Raw snapped column value (the X for `axis:"x"`, the Y for `axis:"y"`). */
575
+ columnValue: unknown;
576
+ /** Formatted column value (`axisTitleFormat` / `defaultFormat`). */
577
+ columnLabel: string;
578
+ /** Which screen axis we snapped on. */
579
+ axis: "x" | "y";
580
+ /** Auto-built series rows (one per series at the snapped column). */
581
+ rows: readonly AxisTooltipRow[];
582
+ /**
583
+ * The snapped datum(s) — one entry per hit-testable layer that produced a
584
+ * group at this column, in layer order. Each carries the source datum, its
585
+ * data index, and the layer's mark label, so a consumer can read any field
586
+ * off a wide row (incl. fields belonging to ribbon/band/text layers that
587
+ * have no hit tests of their own). For wide rows, `data[0].datum` already
588
+ * holds every column.
589
+ */
590
+ data: readonly {
591
+ datum: unknown;
592
+ dataIndex: number;
593
+ mark: string;
594
+ }[];
595
+ }
596
+ /**
597
+ * Axis-mode tooltip content hook. Return a `{ title?, rows }` shorthand (the
598
+ * same shape the item resolver returns) to REPLACE the auto rows, or
599
+ * `null` / `undefined` to keep them verbatim. `accent` / `swatch` per row
600
+ * resolve through the theme exactly like the item path.
601
+ */
602
+ export type AxisTooltipContentResolver = (info: AxisTooltipInfo) => TooltipContentShorthand | null | undefined;
603
+ export interface TooltipConfig {
604
+ showDelay?: number;
605
+ hideDelay?: number;
606
+ fadeMs?: number;
607
+ placement?: "top" | "bottom" | "left" | "right" | "auto";
608
+ /**
609
+ * Override the default channel-driven tooltip body. Receives the hovered
610
+ * datum and returns either:
611
+ * - a plain string (single-row body, no label)
612
+ * - a `{ title?, rows: [{label?, value, accent?, swatch?}] }` shorthand —
613
+ * `accent: "positive" | "negative" | "neutral" | Color` tints the row
614
+ * text via `theme.interactions.tooltipAccents`
615
+ * - `null` / `undefined` to fall back to the auto-built content
616
+ *
617
+ * The library renders the canvas tooltip primitive — there's no HTML/CSS
618
+ * surface to style; row colors come from the theme.
619
+ *
620
+ * Ignored in `trigger:"axis"` mode (use `axisContent`).
621
+ */
622
+ content?: TooltipContentResolver;
623
+ /**
624
+ * Tooltip trigger model. Default `"item"` (today's behavior — one box per
625
+ * hovered mark, fully backward compatible). `"axis"` turns the tooltip into
626
+ * a floating, cursor-following unified readout: it snaps to the nearest data
627
+ * column across ALL hit-testable layers and lists one row per series in a
628
+ * single box.
629
+ */
630
+ trigger?: "item" | "axis";
631
+ /**
632
+ * Which screen axis to snap on in `trigger:"axis"` mode. `"x"` (default) =
633
+ * nearest-X (vertical time-series — pick the column under the cursor's x).
634
+ * `"y"` = nearest-Y (horizontal charts — pick the row under the cursor's y).
635
+ * Ignored when `trigger:"item"`.
636
+ */
637
+ axis?: "x" | "y";
638
+ /**
639
+ * Axis-mode content hook. Receives the snapped column plus the auto-built
640
+ * series rows AND the snapped datum(s), so a consumer can append rows that
641
+ * are NOT y-series (a wind-direction arrow, a day/night flag, a UV risk
642
+ * band) or transform the auto rows. Return value REPLACES the auto rows when
643
+ * non-null; return null/undefined to keep the auto-built rows verbatim.
644
+ * Ignored unless `trigger:"axis"`.
645
+ */
646
+ axisContent?: AxisTooltipContentResolver;
647
+ /** Format the snapped column value used as the tooltip title in axis mode. */
648
+ axisTitleFormat?: (value: unknown) => string;
649
+ /** Format each auto-built series row's value in axis mode. */
650
+ axisValueFormat?: (value: unknown) => string;
651
+ }
652
+ export interface CrosshairConfig {
653
+ /** Which guide line(s) to draw. Default `"x"` (vertical line tracking cursor). */
654
+ axis?: "x" | "y" | "xy";
655
+ /** Stroke color. Default theme.colors.muted at 0.6 alpha. */
656
+ color?: Color;
657
+ /** Stroke width in CSS px. Default 1. */
658
+ width?: number;
659
+ /**
660
+ * Track the raw pointer position even between data points (no snap). Useful
661
+ * for sparse line/area charts where the snapped-to-hit default leaves big
662
+ * gaps. Snapping still wins when the cursor is over a hit; outside hits the
663
+ * crosshair follows the cursor within the plot frame. Default `false`.
664
+ */
665
+ followPointer?: boolean;
666
+ }
667
+ export interface BrushConfig {
668
+ /** Which axes the brush spans. Default `"xy"`. */
669
+ axis?: "x" | "y" | "xy";
670
+ /** Translucent fill. Default theme axis color × 0.12 alpha. */
671
+ fillColor?: Color;
672
+ /** Outline color. Default theme axis color × 0.6 alpha. */
673
+ strokeColor?: Color;
674
+ /** Outline width in CSS px. Default 1. */
675
+ strokeWidth?: number;
676
+ /** Enable edge/corner resize handles. Default `true`. */
677
+ handles?: boolean;
678
+ /** Enable drag-the-rect-interior translate. Default `true`. */
679
+ translate?: boolean;
680
+ /**
681
+ * Snap brush rect edges to nearest hit-test position. `true` snaps on the
682
+ * brush's `axis`; pass `"x"` / `"y"` / `"xy"` to override. Default `false`.
683
+ */
684
+ snap?: boolean | "x" | "y" | "xy";
685
+ }
686
+ /**
687
+ * Read-only view of a `Signal<HoveredHit[]>` exposed on `MountedPlot.brushed`.
688
+ * Empty array when nothing is brushed; remains an empty array (never `null`)
689
+ * when brush is disabled. Independent of `selected` — click + brush coexist
690
+ * with different semantics.
691
+ */
692
+ export interface BrushedSignal {
693
+ get(): readonly HoveredHit[];
694
+ peek(): readonly HoveredHit[];
695
+ subscribe(fn: (v: readonly HoveredHit[]) => void): () => void;
696
+ /** Imperatively clear the active brush. */
697
+ clear(): void;
698
+ }
699
+ export interface SelectionConfig {
700
+ /**
701
+ * Alpha applied to non-selected marks while a selection is active. Default
702
+ * `0.3`. Set `1` to disable dimming (selected rows still get a stroke ring).
703
+ */
704
+ dimAlpha?: number;
705
+ /** Stroke ring color override; defaults to theme.axis.color. */
706
+ ringColor?: Color;
707
+ /** Stroke ring width in CSS px. Default 2. */
708
+ ringWidth?: number;
709
+ }
710
+ /**
711
+ * Read-only view of a `Signal<HoveredHit[]>` exposed on `MountedPlot`. The
712
+ * array is empty when nothing is selected; `null` is never produced (use
713
+ * `length === 0` to detect the empty case).
714
+ */
715
+ export interface SelectedSignal {
716
+ get(): readonly HoveredHit[];
717
+ peek(): readonly HoveredHit[];
718
+ subscribe(fn: (v: readonly HoveredHit[]) => void): () => void;
719
+ /** Imperatively clear the active selection. */
720
+ clear(): void;
721
+ }
722
+ /**
723
+ * Read-only view of a `Signal<ReadonlySet<string>>` exposed on `MountedPlot.hidden`.
724
+ * Empty set when all series are visible.
725
+ */
726
+ export interface HiddenSignal {
727
+ get(): ReadonlySet<string>;
728
+ peek(): ReadonlySet<string>;
729
+ subscribe(fn: (v: ReadonlySet<string>) => void): () => void;
730
+ /** Clear the hidden set (show all). */
731
+ clear(): void;
732
+ }
733
+ /**
734
+ * Read-only view of a `Signal<HoveredHit | null>` exposed on `MountedPlot`.
735
+ * Drops `set`/`update` so callers can subscribe + peek without writing.
736
+ */
737
+ export interface HoveredSignal {
738
+ get(): HoveredHit | null;
739
+ peek(): HoveredHit | null;
740
+ subscribe(fn: (v: HoveredHit | null) => void): () => void;
741
+ }
742
+ export interface MountedPlot<T> {
743
+ /** Schedule a redraw on the next animation frame. */
744
+ invalidate(): void;
745
+ /**
746
+ * Replace the active chart spec or builder.
747
+ * - Pass a `Chart<T>` to swap to a static spec.
748
+ * - Pass `() => Chart<T>` to swap the rebuild closure.
749
+ * - Pass nothing to force a rebuild via the existing builder.
750
+ *
751
+ * When `autoFrame: false`, also draws synchronously.
752
+ */
753
+ update(source?: Chart<T> | (() => Chart<T>)): void;
754
+ /** Replace the data array (drops any reactive data signal subscription). */
755
+ setData(data: readonly T[]): void;
756
+ /**
757
+ * Manual resize. If `autoResize` is on you usually don't need this.
758
+ * Pass no args to re-read the canvas's current bounding rect.
759
+ */
760
+ resize(w?: number, h?: number): void;
761
+ /** Override the background color. Pass `null` to revert to the chart/theme default. */
762
+ setBackground(color: Color | null): void;
763
+ /** Static SVG export from the current spec + data. */
764
+ toSVG(opts?: {
765
+ width?: number;
766
+ height?: number;
767
+ atlas?: GlyphAtlas;
768
+ }): SVGSVGElement;
769
+ /** Tear down: cancels the rAF loop, ResizeObserver, signal subs; destroys what we created. */
770
+ destroy(): void;
771
+ readonly renderer: Renderer2D;
772
+ readonly axisLayer: Layer;
773
+ readonly marksLayer: Layer;
774
+ readonly hudLayer: Layer;
775
+ /** Cursor-overlay layer (tooltip / crosshair / brush / menu), above the hud. */
776
+ readonly overlayLayer: Layer;
777
+ readonly invalidator: Invalidator;
778
+ /**
779
+ * Read-only signal carrying the currently hovered hit (geom kind, dataIndex,
780
+ * data array reference, snapped position) or `null` when nothing is
781
+ * hovered. Updated synchronously from pointer events. Geoms also receive
782
+ * the same value via `CompileContext.hovered` during compile.
783
+ */
784
+ readonly hovered: HoveredSignal;
785
+ /**
786
+ * Read-only signal carrying the currently selected rows (one `HoveredHit`
787
+ * per selected datum). Empty array when nothing is selected; remains an
788
+ * empty array (never `null`) when selection is disabled. Geoms receive
789
+ * the same payload via `CompileContext.selected` during compile.
790
+ */
791
+ readonly selected: SelectedSignal;
792
+ /**
793
+ * Read-only signal carrying the rows currently inside the brush rect.
794
+ * Empty array when nothing is brushed (or when brush is disabled).
795
+ * Independent of `selected`.
796
+ */
797
+ readonly brushed: BrushedSignal;
798
+ /**
799
+ * Read-only signal carrying the set of series keys currently hidden via
800
+ * legend toggle. Empty set when all series are visible; remains an empty
801
+ * set (never `null`) when legend interaction is disabled.
802
+ */
803
+ readonly hidden: HiddenSignal;
804
+ /**
805
+ * Handle for programmatic transition control. Always present even when
806
+ * transitions are disabled (calls become no-ops in that case).
807
+ */
808
+ readonly transitions: TransitionsHandle;
809
+ /** CSS-pixel width currently rendered. */
810
+ readonly width: number;
811
+ /** CSS-pixel height currently rendered. */
812
+ readonly height: number;
813
+ /** Active device-pixel ratio. */
814
+ readonly dpr: number;
815
+ /** Combined shape count across the three internal layers. */
816
+ readonly shapeCount: number;
817
+ /** Combined triangle count across the three internal layers. */
818
+ readonly triangleCount: number;
819
+ /** True when `invalidate()` has been called and a draw hasn't happened yet. */
820
+ readonly needsFrame: boolean;
821
+ /**
822
+ * Inner plot panel rect (absolute element-CSS px) — the area enclosed by
823
+ * the axes, where geom marks draw. Updated each frame from the pipeline.
824
+ * For faceted charts this is the union of all panel frames. Returns a
825
+ * zero-rect before the first draw.
826
+ */
827
+ readonly plotFrame: Frame;
828
+ /**
829
+ * The chart's pan/zoom viewport, present only when `panZoom` was enabled
830
+ * on mount. Lets the caller subscribe to view changes, read the visible
831
+ * domain (e.g. for re-binning data), or call `.reset()`. The mount keeps
832
+ * its frame in sync with `plotFrame` automatically.
833
+ */
834
+ readonly viewport: import("../viewport.ts").DataViewport<number, number> | null;
835
+ /**
836
+ * Wire a `createRangePresets` controller against this chart's viewport and
837
+ * optionally render a chip strip into a host element. Throws if `panZoom`
838
+ * was not enabled at mount time (no `viewport` to drive).
839
+ *
840
+ * The headless flow is preserved — omit `opts.ui` and you get the same
841
+ * controller (`setActive` / `getActive` / `subscribe`) without any DOM
842
+ * construction. Strings in `presets` are expanded to `timePreset(key)`.
843
+ */
844
+ attachRangePresets(opts: import("./attach-presets.ts").AttachRangePresetsOptions): import("./attach-presets.ts").AttachedRangePresets;
845
+ /**
846
+ * Attach a dygraph-style pinned legend — a side panel that updates with each
847
+ * series' value at the cursor's snapped x. Reuses the chart's compiled
848
+ * hit-tests (no separate spatial index) so the snap stays aligned with what
849
+ * the tooltip would have shown.
850
+ *
851
+ * Headless: omit `opts.ui` and observe via `subscribe()` to render your own
852
+ * UI. With `opts.ui` set, a minimal absolute-positioned panel is appended
853
+ * into the mount element and disposed alongside this readout.
854
+ */
855
+ attachSeriesReadout(opts: import("./interactions/series-readout.ts").AttachSeriesReadoutOptions): import("./interactions/series-readout.ts").AttachedSeriesReadout;
856
+ /**
857
+ * Wire a drag-to-rect brush onto the chart imperatively. Mirrors the
858
+ * declarative `interactions: { brush: ... }` config path — the same
859
+ * `MountedPlot.brushed` signal observes the brushed set — but lets a
860
+ * consumer attach (and later dispose) a brush after mount without
861
+ * rebuilding the chart spec.
862
+ *
863
+ * Throws if a brush is already configured on this mount, either via
864
+ * `interactions.brush` or a prior `attachBrush` call that hasn't been
865
+ * disposed. The two surfaces are mutually exclusive: the brush rect is a
866
+ * singleton.
867
+ */
868
+ attachBrush(opts: import("./attach-brush.ts").AttachBrushOptions): import("./attach-brush.ts").AttachedBrush;
869
+ /**
870
+ * Convert an event-relative canvas coordinate (e.g. `event.offsetX/Y`, or
871
+ * `clientX - rect.left`) into the chart's data space, routing through the
872
+ * active coord's `unproject` (identity for Cartesian, polar inverse for
873
+ * `coordPolar` / `coordRadial`).
874
+ *
875
+ * Returns `null` when:
876
+ * - the point falls outside the active plot frame, or
877
+ * - `coord.unproject` returns null (e.g. polar point outside the radius
878
+ * band), or
879
+ * - the pipeline has not produced scales yet (no draw has happened), or
880
+ * - either position scale lacks an `invert` (band scales).
881
+ *
882
+ * `dataX` / `dataY` are the result of `xScale.axisScale.invert(plotFrameX)`
883
+ * and `yScale.axisScale.invert(plotFrameY)` respectively. `plotFrameX/Y` are
884
+ * relative to the plot frame's top-left.
885
+ *
886
+ * This is the screen → data primitive consumers use to drive picking on top
887
+ * of their own spatial index. The mount doesn't know what's in the chart —
888
+ * downstream layers (phylo's `hitTestPhylo`, custom geoms, etc.) take it
889
+ * from here.
890
+ */
891
+ pickAt(canvasX: number, canvasY: number): {
892
+ plotFrameX: number;
893
+ plotFrameY: number;
894
+ dataX: number;
895
+ dataY: number;
896
+ frame: Frame;
897
+ } | null;
898
+ }
899
+ /** @deprecated kept for back-compat; use `MountedPlot<T>`. */
900
+ export type MountedChart<T = Row> = MountedPlot<T>;
901
+ export interface RenderTarget {
902
+ axisLayer: Layer;
903
+ marksLayer: Layer;
904
+ hudLayer: Layer;
905
+ width?: number;
906
+ height?: number;
907
+ }
908
+ export interface Chart<T> {
909
+ layer(geom: Geom<T>): Chart<T>;
910
+ layers(geoms: readonly Geom<T>[]): Chart<T>;
911
+ /**
912
+ * Configure a scale. `domain` is always optional — when omitted it is
913
+ * inferred from the data, and when `panZoom` is enabled on `.mount()` the
914
+ * pipeline overrides the x/y position-scale domain each frame from the
915
+ * viewport's visible window. Consumers should NOT re-thread the viewport's
916
+ * visible domain back through `.scale()` from a `build:` closure; it's
917
+ * redundant and forces a rebuild on every dirty draw.
918
+ */
919
+ scale<C extends Channel>(channel: C, options: ScaleOptionsByChannel<C>): Chart<T>;
920
+ axes(spec: AxesSpec): Chart<T>;
921
+ title(spec: TitleSpec | string): Chart<T>;
922
+ legend(spec: LegendSpec | false): Chart<T>;
923
+ /** Add a free-form text/box annotation. Multiple calls accumulate. */
924
+ annotate(spec: AnnotationSpec): Chart<T>;
925
+ /** Split data into a grid of panels by `spec.by`. Replaces any prior facet. */
926
+ facet(spec: FacetSpec<T>): Chart<T>;
927
+ /**
928
+ * Set the coordinate system. Defaults to `coordCartesian()`. Polar / radial
929
+ * coords land in Phase 3 of the phylo-on-plot rewrite.
930
+ */
931
+ coord(coord: Coord): Chart<T>;
932
+ theme(theme: Theme): Chart<T>;
933
+ /**
934
+ * Bind this chart to a canvas. The mount owns the renderer, atlas, three
935
+ * layers, rAF loop, ResizeObserver and visibility-pause unless you pass
936
+ * your own pieces in `opts`. See `MountPlotOptions` for every escape hatch.
937
+ */
938
+ mount(canvas: HTMLCanvasElement, opts?: MountPlotOptions<T>): MountedPlot<T>;
939
+ /**
940
+ * Compile + emit into externally owned layers. Use when the host already
941
+ * owns a `Renderer2D` (and wants its own per-frame timing). For simpler
942
+ * cases, prefer `mount(canvas)`.
943
+ */
944
+ render(target: RenderTarget): void;
945
+ /** Static SVG export. Caller mounts the returned element where they want. */
946
+ toSVG(options?: {
947
+ width?: number;
948
+ height?: number;
949
+ atlas?: GlyphAtlas;
950
+ }): SVGSVGElement;
951
+ }
952
+ export declare function plot<T>(spec: PlotSpec<T>): Chart<T>;