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,57 @@
1
+ import { type Color } from "insomni";
2
+ import { type PointBorderStyle, type PointShapeKind } from "../../marks.ts";
3
+ import type { Aes } from "../aes.ts";
4
+ import type { Geom } from "./types.ts";
5
+ export interface PointChannels<T> {
6
+ x: Aes<T, number | Date>;
7
+ y: Aes<T, number | Date>;
8
+ color?: Aes<T, unknown>;
9
+ size?: Aes<T, number>;
10
+ /**
11
+ * Categorical shape mapping. Values are looked up in the active shape scale
12
+ * — by default a built-in palette (`POINT_SHAPE_PALETTE`). Pass a literal
13
+ * `PointShapeKind` accessor and `.scale("shape", { palette: [...] })` to
14
+ * customize. When the value is already a `PointShapeKind`, it's used as-is.
15
+ */
16
+ shape?: Aes<T, unknown>;
17
+ alpha?: Aes<T, number>;
18
+ /**
19
+ * Per-datum border treatment. The accessor may return either a resolved
20
+ * {@link PointBorderStyle} (used as-is) or any other categorical value that
21
+ * gets routed through the active `borderStyle` scale (default palette:
22
+ * `solid`, `open`, `dashed`, `dotted`). Configure a custom mapping with
23
+ * `.scale("borderStyle", { palette: [...] })`.
24
+ */
25
+ borderStyle?: Aes<T, unknown>;
26
+ /**
27
+ * Optional secondary glyph overlaid on the base shape at the same anchor.
28
+ * Accepts either a resolved {@link PointShapeKind}/`null`, or a categorical
29
+ * value routed through the `overlayGlyph` scale (default palette starts
30
+ * with `null` so the most-common category gets no overlay). Configure with
31
+ * `.scale("overlayGlyph", { palette: [...] })`.
32
+ */
33
+ overlayGlyph?: Aes<T, unknown>;
34
+ /** Overlay radius as a fraction of base radius. Default `0.6`. */
35
+ overlayScale?: Aes<T, number>;
36
+ }
37
+ export interface PointOptions {
38
+ /** Constant fill if color channel is absent. */
39
+ fill?: Color;
40
+ /** Constant point radius if size channel is absent. */
41
+ radius?: number;
42
+ /** Override theme stroke. */
43
+ stroke?: Color | null;
44
+ /** Override theme stroke width. */
45
+ strokeWidth?: number;
46
+ /** Constant shape if shape channel is absent. */
47
+ shape?: PointShapeKind;
48
+ /** Constant border style if border-style channel is absent. */
49
+ borderStyle?: PointBorderStyle;
50
+ /** Constant overlay glyph if overlay-glyph channel is absent. */
51
+ overlayGlyph?: PointShapeKind | null;
52
+ /** Constant overlay scale if overlay-scale channel is absent. */
53
+ overlayScale?: number;
54
+ /** Display label for legend (defaults to color column name). */
55
+ label?: string;
56
+ }
57
+ export declare function point<T>(channels: PointChannels<T>, options?: PointOptions): Geom<T>;
@@ -0,0 +1,163 @@
1
+ import { createFrame } from "insomni";
2
+ import { describe, expect, test } from "vite-plus/test";
3
+
4
+ import { resolveAes } from "../aes.ts";
5
+ import { buildPositionScale, type ScaleBundle } from "../scales.ts";
6
+ import { themeDefault } from "../theme.ts";
7
+ import { point } from "./point.ts";
8
+ import type { CompileContext } from "./types.ts";
9
+
10
+ interface Row {
11
+ x: number;
12
+ y: number;
13
+ category: string;
14
+ }
15
+
16
+ const data: Row[] = [
17
+ { x: 0, y: 0, category: "a" },
18
+ { x: 5, y: 10, category: "b" },
19
+ { x: 10, y: 20, category: "a" },
20
+ ];
21
+
22
+ function makeCtx(rows: readonly Row[]): CompileContext<Row> {
23
+ const xAes = resolveAes<Row, unknown>("x");
24
+ const yAes = resolveAes<Row, unknown>("y");
25
+ const xScale = buildPositionScale(xAes, rows, [0, 100]);
26
+ const yScale = buildPositionScale(yAes, rows, [200, 0]);
27
+ const scales: ScaleBundle = { x: xScale, y: yScale };
28
+ return {
29
+ data: rows,
30
+ scales,
31
+ plot: createFrame({ x: 50, y: 30, width: 100, height: 200 }),
32
+ theme: themeDefault,
33
+ atlas: undefined,
34
+ };
35
+ }
36
+
37
+ function makeCtxWithDomains(
38
+ rows: readonly Row[],
39
+ xDomain: [number, number],
40
+ yDomain: [number, number],
41
+ ): CompileContext<Row> {
42
+ const xAes = resolveAes<Row, unknown>("x");
43
+ const yAes = resolveAes<Row, unknown>("y");
44
+ const xScale = buildPositionScale(xAes, rows, [0, 100], { domain: xDomain });
45
+ const yScale = buildPositionScale(yAes, rows, [200, 0], { domain: yDomain });
46
+ const scales: ScaleBundle = { x: xScale, y: yScale };
47
+ return {
48
+ data: rows,
49
+ scales,
50
+ plot: createFrame({ x: 50, y: 30, width: 100, height: 200 }),
51
+ theme: themeDefault,
52
+ atlas: undefined,
53
+ };
54
+ }
55
+
56
+ function fakeCircleLayer(): {
57
+ circles: Array<{ cx: number; cy: number; radius: number }>;
58
+ layer: { pushCircle: (shape: { cx: number; cy: number; radius: number }) => void };
59
+ } {
60
+ const circles: Array<{ cx: number; cy: number; radius: number }> = [];
61
+ return {
62
+ circles,
63
+ layer: {
64
+ pushCircle(shape) {
65
+ circles.push(shape);
66
+ },
67
+ },
68
+ };
69
+ }
70
+
71
+ describe("point geom — compileHitTest", () => {
72
+ test("emits absolute element-CSS-px positions per datum", () => {
73
+ const geom = point<Row>({ x: "x", y: "y" });
74
+ const hits = geom.compileHitTest!(makeCtx(data));
75
+ expect(hits).not.toBeNull();
76
+ expect(hits!.geomKind).toBe("point");
77
+ expect(hits!.dataIndex.length).toBe(3);
78
+ // x=0 maps to xScale start (0), so absolute = plot.x + 0 = 50
79
+ expect(hits!.positions[0]).toBeCloseTo(50, 3);
80
+ // y=0 maps to yScale start = 200, absolute = plot.y + 200 = 230
81
+ expect(hits!.positions[1]).toBeCloseTo(230, 3);
82
+ // x=10 maps to xScale end = 100, absolute = 50 + 100 = 150
83
+ expect(hits!.positions[4]).toBeCloseTo(150, 3);
84
+ // y=20 maps to yScale end = 0, absolute = 30 + 0 = 30
85
+ expect(hits!.positions[5]).toBeCloseTo(30, 3);
86
+ });
87
+
88
+ test("dataIndex maps each hit back to original data index (preserves order with all-finite data)", () => {
89
+ const geom = point<Row>({ x: "x", y: "y" });
90
+ const hits = geom.compileHitTest!(makeCtx(data))!;
91
+ expect(Array.from(hits.dataIndex)).toEqual([0, 1, 2]);
92
+ });
93
+
94
+ test("filters non-finite positions", () => {
95
+ const dirty: Row[] = [
96
+ { x: 0, y: 0, category: "a" },
97
+ { x: NaN, y: 5, category: "b" },
98
+ { x: 10, y: 20, category: "a" },
99
+ ];
100
+ const geom = point<Row>({ x: "x", y: "y" });
101
+ const hits = geom.compileHitTest!(makeCtx(dirty))!;
102
+ expect(hits.dataIndex.length).toBe(2);
103
+ expect(Array.from(hits.dataIndex)).toEqual([0, 2]);
104
+ });
105
+
106
+ test("captures resolved channels with column metadata for tooltip labels", () => {
107
+ const geom = point<Row>({ x: "x", y: "y", color: "category" });
108
+ const hits = geom.compileHitTest!(makeCtx(data))!;
109
+ expect(hits.channels.x?.kind).toBe("column");
110
+ expect(hits.channels.x?.column).toBe("x");
111
+ expect(hits.channels.color?.kind).toBe("column");
112
+ expect(hits.channels.color?.column).toBe("category");
113
+ });
114
+
115
+ test("returns null for empty data", () => {
116
+ const geom = point<Row>({ x: "x", y: "y" });
117
+ const hits = geom.compileHitTest!(makeCtx([]));
118
+ expect(hits).toBeNull();
119
+ });
120
+
121
+ test("pickRadius scales with theme.marks.pointRadius and grows with size channel", () => {
122
+ const geom = point<Row>({ x: "x", y: "y" });
123
+ const hits = geom.compileHitTest!(makeCtx(data))!;
124
+ expect(hits.pickRadius).toBeGreaterThanOrEqual(8);
125
+ });
126
+
127
+ test("compile path still produces marks (compileHitTest is non-destructive)", () => {
128
+ const geom = point<Row>({ x: "x", y: "y" });
129
+ const ctx = makeCtx(data);
130
+ const builders = geom.compile(ctx);
131
+ expect(builders.length).toBeGreaterThan(0);
132
+ });
133
+
134
+ test("compile uses transitionKey to match reordered rows", () => {
135
+ const geom = point<Row>({ x: "x", y: "y" });
136
+ const fromRows: Row[] = [
137
+ { x: 0, y: 0, category: "a" },
138
+ { x: 20, y: 20, category: "b" },
139
+ ];
140
+ const toRows: Row[] = [
141
+ { x: 10, y: 20, category: "b" },
142
+ { x: 20, y: 0, category: "a" },
143
+ ];
144
+ const from = geom.captureFrame!({
145
+ ...makeCtxWithDomains(fromRows, [0, 20], [0, 20]),
146
+ transitionKey: (d) => d.category,
147
+ })!;
148
+ const builders = geom.compile({
149
+ ...makeCtxWithDomains(toRows, [0, 20], [0, 20]),
150
+ transitionKey: (d) => d.category,
151
+ activeTransition: {
152
+ t: 0.5,
153
+ from,
154
+ matchIndex: (key) => from.ids?.indexOf(key),
155
+ },
156
+ });
157
+ const { circles, layer } = fakeCircleLayer();
158
+ for (const builder of builders) builder.addTo(layer as never);
159
+ expect(circles).toHaveLength(2);
160
+ expect(circles[0]!.cx).toBeCloseTo(125, 3);
161
+ expect(circles[1]!.cx).toBeCloseTo(100, 3);
162
+ });
163
+ });