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,29 @@
1
+ import type { Color } from "insomni";
2
+ import { type CategoricalPalette } from "../colors.ts";
3
+ import type { ColorScale } from "./scales.ts";
4
+ import type { Theme, ThemeAccentKey } from "./theme.ts";
5
+ /** Multiply a color's alpha by `a`. Preserves rgb. */
6
+ export declare function alphaize(c: Color, a: number): Color;
7
+ /** Override a color's alpha to `a`. */
8
+ export declare function withAlpha(c: Color, a: number): Color;
9
+ /**
10
+ * Accent-key shorthand used by chart-level marks (`band`, `rule`, `interval`,
11
+ * `ribbon`). Literal {@link Color} values bypass theme resolution; accent
12
+ * keys resolve through `theme.accents`.
13
+ */
14
+ export type ColorOrAccent = Color | ThemeAccentKey;
15
+ export declare function isColor(v: unknown): v is Color;
16
+ export declare function isAccentKey(v: unknown): v is ThemeAccentKey;
17
+ /**
18
+ * Resolve a `Color | ThemeAccentKey | undefined` against the theme's accent
19
+ * palette. Returns `undefined` when the input is undefined; throws on an
20
+ * unknown string so typos surface at construction rather than rendering as
21
+ * silent transparent black.
22
+ */
23
+ export declare function resolveAccent(value: ColorOrAccent | undefined, theme: Theme): Color | undefined;
24
+ /**
25
+ * Resolve a per-series color function: prefer the chart-provided color scale
26
+ * (so auto-legend swatches stay in sync), otherwise fall back to a fresh
27
+ * categorical palette keyed on `fallbackKeys`.
28
+ */
29
+ export declare function seriesColor(scale: ColorScale | undefined, palette: CategoricalPalette, fallbackKeys: readonly string[]): (key: string) => Color;
@@ -0,0 +1,53 @@
1
+ import { rgba } from "insomni";
2
+ import { describe, expect, test } from "vite-plus/test";
3
+
4
+ import { isAccentKey, isColor, resolveAccent } from "./color-utils.ts";
5
+ import { theme, themeDefault } from "./theme.ts";
6
+
7
+ describe("resolveAccent", () => {
8
+ test("returns undefined for undefined input", () => {
9
+ expect(resolveAccent(undefined, themeDefault)).toBeUndefined();
10
+ });
11
+
12
+ test("passes through literal Color values", () => {
13
+ const c = rgba(0.1, 0.2, 0.3, 1);
14
+ expect(resolveAccent(c, themeDefault)).toBe(c);
15
+ });
16
+
17
+ test("resolves each accent key against theme.accents", () => {
18
+ expect(resolveAccent("positive", themeDefault)).toBe(themeDefault.accents.positive);
19
+ expect(resolveAccent("negative", themeDefault)).toBe(themeDefault.accents.negative);
20
+ expect(resolveAccent("warn", themeDefault)).toBe(themeDefault.accents.warn);
21
+ expect(resolveAccent("info", themeDefault)).toBe(themeDefault.accents.info);
22
+ });
23
+
24
+ test("picks up theme overrides", () => {
25
+ const customWarn = rgba(0.5, 0.5, 0.5, 1);
26
+ const t = theme({ accents: { warn: customWarn } });
27
+ // `theme()` deep-merges, so the resolved value is a structural copy, not
28
+ // the same reference as `customWarn`.
29
+ expect(resolveAccent("warn", t)).toEqual(customWarn);
30
+ });
31
+
32
+ test("throws on unknown string", () => {
33
+ expect(() => resolveAccent("good" as never, themeDefault)).toThrow(/unknown accent key/);
34
+ });
35
+ });
36
+
37
+ describe("isColor / isAccentKey", () => {
38
+ test("isColor distinguishes Color from accent string", () => {
39
+ expect(isColor(rgba(0, 0, 0, 1))).toBe(true);
40
+ expect(isColor("positive")).toBe(false);
41
+ expect(isColor(undefined)).toBe(false);
42
+ });
43
+
44
+ test("isAccentKey only matches the four known keys", () => {
45
+ expect(isAccentKey("positive")).toBe(true);
46
+ expect(isAccentKey("negative")).toBe(true);
47
+ expect(isAccentKey("warn")).toBe(true);
48
+ expect(isAccentKey("info")).toBe(true);
49
+ expect(isAccentKey("good")).toBe(false);
50
+ expect(isAccentKey("")).toBe(false);
51
+ expect(isAccentKey(rgba(0, 0, 0, 1))).toBe(false);
52
+ });
53
+ });
@@ -0,0 +1,66 @@
1
+ import type { Color } from "insomni";
2
+ import { colorScale, type CategoricalPalette } from "../colors.ts";
3
+ import type { ColorScale } from "./scales.ts";
4
+ import type { Theme, ThemeAccentKey } from "./theme.ts";
5
+
6
+ /** Multiply a color's alpha by `a`. Preserves rgb. */
7
+ export function alphaize(c: Color, a: number): Color {
8
+ return { r: c.r, g: c.g, b: c.b, a: (c.a ?? 1) * a };
9
+ }
10
+
11
+ /** Override a color's alpha to `a`. */
12
+ export function withAlpha(c: Color, a: number): Color {
13
+ return { r: c.r, g: c.g, b: c.b, a };
14
+ }
15
+
16
+ /**
17
+ * Accent-key shorthand used by chart-level marks (`band`, `rule`, `interval`,
18
+ * `ribbon`). Literal {@link Color} values bypass theme resolution; accent
19
+ * keys resolve through `theme.accents`.
20
+ */
21
+ export type ColorOrAccent = Color | ThemeAccentKey;
22
+
23
+ export function isColor(v: unknown): v is Color {
24
+ return (
25
+ typeof v === "object" &&
26
+ v !== null &&
27
+ typeof (v as { r?: unknown }).r === "number" &&
28
+ typeof (v as { g?: unknown }).g === "number" &&
29
+ typeof (v as { b?: unknown }).b === "number"
30
+ );
31
+ }
32
+
33
+ const ACCENT_KEYS: ReadonlySet<ThemeAccentKey> = new Set(["positive", "negative", "warn", "info"]);
34
+
35
+ export function isAccentKey(v: unknown): v is ThemeAccentKey {
36
+ return typeof v === "string" && ACCENT_KEYS.has(v as ThemeAccentKey);
37
+ }
38
+
39
+ /**
40
+ * Resolve a `Color | ThemeAccentKey | undefined` against the theme's accent
41
+ * palette. Returns `undefined` when the input is undefined; throws on an
42
+ * unknown string so typos surface at construction rather than rendering as
43
+ * silent transparent black.
44
+ */
45
+ export function resolveAccent(value: ColorOrAccent | undefined, theme: Theme): Color | undefined {
46
+ if (value === undefined) return undefined;
47
+ if (isColor(value)) return value;
48
+ if (isAccentKey(value)) return theme.accents[value];
49
+ throw new Error(
50
+ `resolveAccent: unknown accent key "${String(value)}" — expected positive | negative | warn | info, or a Color.`,
51
+ );
52
+ }
53
+
54
+ /**
55
+ * Resolve a per-series color function: prefer the chart-provided color scale
56
+ * (so auto-legend swatches stay in sync), otherwise fall back to a fresh
57
+ * categorical palette keyed on `fallbackKeys`.
58
+ */
59
+ export function seriesColor(
60
+ scale: ColorScale | undefined,
61
+ palette: CategoricalPalette,
62
+ fallbackKeys: readonly string[],
63
+ ): (key: string) => Color {
64
+ if (scale) return (key: string) => scale.fn(key);
65
+ return colorScale(palette, fallbackKeys);
66
+ }
@@ -0,0 +1,45 @@
1
+ import type { DataPanBoundsOptions } from "../viewport.ts";
2
+ export declare const DEFAULT_CHART_WIDTH = 800;
3
+ export declare const DEFAULT_CHART_HEIGHT = 500;
4
+ export declare const DEFAULT_PADDING = 16;
5
+ export declare const DEFAULT_TICK_COUNT = 5;
6
+ export declare const DEFAULT_ATLAS_SIZE = 1024;
7
+ /** Default pan-bounds when panZoom is enabled without explicit bounds. */
8
+ export declare const DEFAULT_PAN_BOUNDS: DataPanBoundsOptions;
9
+ /** Half-padding fraction applied around the visible-Y extent when yFit is enabled. */
10
+ export declare const DEFAULT_Y_FIT_PADDING = 0.05;
11
+ /** Confidence-interval level used by aggregate/smooth when none is supplied. */
12
+ export declare const DEFAULT_CI_LEVEL = 0.95;
13
+ /** Default secondary-glyph scale relative to the base point in overlay geoms. */
14
+ export declare const DEFAULT_OVERLAY_SCALE = 0.6;
15
+ /** Facet layout defaults: gap between panels and strip dimensions. */
16
+ export declare const DEFAULT_FACET_GAP = 12;
17
+ export declare const DEFAULT_FACET_STRIP_HEIGHT = 22;
18
+ export declare const DEFAULT_FACET_STRIP_FONT_SIZE = 11;
19
+ /**
20
+ * Per-bucket sample-count threshold below which boxplot/violin geoms switch
21
+ * from the summary mark to drawing each raw point. Keeps tiny groups from
22
+ * showing a misleading shape built from <10 samples.
23
+ */
24
+ export declare const DEFAULT_POINTS_THRESHOLD = 10;
25
+ /**
26
+ * Default ridgeline ridge overlap as a multiple of one row's cell size.
27
+ * `2.5` lets each ridge rise 2.5 cells above its baseline before the next
28
+ * ridge sits on top.
29
+ */
30
+ export declare const DEFAULT_OVERLAP = 2.5;
31
+ /** Pixel gaps between layout regions inside `computeLayout`. */
32
+ export declare const LAYOUT_GAP: {
33
+ /** Gap above the plot frame after title/legend reservation. */
34
+ readonly topReservation: 16;
35
+ /** Right margin inside the outer frame. */
36
+ readonly plotRight: 4;
37
+ /** Pixels between axis edge and plot frame. */
38
+ readonly axisToPlot: 4;
39
+ /** Pixels between title block and legend (when both present). */
40
+ readonly titleToLegend: 4;
41
+ /** Pixels between title and subtitle within title block. */
42
+ readonly subtitleGap: 8;
43
+ /** Pixels reserved below legend before plot frame. */
44
+ readonly legendToPlot: 12;
45
+ };
@@ -0,0 +1,61 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Grammar-layer constants
3
+ // ---------------------------------------------------------------------------
4
+ // Sizes and spacings used by the chart pipeline that are NOT theme-able. Theme
5
+ // covers visual appearance (fonts, colors, alphas); this file covers structural
6
+ // layout numbers and pipeline defaults.
7
+
8
+ import type { DataPanBoundsOptions } from "../viewport.ts";
9
+
10
+ export const DEFAULT_CHART_WIDTH = 800;
11
+ export const DEFAULT_CHART_HEIGHT = 500;
12
+ export const DEFAULT_PADDING = 16;
13
+ export const DEFAULT_TICK_COUNT = 5;
14
+ export const DEFAULT_ATLAS_SIZE = 1024;
15
+
16
+ /** Default pan-bounds when panZoom is enabled without explicit bounds. */
17
+ export const DEFAULT_PAN_BOUNDS: DataPanBoundsOptions = { overshoot: 0.1 };
18
+
19
+ /** Half-padding fraction applied around the visible-Y extent when yFit is enabled. */
20
+ export const DEFAULT_Y_FIT_PADDING = 0.05;
21
+
22
+ /** Confidence-interval level used by aggregate/smooth when none is supplied. */
23
+ export const DEFAULT_CI_LEVEL = 0.95;
24
+
25
+ /** Default secondary-glyph scale relative to the base point in overlay geoms. */
26
+ export const DEFAULT_OVERLAY_SCALE = 0.6;
27
+
28
+ /** Facet layout defaults: gap between panels and strip dimensions. */
29
+ export const DEFAULT_FACET_GAP = 12;
30
+ export const DEFAULT_FACET_STRIP_HEIGHT = 22;
31
+ export const DEFAULT_FACET_STRIP_FONT_SIZE = 11;
32
+
33
+ /**
34
+ * Per-bucket sample-count threshold below which boxplot/violin geoms switch
35
+ * from the summary mark to drawing each raw point. Keeps tiny groups from
36
+ * showing a misleading shape built from <10 samples.
37
+ */
38
+ export const DEFAULT_POINTS_THRESHOLD = 10;
39
+
40
+ /**
41
+ * Default ridgeline ridge overlap as a multiple of one row's cell size.
42
+ * `2.5` lets each ridge rise 2.5 cells above its baseline before the next
43
+ * ridge sits on top.
44
+ */
45
+ export const DEFAULT_OVERLAP = 2.5;
46
+
47
+ /** Pixel gaps between layout regions inside `computeLayout`. */
48
+ export const LAYOUT_GAP = {
49
+ /** Gap above the plot frame after title/legend reservation. */
50
+ topReservation: 16,
51
+ /** Right margin inside the outer frame. */
52
+ plotRight: 4,
53
+ /** Pixels between axis edge and plot frame. */
54
+ axisToPlot: 4,
55
+ /** Pixels between title block and legend (when both present). */
56
+ titleToLegend: 4,
57
+ /** Pixels between title and subtitle within title block. */
58
+ subtitleGap: 8,
59
+ /** Pixels reserved below legend before plot frame. */
60
+ legendToPlot: 12,
61
+ } as const;
@@ -0,0 +1,183 @@
1
+ import { type GlyphAtlas, type Layer } from "insomni";
2
+ import { type AxisOptions } from "../axis.ts";
3
+ import type { ScaleBundle } from "./geoms/types.ts";
4
+ export interface Point {
5
+ x: number;
6
+ y: number;
7
+ }
8
+ /**
9
+ * Inputs to `Coord.renderAxes`. The pipeline owns scale construction and
10
+ * layout; the coord owns axis dispatch (Cartesian → bottom + left; polar →
11
+ * angular ring + radial spokes).
12
+ */
13
+ export interface CoordAxesArgs {
14
+ axisLayer: Layer;
15
+ scales: ScaleBundle;
16
+ /** Inner plot frame — coords project relative to this. */
17
+ plotFrame: import("insomni").Frame;
18
+ /** True when the chart actually has a column on this channel. Skipped axes are not drawn. */
19
+ hasX: boolean;
20
+ hasY: boolean;
21
+ xAxisOptions: AxisOptions<unknown>;
22
+ yAxisOptions: AxisOptions<unknown>;
23
+ atlas: GlyphAtlas | undefined;
24
+ }
25
+ /**
26
+ * Inputs to `Coord.handlePan`. The mount / interactions layer passes a pointer
27
+ * delta in plot-frame pixels plus the active plot frame and a viewport handle
28
+ * the coord can use to mutate scale state. Cartesian delegates the whole
29
+ * thing to `viewport.panBy(dx, dy)`; polar decomposes into tangential
30
+ * (rotate `startAngle`) and radial (translate radius domain via the viewport).
31
+ */
32
+ export interface CoordPanArgs {
33
+ dx: number;
34
+ dy: number;
35
+ /** Plot frame in absolute layer-pixel space (x, y are screen-space origin). */
36
+ plotFrame: import("insomni").Frame;
37
+ /** Viewport handle for scale-domain mutations. */
38
+ viewport: CoordViewportHandle;
39
+ }
40
+ export interface CoordZoomArgs {
41
+ /**
42
+ * Multiplicative zoom factor — `> 1` zooms in, `< 1` zooms out. May be a
43
+ * scalar (both axes) or a `{ x?, y? }` per-axis form (matches
44
+ * `viewport.zoomAt` and the masking that `bindDataViewport` performs).
45
+ */
46
+ factor: number | {
47
+ x?: number;
48
+ y?: number;
49
+ };
50
+ /** Cursor position in absolute layer-pixel space (matches `viewport.zoomAt`). */
51
+ cx: number;
52
+ cy: number;
53
+ plotFrame: import("insomni").Frame;
54
+ viewport: CoordViewportHandle;
55
+ }
56
+ /**
57
+ * Minimal facade over `DataViewport` so the coord can mutate scale state
58
+ * without depending on the full viewport surface. The two methods polar
59
+ * uses (`panBy`, `zoomAt`) match `DataViewport` semantics 1:1; Cartesian's
60
+ * implementation forwards through them so behavior is byte-identical to the
61
+ * pre-`handlePan` path.
62
+ */
63
+ export interface CoordViewportHandle {
64
+ panBy(dxPx: number, dyPx: number): void;
65
+ zoomAt(anchorSx: number, anchorSy: number, factor: number | {
66
+ x?: number;
67
+ y?: number;
68
+ }): void;
69
+ }
70
+ /**
71
+ * A coordinate system. Polar / cartesian today; future room for log-polar /
72
+ * geographic projections behind the same interface.
73
+ */
74
+ export interface Coord {
75
+ readonly kind: "cartesian" | "polar";
76
+ /**
77
+ * Bind the coord to a specific plot frame for the upcoming render.
78
+ * Polar's `project` / `segment` / `renderAxes` need the plot-frame
79
+ * dimensions and centre to compute (cx, cy) and the default outerRadius.
80
+ * Called by the pipeline once per panel (faceted) or once per chart
81
+ * (unfaceted) before any `project` / `renderAxes` call. Cartesian no-ops.
82
+ */
83
+ bindFrame(plotFrame: import("insomni").Frame): void;
84
+ /**
85
+ * Map a single point from plot-frame pixel space (0..plotFrame.width on x,
86
+ * 0..plotFrame.height on y — i.e. the raw output of `xScale.fn` / `yScale.fn`)
87
+ * to layer-pixel space (still relative to the plot frame's origin —
88
+ * `plot.topLeft` offsets are applied later by each geom).
89
+ *
90
+ * Cartesian: identity. Polar: (θ, r) → (cx + r·cosθ, cy + r·sinθ).
91
+ */
92
+ project(p: Point): Point;
93
+ /**
94
+ * Tessellate a polyline segment between two points in plot-frame pixel
95
+ * space. Returns the projected pixel points (including both endpoints).
96
+ * Cartesian returns `[project(p1), project(p2)]`; polar returns ~N points
97
+ * along the arc.
98
+ */
99
+ segment(p1: Point, p2: Point): Point[];
100
+ /**
101
+ * Render axes into `args.axisLayer`. Cartesian draws bottom (x) + left (y);
102
+ * polar draws an angular ring (spokes) + radial concentric circles.
103
+ */
104
+ renderAxes(args: CoordAxesArgs): void;
105
+ /**
106
+ * Inverse of `project`, for hit-testing / tooltips. Cartesian is the
107
+ * identity within the plot frame. Polar inverts (θ, r) and returns `null`
108
+ * when the projected point is outside `[innerRadius, outerRadius]`.
109
+ */
110
+ unproject(p: Point): Point | null;
111
+ /**
112
+ * Translate a pointer pan delta into scale-domain mutations.
113
+ * Cartesian forwards to `viewport.panBy(dx, dy)` — byte-identical to the
114
+ * pre-coord path. Polar decomposes the delta relative to the plot centre
115
+ * into tangential (rotate `startAngle`) and radial (translate the radius
116
+ * scale via `viewport.panBy(0, radial_dy)`) components.
117
+ */
118
+ handlePan(args: CoordPanArgs): void;
119
+ /**
120
+ * Translate a zoom factor + anchor into scale-domain mutations.
121
+ * Cartesian forwards to `viewport.zoomAt(cx, cy, factor)`. Polar scales the
122
+ * radius domain around the cursor's data-space radius; angle scale
123
+ * unchanged.
124
+ */
125
+ handleZoom(args: CoordZoomArgs): void;
126
+ }
127
+ /**
128
+ * Default coord — identity projection, current axis behavior. Plot's existing
129
+ * pipeline behaves exactly as it did before the `Coord` interface was added
130
+ * when this is in use.
131
+ */
132
+ export declare function coordCartesian(): Coord;
133
+ export interface CoordPolarOptions {
134
+ /** Angle (radians) where the angular axis starts. Default `-π/2` (top). */
135
+ startAngle?: number;
136
+ /** Angle where the angular axis ends. Default `startAngle + 2π` (full circle). */
137
+ endAngle?: number;
138
+ /**
139
+ * Convenience for non-full-circle layouts: the gap (in radians) between
140
+ * `startAngle` and `endAngle`. `openAngle: 0` ↔ full circle;
141
+ * `openAngle: π/4` ↔ fan with a 45° gap at the start. Ignored when
142
+ * `endAngle` is provided.
143
+ */
144
+ openAngle?: number;
145
+ /** `1` (default, CCW) or `-1` (CW). */
146
+ direction?: 1 | -1;
147
+ /** Inner radius in pixels. Default `0`. */
148
+ innerRadius?: number;
149
+ /**
150
+ * Outer radius in pixels. Default `min(plotFrame.width, plotFrame.height) / 2`
151
+ * — resolved lazily on `bindFrame`.
152
+ */
153
+ outerRadius?: number;
154
+ /** Which channel maps to θ. Default `'y'` (gheatmap/circular-tree convention). */
155
+ angleChannel?: "x" | "y";
156
+ /** Angular tessellation step (radians) for `segment` and circular axes. Default ~1°. */
157
+ quality?: number;
158
+ }
159
+ /**
160
+ * Polar projection. See {@link CoordPolarOptions}.
161
+ *
162
+ * Each call returns a fresh stateful coord so the same `coordPolar({...})`
163
+ * expression can be reused safely. `bindFrame` mutates the centre and the
164
+ * default `outerRadius`.
165
+ */
166
+ export declare function coordPolar(opts?: CoordPolarOptions): Coord;
167
+ /**
168
+ * Convenience polar coord: full circle, root at centre. Equivalent to
169
+ * `coordPolar({ openAngle: 0, innerRadius: 0 })`.
170
+ */
171
+ export declare function coordRadial(opts?: Omit<CoordPolarOptions, "openAngle" | "innerRadius">): Coord;
172
+ /**
173
+ * Pin a coord to one plot frame (faceted panels). The facet loop mutates a
174
+ * SINGLE shared stateful coord via `bindFrame(panel.frame)` per panel; that's
175
+ * fine for the synchronous mark-push path (compiled right after the bind), but
176
+ * a geom's `hoverDecoration` closure captures `ctx.coord` and runs LATER (at
177
+ * hover, from the mount) — by then the shared coord is bound to the LAST
178
+ * panel's frame, so a polar halo would project against the wrong centre. This
179
+ * wrapper re-binds the underlying coord to THIS panel's frame before every
180
+ * frame-dependent delegate, so each panel's closures see a panel-stable
181
+ * projection. Cartesian's `bindFrame` is a no-op so this is zero-cost there.
182
+ */
183
+ export declare function frameBoundCoord(coord: Coord, frame: import("insomni").Frame): Coord;