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.
- package/LICENSE.md +674 -0
- package/README.md +81 -0
- package/dist/core.d.mts +340 -0
- package/dist/core.mjs +1047 -0
- package/dist/index.d.mts +3426 -0
- package/dist/index.mjs +12762 -0
- package/dist/interactions-DEFL_F4E.mjs +5395 -0
- package/dist/range-presets-CzECsu3V.d.mts +1523 -0
- package/package.json +34 -0
- package/src/annotations.d.ts +121 -0
- package/src/annotations.ts +438 -0
- package/src/axis.d.ts +184 -0
- package/src/axis.test.ts +131 -0
- package/src/axis.ts +765 -0
- package/src/colorbar.d.ts +69 -0
- package/src/colorbar.ts +294 -0
- package/src/colors.d.ts +57 -0
- package/src/colors.test.ts +28 -0
- package/src/colors.ts +486 -0
- package/src/core.ts +299 -0
- package/src/format.d.ts +54 -0
- package/src/format.ts +138 -0
- package/src/grammar/accessibility.d.ts +147 -0
- package/src/grammar/accessibility.test.ts +199 -0
- package/src/grammar/accessibility.ts +443 -0
- package/src/grammar/aes.d.ts +35 -0
- package/src/grammar/aes.test.ts +75 -0
- package/src/grammar/aes.ts +120 -0
- package/src/grammar/annotations.d.ts +86 -0
- package/src/grammar/annotations.test.ts +68 -0
- package/src/grammar/annotations.ts +336 -0
- package/src/grammar/attach-brush.d.ts +44 -0
- package/src/grammar/attach-brush.test.ts +214 -0
- package/src/grammar/attach-brush.ts +111 -0
- package/src/grammar/attach-presets.d.ts +33 -0
- package/src/grammar/attach-presets.test.ts +106 -0
- package/src/grammar/attach-presets.ts +215 -0
- package/src/grammar/chart.d.ts +952 -0
- package/src/grammar/chart.test.ts +118 -0
- package/src/grammar/chart.ts +1172 -0
- package/src/grammar/color-utils.d.ts +29 -0
- package/src/grammar/color-utils.test.ts +53 -0
- package/src/grammar/color-utils.ts +66 -0
- package/src/grammar/constants.d.ts +45 -0
- package/src/grammar/constants.ts +61 -0
- package/src/grammar/coord.d.ts +183 -0
- package/src/grammar/coord.test.ts +355 -0
- package/src/grammar/coord.ts +619 -0
- package/src/grammar/data/pivot.d.ts +57 -0
- package/src/grammar/data/pivot.ts +107 -0
- package/src/grammar/emphasis-driver.d.ts +69 -0
- package/src/grammar/emphasis-driver.test.ts +199 -0
- package/src/grammar/emphasis-driver.ts +205 -0
- package/src/grammar/equality.d.ts +3 -0
- package/src/grammar/equality.ts +40 -0
- package/src/grammar/facet.d.ts +63 -0
- package/src/grammar/facet.test.ts +60 -0
- package/src/grammar/facet.ts +175 -0
- package/src/grammar/geoms/_categorical.d.ts +94 -0
- package/src/grammar/geoms/_categorical.ts +0 -0
- package/src/grammar/geoms/_distribution.d.ts +52 -0
- package/src/grammar/geoms/_distribution.ts +125 -0
- package/src/grammar/geoms/_mark.d.ts +69 -0
- package/src/grammar/geoms/_mark.ts +136 -0
- package/src/grammar/geoms/_shape.d.ts +41 -0
- package/src/grammar/geoms/_shape.ts +74 -0
- package/src/grammar/geoms/aggregate.d.ts +95 -0
- package/src/grammar/geoms/aggregate.test.ts +554 -0
- package/src/grammar/geoms/aggregate.ts +840 -0
- package/src/grammar/geoms/area.d.ts +32 -0
- package/src/grammar/geoms/area.test.ts +165 -0
- package/src/grammar/geoms/area.ts +578 -0
- package/src/grammar/geoms/band.d.ts +27 -0
- package/src/grammar/geoms/band.test.ts +57 -0
- package/src/grammar/geoms/band.ts +126 -0
- package/src/grammar/geoms/bar.d.ts +56 -0
- package/src/grammar/geoms/bar.test.ts +367 -0
- package/src/grammar/geoms/bar.ts +1054 -0
- package/src/grammar/geoms/boxplot.d.ts +129 -0
- package/src/grammar/geoms/boxplot.test.ts +299 -0
- package/src/grammar/geoms/boxplot.ts +834 -0
- package/src/grammar/geoms/connected-scatter.d.ts +27 -0
- package/src/grammar/geoms/connected-scatter.test.ts +157 -0
- package/src/grammar/geoms/connected-scatter.ts +63 -0
- package/src/grammar/geoms/emphasis.d.ts +76 -0
- package/src/grammar/geoms/emphasis.test.ts +135 -0
- package/src/grammar/geoms/emphasis.ts +162 -0
- package/src/grammar/geoms/histogram.d.ts +75 -0
- package/src/grammar/geoms/histogram.test.ts +262 -0
- package/src/grammar/geoms/histogram.ts +740 -0
- package/src/grammar/geoms/index.d.ts +20 -0
- package/src/grammar/geoms/index.ts +77 -0
- package/src/grammar/geoms/interval.d.ts +31 -0
- package/src/grammar/geoms/interval.test.ts +154 -0
- package/src/grammar/geoms/interval.ts +342 -0
- package/src/grammar/geoms/line.d.ts +38 -0
- package/src/grammar/geoms/line.test.ts +247 -0
- package/src/grammar/geoms/line.ts +659 -0
- package/src/grammar/geoms/point.d.ts +57 -0
- package/src/grammar/geoms/point.test.ts +163 -0
- package/src/grammar/geoms/point.ts +545 -0
- package/src/grammar/geoms/polar.test.ts +216 -0
- package/src/grammar/geoms/ribbon.d.ts +21 -0
- package/src/grammar/geoms/ribbon.test.ts +170 -0
- package/src/grammar/geoms/ribbon.ts +87 -0
- package/src/grammar/geoms/ridgeline.d.ts +89 -0
- package/src/grammar/geoms/ridgeline.test.ts +247 -0
- package/src/grammar/geoms/ridgeline.ts +1164 -0
- package/src/grammar/geoms/rolling.d.ts +43 -0
- package/src/grammar/geoms/rolling.test.ts +217 -0
- package/src/grammar/geoms/rolling.ts +387 -0
- package/src/grammar/geoms/rug.d.ts +28 -0
- package/src/grammar/geoms/rug.test.ts +126 -0
- package/src/grammar/geoms/rug.ts +214 -0
- package/src/grammar/geoms/rule.d.ts +23 -0
- package/src/grammar/geoms/rule.test.ts +69 -0
- package/src/grammar/geoms/rule.ts +212 -0
- package/src/grammar/geoms/smooth.d.ts +54 -0
- package/src/grammar/geoms/smooth.test.ts +78 -0
- package/src/grammar/geoms/smooth.ts +337 -0
- package/src/grammar/geoms/text.d.ts +29 -0
- package/src/grammar/geoms/text.test.ts +64 -0
- package/src/grammar/geoms/text.ts +234 -0
- package/src/grammar/geoms/tile.d.ts +61 -0
- package/src/grammar/geoms/tile.test.ts +157 -0
- package/src/grammar/geoms/tile.ts +621 -0
- package/src/grammar/geoms/types.d.ts +319 -0
- package/src/grammar/geoms/types.ts +362 -0
- package/src/grammar/geoms/violin.d.ts +85 -0
- package/src/grammar/geoms/violin.test.ts +187 -0
- package/src/grammar/geoms/violin.ts +672 -0
- package/src/grammar/index.d.ts +22 -0
- package/src/grammar/index.ts +269 -0
- package/src/grammar/interactions/_disposable.d.ts +5 -0
- package/src/grammar/interactions/_disposable.ts +23 -0
- package/src/grammar/interactions/_z.d.ts +4 -0
- package/src/grammar/interactions/_z.ts +16 -0
- package/src/grammar/interactions/brush-selection.test.ts +262 -0
- package/src/grammar/interactions/brush.d.ts +63 -0
- package/src/grammar/interactions/brush.test.ts +483 -0
- package/src/grammar/interactions/brush.ts +452 -0
- package/src/grammar/interactions/crosshair.d.ts +19 -0
- package/src/grammar/interactions/crosshair.test.ts +127 -0
- package/src/grammar/interactions/crosshair.ts +76 -0
- package/src/grammar/interactions/hit-layer.d.ts +64 -0
- package/src/grammar/interactions/hit-layer.ts +246 -0
- package/src/grammar/interactions/legend.d.ts +19 -0
- package/src/grammar/interactions/legend.ts +101 -0
- package/src/grammar/interactions/menu.d.ts +93 -0
- package/src/grammar/interactions/menu.test.ts +373 -0
- package/src/grammar/interactions/menu.ts +342 -0
- package/src/grammar/interactions/selection.d.ts +25 -0
- package/src/grammar/interactions/selection.test.ts +289 -0
- package/src/grammar/interactions/selection.ts +142 -0
- package/src/grammar/interactions/series-readout.d.ts +91 -0
- package/src/grammar/interactions/series-readout.test.ts +668 -0
- package/src/grammar/interactions/series-readout.ts +422 -0
- package/src/grammar/interactions/series-snap.d.ts +70 -0
- package/src/grammar/interactions/series-snap.test.ts +214 -0
- package/src/grammar/interactions/series-snap.ts +218 -0
- package/src/grammar/interactions/tooltip-axis.test.ts +176 -0
- package/src/grammar/interactions/tooltip-touch.browser.test.ts +49 -0
- package/src/grammar/interactions/tooltip-touch.test.ts +161 -0
- package/src/grammar/interactions/tooltip.d.ts +140 -0
- package/src/grammar/interactions/tooltip.test.ts +406 -0
- package/src/grammar/interactions/tooltip.ts +622 -0
- package/src/grammar/interactions/transitions.d.ts +34 -0
- package/src/grammar/interactions/transitions.test.ts +172 -0
- package/src/grammar/interactions/transitions.ts +160 -0
- package/src/grammar/layout.d.ts +68 -0
- package/src/grammar/layout.ts +186 -0
- package/src/grammar/legend-merge.test.ts +332 -0
- package/src/grammar/mount.d.ts +78 -0
- package/src/grammar/mount.test.ts +479 -0
- package/src/grammar/mount.ts +2112 -0
- package/src/grammar/palettes.d.ts +54 -0
- package/src/grammar/palettes.test.ts +80 -0
- package/src/grammar/palettes.ts +167 -0
- package/src/grammar/pan-zoom.test.ts +398 -0
- package/src/grammar/phylo.d.ts +65 -0
- package/src/grammar/phylo.test.ts +59 -0
- package/src/grammar/phylo.ts +112 -0
- package/src/grammar/pipeline.auto-ticks.test.ts +40 -0
- package/src/grammar/pipeline.d.ts +158 -0
- package/src/grammar/pipeline.test.ts +463 -0
- package/src/grammar/pipeline.ts +1233 -0
- package/src/grammar/profiling.d.ts +8 -0
- package/src/grammar/profiling.ts +24 -0
- package/src/grammar/scales.d.ts +188 -0
- package/src/grammar/scales.test.ts +181 -0
- package/src/grammar/scales.ts +800 -0
- package/src/grammar/svg.d.ts +3 -0
- package/src/grammar/svg.ts +39 -0
- package/src/grammar/theme.d.ts +261 -0
- package/src/grammar/theme.test.ts +105 -0
- package/src/grammar/theme.ts +490 -0
- package/src/heatmap/cpu.ts +109 -0
- package/src/heatmap/gpu.ts +565 -0
- package/src/heatmap/types.ts +177 -0
- package/src/heatmap.browser.test.ts +308 -0
- package/src/heatmap.test.ts +320 -0
- package/src/heatmap.ts +123 -0
- package/src/index.d.ts +1 -0
- package/src/index.ts +8 -0
- package/src/interactions.d.ts +48 -0
- package/src/interactions.test.ts +226 -0
- package/src/interactions.ts +394 -0
- package/src/layout/box.d.ts +48 -0
- package/src/layout/box.test.ts +107 -0
- package/src/layout/box.ts +143 -0
- package/src/legend.d.ts +115 -0
- package/src/legend.ts +422 -0
- package/src/marks/curve.d.ts +43 -0
- package/src/marks/curve.ts +244 -0
- package/src/marks/stack.d.ts +53 -0
- package/src/marks/stack.ts +184 -0
- package/src/marks.d.ts +273 -0
- package/src/marks.test.ts +541 -0
- package/src/marks.ts +1292 -0
- package/src/navigator.test.ts +174 -0
- package/src/navigator.ts +393 -0
- package/src/range-presets.d.ts +113 -0
- package/src/range-presets.test.ts +345 -0
- package/src/range-presets.ts +349 -0
- package/src/scales.d.ts +98 -0
- package/src/scales.test.ts +103 -0
- package/src/scales.ts +695 -0
- package/src/stats/index.d.ts +200 -0
- package/src/stats/index.test.ts +349 -0
- package/src/stats/index.ts +740 -0
- package/src/stats/regression.d.ts +38 -0
- package/src/stats/regression.test.ts +56 -0
- package/src/stats/regression.ts +396 -0
- package/src/stats/rolling-window.d.ts +55 -0
- package/src/stats/rolling-window.test.ts +237 -0
- package/src/stats/rolling-window.ts +256 -0
- package/src/test-setup.ts +19 -0
- package/src/viewport/axis-state.d.ts +72 -0
- package/src/viewport/axis-state.ts +476 -0
- package/src/viewport.d.ts +170 -0
- package/src/viewport.test.ts +363 -0
- package/src/viewport.ts +510 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import type { Color, Frame, GlyphAtlas, Layer } from "insomni";
|
|
2
|
+
import type { MarkBuilder } from "../../marks.ts";
|
|
3
|
+
import type { SwatchSpec } from "../../legend.ts";
|
|
4
|
+
import type { Aes, ResolvedAes } from "../aes.ts";
|
|
5
|
+
import type { AlphaScale, BorderStyleScale, ColorScale, OverlayGlyphScale, PositionScale, PositionScaleOptions, ShapeScale, SizeScale } from "../scales.ts";
|
|
6
|
+
import type { Theme } from "../theme.ts";
|
|
7
|
+
export type GeomKind = "point" | "line" | "area" | "bar" | "text" | "rule" | "band" | "boxplot" | "violin" | "histogram" | "ridgeline" | "rug" | "smooth" | "rolling" | "tile" | "interval";
|
|
8
|
+
/**
|
|
9
|
+
* Channel mappings as declared by the user. Stored at this width on `Geom<T>`
|
|
10
|
+
* so the chart can iterate channels generically. Geom factories accept their
|
|
11
|
+
* narrower per-geom channel types (PointChannels, LineChannels, ...) as the
|
|
12
|
+
* public surface and cast into this for storage.
|
|
13
|
+
*/
|
|
14
|
+
export interface ChannelSpec<_T> {
|
|
15
|
+
x?: unknown;
|
|
16
|
+
y?: unknown;
|
|
17
|
+
color?: unknown;
|
|
18
|
+
size?: unknown;
|
|
19
|
+
shape?: unknown;
|
|
20
|
+
alpha?: unknown;
|
|
21
|
+
borderStyle?: unknown;
|
|
22
|
+
overlayGlyph?: unknown;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Per-geom hints for position-scale construction. Geoms that have a
|
|
26
|
+
* conventional baseline (bar, area) request that their value axis include 0
|
|
27
|
+
* — or, for `position: 'fill'`, set an explicit `[0, 1]` domain. Hints are
|
|
28
|
+
* only applied to numeric (linear/log/sqrt) scales; band/time scales ignore
|
|
29
|
+
* them. An explicit `.scale(channel, { domain })` override always wins.
|
|
30
|
+
*/
|
|
31
|
+
export interface PositionScaleHint {
|
|
32
|
+
/** Force this exact domain (overrides include flags). */
|
|
33
|
+
domain?: readonly [number, number];
|
|
34
|
+
/** Extend inferred domain to include 0. */
|
|
35
|
+
includeZero?: boolean;
|
|
36
|
+
/** Extend inferred domain to include 1. */
|
|
37
|
+
includeOne?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Extend the inferred domain to include this range. Unlike `domain`, this
|
|
40
|
+
* is unioned with the data-derived extent (and with other layers' extends)
|
|
41
|
+
* rather than replacing it. Use for geoms whose visual footprint extends
|
|
42
|
+
* past the raw data — e.g. a KDE-based violin whose smoothed tails reach
|
|
43
|
+
* outside `[dataMin, dataMax]`.
|
|
44
|
+
*/
|
|
45
|
+
extend?: readonly [number, number];
|
|
46
|
+
}
|
|
47
|
+
export interface ScaleHints {
|
|
48
|
+
x?: PositionScaleHint;
|
|
49
|
+
y?: PositionScaleHint;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Pixel reservations on the plot frame for a geom whose visual extent
|
|
53
|
+
* exceeds its data footprint. The chart shrinks the position-scale range
|
|
54
|
+
* by these amounts so axis ticks track the compressed layout — used by
|
|
55
|
+
* ridgeline rows that rise above their baseline. Reservations from
|
|
56
|
+
* multiple layers are merged by max (the largest demand wins).
|
|
57
|
+
*/
|
|
58
|
+
export interface RangeHints {
|
|
59
|
+
top?: number;
|
|
60
|
+
bottom?: number;
|
|
61
|
+
left?: number;
|
|
62
|
+
right?: number;
|
|
63
|
+
}
|
|
64
|
+
export interface PrepareRangeContext<T> {
|
|
65
|
+
data: readonly T[];
|
|
66
|
+
plot: Frame;
|
|
67
|
+
scaleOptions: {
|
|
68
|
+
x?: PositionScaleOptions;
|
|
69
|
+
y?: PositionScaleOptions;
|
|
70
|
+
};
|
|
71
|
+
theme: Theme;
|
|
72
|
+
atlas: GlyphAtlas | undefined;
|
|
73
|
+
}
|
|
74
|
+
export type AnyAes<T> = Aes<T, unknown>;
|
|
75
|
+
export interface ScaleBundle {
|
|
76
|
+
x: PositionScale;
|
|
77
|
+
y: PositionScale;
|
|
78
|
+
color?: ColorScale;
|
|
79
|
+
size?: SizeScale;
|
|
80
|
+
alpha?: AlphaScale;
|
|
81
|
+
shape?: ShapeScale;
|
|
82
|
+
borderStyle?: BorderStyleScale;
|
|
83
|
+
overlayGlyph?: OverlayGlyphScale;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Per-rendered-element channel snapshot used for animated transitions.
|
|
87
|
+
* For simple geoms this usually matches the source datum index; for stacked /
|
|
88
|
+
* grouped geoms it can be one entry per visible segment. NaN marks filtered /
|
|
89
|
+
* hidden entries. Each geom owns the index convention used by its compile path.
|
|
90
|
+
*/
|
|
91
|
+
export interface GeomFrame {
|
|
92
|
+
count: number;
|
|
93
|
+
x: Float32Array;
|
|
94
|
+
y: Float32Array;
|
|
95
|
+
rgba: Float32Array;
|
|
96
|
+
a: Float32Array;
|
|
97
|
+
r?: Float32Array;
|
|
98
|
+
ids?: readonly string[];
|
|
99
|
+
}
|
|
100
|
+
/** Injected into CompileContext during an active data/scale transition. */
|
|
101
|
+
export interface ActiveTransition {
|
|
102
|
+
/** Progress 0 → 1. */
|
|
103
|
+
t: number;
|
|
104
|
+
/** From-snapshot for this geom. Indexed by datum i. */
|
|
105
|
+
from: GeomFrame;
|
|
106
|
+
/** Resolve a stable match index in `from` for the given key. */
|
|
107
|
+
matchIndex(key: string, fallbackIndex?: number): number | undefined;
|
|
108
|
+
}
|
|
109
|
+
export interface CompileContext<T> {
|
|
110
|
+
data: readonly T[];
|
|
111
|
+
scales: ScaleBundle;
|
|
112
|
+
plot: Frame;
|
|
113
|
+
theme: Theme;
|
|
114
|
+
atlas: GlyphAtlas | undefined;
|
|
115
|
+
/**
|
|
116
|
+
* Coordinate system in effect for this chart. Geoms can call
|
|
117
|
+
* `ctx.coord.project(p)` / `ctx.coord.segment(p1, p2)` to remap plot-frame
|
|
118
|
+
* pixel space into layer-pixel space — under `coordCartesian()` (the
|
|
119
|
+
* default) both are the identity, so existing geoms are unaffected. Phase 3
|
|
120
|
+
* adds `coordPolar()` / `coordRadial()` and per-geom polar projection.
|
|
121
|
+
*
|
|
122
|
+
* Optional during Phase 1: only the pipeline supplies it today, and geoms
|
|
123
|
+
* have not been migrated to project through it yet. Treat absence as
|
|
124
|
+
* `coordCartesian()` if you read it in a geom. Will become required when
|
|
125
|
+
* Phase 3 lands and per-geom polar projection ships.
|
|
126
|
+
*/
|
|
127
|
+
coord?: import("../coord.ts").Coord;
|
|
128
|
+
/**
|
|
129
|
+
* Currently hovered hit, or `null` if nothing is hovered. Geoms compare
|
|
130
|
+
* `hovered.data === ctx.data && hovered.geomKind === this.kind` to detect
|
|
131
|
+
* "their" hit and can use `hovered.dataIndex` to render a highlight (halo,
|
|
132
|
+
* elevated alpha/stroke, etc.). Provided by the mount; `undefined` when
|
|
133
|
+
* compiling outside a mount context (e.g. SSR / SVG export).
|
|
134
|
+
*/
|
|
135
|
+
hovered?: HoveredHit | null;
|
|
136
|
+
/**
|
|
137
|
+
* Currently selected hits (multi-select). Empty array = nothing selected;
|
|
138
|
+
* `undefined` = selection is disabled (no visual treatment). Geoms render
|
|
139
|
+
* stroke rings on matching rows and may dim non-selected rows when the
|
|
140
|
+
* array is non-empty.
|
|
141
|
+
*/
|
|
142
|
+
selected?: readonly HoveredHit[];
|
|
143
|
+
/** Set of series keys currently hidden via legend toggle. */
|
|
144
|
+
hidden?: ReadonlySet<string>;
|
|
145
|
+
/** Optional stable key used to match rows across data refreshes for transitions. */
|
|
146
|
+
transitionKey?: (datum: T, index: number) => string;
|
|
147
|
+
/**
|
|
148
|
+
* Active data/scale transition context. Present only during an animated
|
|
149
|
+
* transition; geoms use it to lerp channels from the previous frame toward
|
|
150
|
+
* the current compiled values.
|
|
151
|
+
*/
|
|
152
|
+
activeTransition?: ActiveTransition;
|
|
153
|
+
/**
|
|
154
|
+
* Disjoint emphasis-key band base for this geom (P5-T3). The pipeline assigns
|
|
155
|
+
* `geomEmphasisBase(geomIndex)`; dim-participating geoms tag each mark
|
|
156
|
+
* instance `emphasisKey: emphasisKeyFor(base, ordinal)` so the core's GPU dim
|
|
157
|
+
* uniform can fade non-focused instances WITHOUT a marks recompile. `undefined`
|
|
158
|
+
* outside a mount (SSR / SVG export) → geoms skip tagging (no GPU emphasis).
|
|
159
|
+
* See {@link import("./emphasis.ts")}.
|
|
160
|
+
*/
|
|
161
|
+
emphasisBase?: number;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The active hover state surfaced to compile contexts and exposed on
|
|
165
|
+
* `MountedPlot.hovered`. Coordinates are absolute element-CSS pixels
|
|
166
|
+
* (matching `CompiledHitTest.positions`).
|
|
167
|
+
*/
|
|
168
|
+
export interface HoveredHit {
|
|
169
|
+
geomKind: GeomKind;
|
|
170
|
+
dataIndex: number;
|
|
171
|
+
/** Optional segment key for multi-series geoms (stacked/dodged bars, stacked areas). */
|
|
172
|
+
seriesKey?: string;
|
|
173
|
+
/**
|
|
174
|
+
* Reference to the data array used to compile the originating geom — used
|
|
175
|
+
* for identity comparison (`hovered.data === ctx.data`) so multi-layer
|
|
176
|
+
* charts can route the hit to the right geom.
|
|
177
|
+
*/
|
|
178
|
+
data: readonly unknown[];
|
|
179
|
+
x: number;
|
|
180
|
+
y: number;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Resolved aesthetics for each channel of a geom — used by interaction layers
|
|
184
|
+
* (tooltips, legends-on-hover) to read the original column name and pull the
|
|
185
|
+
* raw value back out for a given datum.
|
|
186
|
+
*/
|
|
187
|
+
export interface ResolvedChannelMap<T> {
|
|
188
|
+
x?: ResolvedAes<T, unknown>;
|
|
189
|
+
y?: ResolvedAes<T, unknown>;
|
|
190
|
+
color?: ResolvedAes<T, unknown>;
|
|
191
|
+
size?: ResolvedAes<T, unknown>;
|
|
192
|
+
shape?: ResolvedAes<T, unknown>;
|
|
193
|
+
alpha?: ResolvedAes<T, unknown>;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Hit-test points emitted by a geom for hover/click. Coordinates are absolute
|
|
197
|
+
* element-CSS pixels (the chart's plot frame offset is already baked in), so
|
|
198
|
+
* the consumer can hand them to a `space: "ui"` PointCloudNode without
|
|
199
|
+
* adjustment. `dataIndex[i]` maps hit `i` back to the original `data` array
|
|
200
|
+
* (after filtering NaN/null values). `seriesKey[i]` further distinguishes
|
|
201
|
+
* segments that share a source row.
|
|
202
|
+
*/
|
|
203
|
+
export interface CompiledHitTest<T> {
|
|
204
|
+
geomKind: GeomKind;
|
|
205
|
+
label?: string;
|
|
206
|
+
positions: Float32Array;
|
|
207
|
+
dataIndex: Int32Array;
|
|
208
|
+
seriesKey?: readonly (string | undefined)[];
|
|
209
|
+
pickRadius: number;
|
|
210
|
+
/**
|
|
211
|
+
* Optional per-hit bounding rect in absolute element-CSS pixels. When
|
|
212
|
+
* present, the hit-layer prefers rect containment over nearest-point
|
|
213
|
+
* picking (`positions` + `pickRadius`), giving "whole shape" hover for
|
|
214
|
+
* shape-based geoms (bar, histogram, ridgeline rows, tile cells, ...).
|
|
215
|
+
* Layout: `[x, y, w, h]` per `dataIndex` entry. `positions` is still
|
|
216
|
+
* required as a fallback (used to anchor tooltips, brushes, etc.).
|
|
217
|
+
*/
|
|
218
|
+
rects?: Float32Array;
|
|
219
|
+
/**
|
|
220
|
+
* Distance metric for nearest-point queries. Default `"xy"` (Euclidean).
|
|
221
|
+
* `"x"` makes the picker resolve nearest-by-x only — used by `line()` /
|
|
222
|
+
* `area()` when `nearestX: true` so the user can hover anywhere along the
|
|
223
|
+
* curve and the active vertex follows the cursor's x.
|
|
224
|
+
*/
|
|
225
|
+
pickAxis?: "x" | "y" | "xy";
|
|
226
|
+
channels: ResolvedChannelMap<T>;
|
|
227
|
+
data: readonly T[];
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* A geom's hover-focus decoration, captured at compile time so the mount can
|
|
231
|
+
* draw it on hover **without recompiling the pipeline**. The mount calls
|
|
232
|
+
* {@link decorate} into the live overlay layer (which composites above the baked
|
|
233
|
+
* marks), so local focus treatment — a contrast halo, bringing the hovered
|
|
234
|
+
* element to the front — costs only a cheap overlay repaint rather than a full
|
|
235
|
+
* marks recompute. The complementary *global* dim-others treatment (fading every
|
|
236
|
+
* other element) rides the core's GPU emphasis uniform (see {@link
|
|
237
|
+
* EmphasisResolver}), so a geom can provide both: the decorator draws the focus
|
|
238
|
+
* halo (left at emphasis key 0 = exempt, full-strength) while the uniform dims
|
|
239
|
+
* the rest. Geoms with no local focus shape simply omit this.
|
|
240
|
+
*
|
|
241
|
+
* `geomKind` + `data` identity let the mount match the decorator to the active
|
|
242
|
+
* `HoveredHit` (the same keys used to route a hit to its geom).
|
|
243
|
+
*/
|
|
244
|
+
export interface GeomHoverDecorator {
|
|
245
|
+
readonly geomKind: GeomKind;
|
|
246
|
+
readonly data: readonly unknown[];
|
|
247
|
+
/** Draw the focus decoration for `hit` into `layer` (the overlay layer). */
|
|
248
|
+
decorate(hit: HoveredHit, layer: Layer): void;
|
|
249
|
+
}
|
|
250
|
+
export interface Geom<T> {
|
|
251
|
+
readonly kind: GeomKind;
|
|
252
|
+
readonly channels: ChannelSpec<T>;
|
|
253
|
+
/** Used by the auto-legend to label the layer. Falls back to channel name. */
|
|
254
|
+
readonly label?: string;
|
|
255
|
+
/** Optional position-scale hints (e.g. anchor value axis at 0 for bars). */
|
|
256
|
+
readonly scaleHints?: ScaleHints;
|
|
257
|
+
/**
|
|
258
|
+
* When true, the geom renders into the hud layer (above marks, no clip rect)
|
|
259
|
+
* instead of the marks layer. Used by geoms whose visual extent intentionally
|
|
260
|
+
* exceeds the plot frame — e.g. phylo tip labels — and that should not be
|
|
261
|
+
* clipped at the frame edge.
|
|
262
|
+
*/
|
|
263
|
+
readonly overlay?: boolean;
|
|
264
|
+
/**
|
|
265
|
+
* Optional data-derived scale hints. Called once before scales are built,
|
|
266
|
+
* so geoms whose visual extent depends on the data (e.g. KDE-smoothed
|
|
267
|
+
* violins) can extend the position-scale domain accordingly. Returned
|
|
268
|
+
* hints are merged with `scaleHints` and any hints contributed by other
|
|
269
|
+
* layers. An explicit `.scale(channel, { domain })` override always wins.
|
|
270
|
+
*/
|
|
271
|
+
prepareDomain?(data: readonly T[]): ScaleHints | undefined;
|
|
272
|
+
/**
|
|
273
|
+
* Optional layout-time hook that runs after layout but before scale
|
|
274
|
+
* construction. Geoms whose visual extent exceeds their data footprint
|
|
275
|
+
* — e.g. a ridgeline ridge that rises above its baseline by `overlap ×
|
|
276
|
+
* cellSize` — use this to reserve pixel margins on the plot frame, so
|
|
277
|
+
* the position scale (and its axis ticks) shrink to fit.
|
|
278
|
+
*/
|
|
279
|
+
prepareRange?(ctx: PrepareRangeContext<T>): RangeHints | undefined;
|
|
280
|
+
/**
|
|
281
|
+
* Optional override for the auto-legend's per-series swatch. Geoms that
|
|
282
|
+
* draw filled regions (bar/area/tile) or strokes (line) supply their own;
|
|
283
|
+
* the pipeline falls back to a point swatch when omitted.
|
|
284
|
+
*/
|
|
285
|
+
legendSwatch?(color: Color, theme: Theme): SwatchSpec;
|
|
286
|
+
compile(ctx: CompileContext<T>): readonly MarkBuilder[];
|
|
287
|
+
/**
|
|
288
|
+
* Optional hit-test contribution for interactions. Implemented per geom that
|
|
289
|
+
* wants to support hover/click selection (`point` in v1; bar/line/area in
|
|
290
|
+
* later phases). Return `null` to opt out for a particular compile pass
|
|
291
|
+
* (e.g. when the geom has no points after filtering).
|
|
292
|
+
*/
|
|
293
|
+
compileHitTest?(ctx: CompileContext<T>): CompiledHitTest<T> | null;
|
|
294
|
+
/**
|
|
295
|
+
* Optional hover-focus decorator. Implemented by geoms whose focus treatment
|
|
296
|
+
* is *local* (point: contrast halo + bring-to-front) so it can ride the
|
|
297
|
+
* mount's cheap overlay path instead of a marks recompute. Called once per
|
|
298
|
+
* full compile with the same `ctx`; returns `null` to opt out (e.g. empty
|
|
299
|
+
* data). See {@link GeomHoverDecorator}.
|
|
300
|
+
*/
|
|
301
|
+
hoverDecoration?(ctx: CompileContext<T>): GeomHoverDecorator | null;
|
|
302
|
+
/**
|
|
303
|
+
* Emphasis-key resolver for geoms whose hover treatment is *global* (dim the
|
|
304
|
+
* others via the core's GPU emphasis uniform: bar/line/violin/...). Captured
|
|
305
|
+
* once per full compile with the same `ctx` (so it sees the same `emphasisBase`
|
|
306
|
+
* + scales the tagging used); the mount maps an active {@link HoveredHit} to the
|
|
307
|
+
* namespaced key the geom tagged its focused instance(s) with — without
|
|
308
|
+
* recompiling. Returns `null` to opt out (e.g. empty data, or `emphasisBase`
|
|
309
|
+
* absent). Mutually complementary with {@link hoverDecoration} (local focus).
|
|
310
|
+
* See {@link import("./emphasis.ts").EmphasisResolver}.
|
|
311
|
+
*/
|
|
312
|
+
emphasisResolution?(ctx: CompileContext<T>): import("./emphasis.ts").EmphasisResolver | null;
|
|
313
|
+
/**
|
|
314
|
+
* Capture a per-datum channel snapshot for use as a transition "from" frame.
|
|
315
|
+
* Called after `compile` on each stable (non-animating) frame. Returns `null`
|
|
316
|
+
* if the geom has no meaningful frame to capture (e.g. empty data).
|
|
317
|
+
*/
|
|
318
|
+
captureFrame?(ctx: CompileContext<T>): GeomFrame | null;
|
|
319
|
+
}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Geom contract
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
import type { Color, Frame, GlyphAtlas, Layer } from "insomni";
|
|
6
|
+
import type { MarkBuilder } from "../../marks.ts";
|
|
7
|
+
import type { SwatchSpec } from "../../legend.ts";
|
|
8
|
+
import type { Aes, ResolvedAes } from "../aes.ts";
|
|
9
|
+
import type {
|
|
10
|
+
AlphaScale,
|
|
11
|
+
BorderStyleScale,
|
|
12
|
+
ColorScale,
|
|
13
|
+
OverlayGlyphScale,
|
|
14
|
+
PositionScale,
|
|
15
|
+
PositionScaleOptions,
|
|
16
|
+
ShapeScale,
|
|
17
|
+
SizeScale,
|
|
18
|
+
} from "../scales.ts";
|
|
19
|
+
import type { Theme } from "../theme.ts";
|
|
20
|
+
|
|
21
|
+
export type GeomKind =
|
|
22
|
+
| "point"
|
|
23
|
+
| "line"
|
|
24
|
+
| "area"
|
|
25
|
+
| "bar"
|
|
26
|
+
| "text"
|
|
27
|
+
| "rule"
|
|
28
|
+
| "band"
|
|
29
|
+
| "boxplot"
|
|
30
|
+
| "violin"
|
|
31
|
+
| "histogram"
|
|
32
|
+
| "ridgeline"
|
|
33
|
+
| "rug"
|
|
34
|
+
| "smooth"
|
|
35
|
+
| "rolling"
|
|
36
|
+
| "tile"
|
|
37
|
+
| "interval";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Channel mappings as declared by the user. Stored at this width on `Geom<T>`
|
|
41
|
+
* so the chart can iterate channels generically. Geom factories accept their
|
|
42
|
+
* narrower per-geom channel types (PointChannels, LineChannels, ...) as the
|
|
43
|
+
* public surface and cast into this for storage.
|
|
44
|
+
*/
|
|
45
|
+
export interface ChannelSpec<_T> {
|
|
46
|
+
x?: unknown;
|
|
47
|
+
y?: unknown;
|
|
48
|
+
color?: unknown;
|
|
49
|
+
size?: unknown;
|
|
50
|
+
shape?: unknown;
|
|
51
|
+
alpha?: unknown;
|
|
52
|
+
borderStyle?: unknown;
|
|
53
|
+
overlayGlyph?: unknown;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Per-geom hints for position-scale construction. Geoms that have a
|
|
58
|
+
* conventional baseline (bar, area) request that their value axis include 0
|
|
59
|
+
* — or, for `position: 'fill'`, set an explicit `[0, 1]` domain. Hints are
|
|
60
|
+
* only applied to numeric (linear/log/sqrt) scales; band/time scales ignore
|
|
61
|
+
* them. An explicit `.scale(channel, { domain })` override always wins.
|
|
62
|
+
*/
|
|
63
|
+
export interface PositionScaleHint {
|
|
64
|
+
/** Force this exact domain (overrides include flags). */
|
|
65
|
+
domain?: readonly [number, number];
|
|
66
|
+
/** Extend inferred domain to include 0. */
|
|
67
|
+
includeZero?: boolean;
|
|
68
|
+
/** Extend inferred domain to include 1. */
|
|
69
|
+
includeOne?: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Extend the inferred domain to include this range. Unlike `domain`, this
|
|
72
|
+
* is unioned with the data-derived extent (and with other layers' extends)
|
|
73
|
+
* rather than replacing it. Use for geoms whose visual footprint extends
|
|
74
|
+
* past the raw data — e.g. a KDE-based violin whose smoothed tails reach
|
|
75
|
+
* outside `[dataMin, dataMax]`.
|
|
76
|
+
*/
|
|
77
|
+
extend?: readonly [number, number];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface ScaleHints {
|
|
81
|
+
x?: PositionScaleHint;
|
|
82
|
+
y?: PositionScaleHint;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Pixel reservations on the plot frame for a geom whose visual extent
|
|
87
|
+
* exceeds its data footprint. The chart shrinks the position-scale range
|
|
88
|
+
* by these amounts so axis ticks track the compressed layout — used by
|
|
89
|
+
* ridgeline rows that rise above their baseline. Reservations from
|
|
90
|
+
* multiple layers are merged by max (the largest demand wins).
|
|
91
|
+
*/
|
|
92
|
+
export interface RangeHints {
|
|
93
|
+
top?: number;
|
|
94
|
+
bottom?: number;
|
|
95
|
+
left?: number;
|
|
96
|
+
right?: number;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface PrepareRangeContext<T> {
|
|
100
|
+
data: readonly T[];
|
|
101
|
+
plot: Frame;
|
|
102
|
+
scaleOptions: { x?: PositionScaleOptions; y?: PositionScaleOptions };
|
|
103
|
+
theme: Theme;
|
|
104
|
+
atlas: GlyphAtlas | undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Used inside the chart pipeline once channels are read off a geom.
|
|
108
|
+
export type AnyAes<T> = Aes<T, unknown>;
|
|
109
|
+
|
|
110
|
+
export interface ScaleBundle {
|
|
111
|
+
x: PositionScale;
|
|
112
|
+
y: PositionScale;
|
|
113
|
+
color?: ColorScale;
|
|
114
|
+
size?: SizeScale;
|
|
115
|
+
alpha?: AlphaScale;
|
|
116
|
+
shape?: ShapeScale;
|
|
117
|
+
borderStyle?: BorderStyleScale;
|
|
118
|
+
overlayGlyph?: OverlayGlyphScale;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Per-rendered-element channel snapshot used for animated transitions.
|
|
123
|
+
* For simple geoms this usually matches the source datum index; for stacked /
|
|
124
|
+
* grouped geoms it can be one entry per visible segment. NaN marks filtered /
|
|
125
|
+
* hidden entries. Each geom owns the index convention used by its compile path.
|
|
126
|
+
*/
|
|
127
|
+
export interface GeomFrame {
|
|
128
|
+
count: number; // data.length this frame
|
|
129
|
+
x: Float32Array; // plot-relative pixel x
|
|
130
|
+
y: Float32Array; // plot-relative pixel y
|
|
131
|
+
rgba: Float32Array; // 4 floats per datum: [r,g,b,a, r,g,b,a, ...]
|
|
132
|
+
a: Float32Array; // per-datum alpha [0,1]
|
|
133
|
+
r?: Float32Array; // point: radius; area: y0 (baseline px); bar: raw domain value
|
|
134
|
+
ids?: readonly string[];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Injected into CompileContext during an active data/scale transition. */
|
|
138
|
+
export interface ActiveTransition {
|
|
139
|
+
/** Progress 0 → 1. */
|
|
140
|
+
t: number;
|
|
141
|
+
/** From-snapshot for this geom. Indexed by datum i. */
|
|
142
|
+
from: GeomFrame;
|
|
143
|
+
/** Resolve a stable match index in `from` for the given key. */
|
|
144
|
+
matchIndex(key: string, fallbackIndex?: number): number | undefined;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface CompileContext<T> {
|
|
148
|
+
data: readonly T[];
|
|
149
|
+
scales: ScaleBundle;
|
|
150
|
+
plot: Frame;
|
|
151
|
+
theme: Theme;
|
|
152
|
+
atlas: GlyphAtlas | undefined;
|
|
153
|
+
/**
|
|
154
|
+
* Coordinate system in effect for this chart. Geoms can call
|
|
155
|
+
* `ctx.coord.project(p)` / `ctx.coord.segment(p1, p2)` to remap plot-frame
|
|
156
|
+
* pixel space into layer-pixel space — under `coordCartesian()` (the
|
|
157
|
+
* default) both are the identity, so existing geoms are unaffected. Phase 3
|
|
158
|
+
* adds `coordPolar()` / `coordRadial()` and per-geom polar projection.
|
|
159
|
+
*
|
|
160
|
+
* Optional during Phase 1: only the pipeline supplies it today, and geoms
|
|
161
|
+
* have not been migrated to project through it yet. Treat absence as
|
|
162
|
+
* `coordCartesian()` if you read it in a geom. Will become required when
|
|
163
|
+
* Phase 3 lands and per-geom polar projection ships.
|
|
164
|
+
*/
|
|
165
|
+
coord?: import("../coord.ts").Coord;
|
|
166
|
+
/**
|
|
167
|
+
* Currently hovered hit, or `null` if nothing is hovered. Geoms compare
|
|
168
|
+
* `hovered.data === ctx.data && hovered.geomKind === this.kind` to detect
|
|
169
|
+
* "their" hit and can use `hovered.dataIndex` to render a highlight (halo,
|
|
170
|
+
* elevated alpha/stroke, etc.). Provided by the mount; `undefined` when
|
|
171
|
+
* compiling outside a mount context (e.g. SSR / SVG export).
|
|
172
|
+
*/
|
|
173
|
+
hovered?: HoveredHit | null;
|
|
174
|
+
/**
|
|
175
|
+
* Currently selected hits (multi-select). Empty array = nothing selected;
|
|
176
|
+
* `undefined` = selection is disabled (no visual treatment). Geoms render
|
|
177
|
+
* stroke rings on matching rows and may dim non-selected rows when the
|
|
178
|
+
* array is non-empty.
|
|
179
|
+
*/
|
|
180
|
+
selected?: readonly HoveredHit[];
|
|
181
|
+
/** Set of series keys currently hidden via legend toggle. */
|
|
182
|
+
hidden?: ReadonlySet<string>;
|
|
183
|
+
/** Optional stable key used to match rows across data refreshes for transitions. */
|
|
184
|
+
transitionKey?: (datum: T, index: number) => string;
|
|
185
|
+
/**
|
|
186
|
+
* Active data/scale transition context. Present only during an animated
|
|
187
|
+
* transition; geoms use it to lerp channels from the previous frame toward
|
|
188
|
+
* the current compiled values.
|
|
189
|
+
*/
|
|
190
|
+
activeTransition?: ActiveTransition;
|
|
191
|
+
/**
|
|
192
|
+
* Disjoint emphasis-key band base for this geom (P5-T3). The pipeline assigns
|
|
193
|
+
* `geomEmphasisBase(geomIndex)`; dim-participating geoms tag each mark
|
|
194
|
+
* instance `emphasisKey: emphasisKeyFor(base, ordinal)` so the core's GPU dim
|
|
195
|
+
* uniform can fade non-focused instances WITHOUT a marks recompile. `undefined`
|
|
196
|
+
* outside a mount (SSR / SVG export) → geoms skip tagging (no GPU emphasis).
|
|
197
|
+
* See {@link import("./emphasis.ts")}.
|
|
198
|
+
*/
|
|
199
|
+
emphasisBase?: number;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The active hover state surfaced to compile contexts and exposed on
|
|
204
|
+
* `MountedPlot.hovered`. Coordinates are absolute element-CSS pixels
|
|
205
|
+
* (matching `CompiledHitTest.positions`).
|
|
206
|
+
*/
|
|
207
|
+
export interface HoveredHit {
|
|
208
|
+
geomKind: GeomKind;
|
|
209
|
+
dataIndex: number;
|
|
210
|
+
/** Optional segment key for multi-series geoms (stacked/dodged bars, stacked areas). */
|
|
211
|
+
seriesKey?: string;
|
|
212
|
+
/**
|
|
213
|
+
* Reference to the data array used to compile the originating geom — used
|
|
214
|
+
* for identity comparison (`hovered.data === ctx.data`) so multi-layer
|
|
215
|
+
* charts can route the hit to the right geom.
|
|
216
|
+
*/
|
|
217
|
+
data: readonly unknown[];
|
|
218
|
+
x: number;
|
|
219
|
+
y: number;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Resolved aesthetics for each channel of a geom — used by interaction layers
|
|
224
|
+
* (tooltips, legends-on-hover) to read the original column name and pull the
|
|
225
|
+
* raw value back out for a given datum.
|
|
226
|
+
*/
|
|
227
|
+
export interface ResolvedChannelMap<T> {
|
|
228
|
+
x?: ResolvedAes<T, unknown>;
|
|
229
|
+
y?: ResolvedAes<T, unknown>;
|
|
230
|
+
color?: ResolvedAes<T, unknown>;
|
|
231
|
+
size?: ResolvedAes<T, unknown>;
|
|
232
|
+
shape?: ResolvedAes<T, unknown>;
|
|
233
|
+
alpha?: ResolvedAes<T, unknown>;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Hit-test points emitted by a geom for hover/click. Coordinates are absolute
|
|
238
|
+
* element-CSS pixels (the chart's plot frame offset is already baked in), so
|
|
239
|
+
* the consumer can hand them to a `space: "ui"` PointCloudNode without
|
|
240
|
+
* adjustment. `dataIndex[i]` maps hit `i` back to the original `data` array
|
|
241
|
+
* (after filtering NaN/null values). `seriesKey[i]` further distinguishes
|
|
242
|
+
* segments that share a source row.
|
|
243
|
+
*/
|
|
244
|
+
export interface CompiledHitTest<T> {
|
|
245
|
+
geomKind: GeomKind;
|
|
246
|
+
label?: string;
|
|
247
|
+
positions: Float32Array;
|
|
248
|
+
dataIndex: Int32Array;
|
|
249
|
+
seriesKey?: readonly (string | undefined)[];
|
|
250
|
+
pickRadius: number;
|
|
251
|
+
/**
|
|
252
|
+
* Optional per-hit bounding rect in absolute element-CSS pixels. When
|
|
253
|
+
* present, the hit-layer prefers rect containment over nearest-point
|
|
254
|
+
* picking (`positions` + `pickRadius`), giving "whole shape" hover for
|
|
255
|
+
* shape-based geoms (bar, histogram, ridgeline rows, tile cells, ...).
|
|
256
|
+
* Layout: `[x, y, w, h]` per `dataIndex` entry. `positions` is still
|
|
257
|
+
* required as a fallback (used to anchor tooltips, brushes, etc.).
|
|
258
|
+
*/
|
|
259
|
+
rects?: Float32Array;
|
|
260
|
+
/**
|
|
261
|
+
* Distance metric for nearest-point queries. Default `"xy"` (Euclidean).
|
|
262
|
+
* `"x"` makes the picker resolve nearest-by-x only — used by `line()` /
|
|
263
|
+
* `area()` when `nearestX: true` so the user can hover anywhere along the
|
|
264
|
+
* curve and the active vertex follows the cursor's x.
|
|
265
|
+
*/
|
|
266
|
+
pickAxis?: "x" | "y" | "xy";
|
|
267
|
+
channels: ResolvedChannelMap<T>;
|
|
268
|
+
data: readonly T[];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* A geom's hover-focus decoration, captured at compile time so the mount can
|
|
273
|
+
* draw it on hover **without recompiling the pipeline**. The mount calls
|
|
274
|
+
* {@link decorate} into the live overlay layer (which composites above the baked
|
|
275
|
+
* marks), so local focus treatment — a contrast halo, bringing the hovered
|
|
276
|
+
* element to the front — costs only a cheap overlay repaint rather than a full
|
|
277
|
+
* marks recompute. The complementary *global* dim-others treatment (fading every
|
|
278
|
+
* other element) rides the core's GPU emphasis uniform (see {@link
|
|
279
|
+
* EmphasisResolver}), so a geom can provide both: the decorator draws the focus
|
|
280
|
+
* halo (left at emphasis key 0 = exempt, full-strength) while the uniform dims
|
|
281
|
+
* the rest. Geoms with no local focus shape simply omit this.
|
|
282
|
+
*
|
|
283
|
+
* `geomKind` + `data` identity let the mount match the decorator to the active
|
|
284
|
+
* `HoveredHit` (the same keys used to route a hit to its geom).
|
|
285
|
+
*/
|
|
286
|
+
export interface GeomHoverDecorator {
|
|
287
|
+
readonly geomKind: GeomKind;
|
|
288
|
+
readonly data: readonly unknown[];
|
|
289
|
+
/** Draw the focus decoration for `hit` into `layer` (the overlay layer). */
|
|
290
|
+
decorate(hit: HoveredHit, layer: Layer): void;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export interface Geom<T> {
|
|
294
|
+
readonly kind: GeomKind;
|
|
295
|
+
readonly channels: ChannelSpec<T>;
|
|
296
|
+
/** Used by the auto-legend to label the layer. Falls back to channel name. */
|
|
297
|
+
readonly label?: string;
|
|
298
|
+
/** Optional position-scale hints (e.g. anchor value axis at 0 for bars). */
|
|
299
|
+
readonly scaleHints?: ScaleHints;
|
|
300
|
+
/**
|
|
301
|
+
* When true, the geom renders into the hud layer (above marks, no clip rect)
|
|
302
|
+
* instead of the marks layer. Used by geoms whose visual extent intentionally
|
|
303
|
+
* exceeds the plot frame — e.g. phylo tip labels — and that should not be
|
|
304
|
+
* clipped at the frame edge.
|
|
305
|
+
*/
|
|
306
|
+
readonly overlay?: boolean;
|
|
307
|
+
/**
|
|
308
|
+
* Optional data-derived scale hints. Called once before scales are built,
|
|
309
|
+
* so geoms whose visual extent depends on the data (e.g. KDE-smoothed
|
|
310
|
+
* violins) can extend the position-scale domain accordingly. Returned
|
|
311
|
+
* hints are merged with `scaleHints` and any hints contributed by other
|
|
312
|
+
* layers. An explicit `.scale(channel, { domain })` override always wins.
|
|
313
|
+
*/
|
|
314
|
+
prepareDomain?(data: readonly T[]): ScaleHints | undefined;
|
|
315
|
+
/**
|
|
316
|
+
* Optional layout-time hook that runs after layout but before scale
|
|
317
|
+
* construction. Geoms whose visual extent exceeds their data footprint
|
|
318
|
+
* — e.g. a ridgeline ridge that rises above its baseline by `overlap ×
|
|
319
|
+
* cellSize` — use this to reserve pixel margins on the plot frame, so
|
|
320
|
+
* the position scale (and its axis ticks) shrink to fit.
|
|
321
|
+
*/
|
|
322
|
+
prepareRange?(ctx: PrepareRangeContext<T>): RangeHints | undefined;
|
|
323
|
+
/**
|
|
324
|
+
* Optional override for the auto-legend's per-series swatch. Geoms that
|
|
325
|
+
* draw filled regions (bar/area/tile) or strokes (line) supply their own;
|
|
326
|
+
* the pipeline falls back to a point swatch when omitted.
|
|
327
|
+
*/
|
|
328
|
+
legendSwatch?(color: Color, theme: Theme): SwatchSpec;
|
|
329
|
+
compile(ctx: CompileContext<T>): readonly MarkBuilder[];
|
|
330
|
+
/**
|
|
331
|
+
* Optional hit-test contribution for interactions. Implemented per geom that
|
|
332
|
+
* wants to support hover/click selection (`point` in v1; bar/line/area in
|
|
333
|
+
* later phases). Return `null` to opt out for a particular compile pass
|
|
334
|
+
* (e.g. when the geom has no points after filtering).
|
|
335
|
+
*/
|
|
336
|
+
compileHitTest?(ctx: CompileContext<T>): CompiledHitTest<T> | null;
|
|
337
|
+
/**
|
|
338
|
+
* Optional hover-focus decorator. Implemented by geoms whose focus treatment
|
|
339
|
+
* is *local* (point: contrast halo + bring-to-front) so it can ride the
|
|
340
|
+
* mount's cheap overlay path instead of a marks recompute. Called once per
|
|
341
|
+
* full compile with the same `ctx`; returns `null` to opt out (e.g. empty
|
|
342
|
+
* data). See {@link GeomHoverDecorator}.
|
|
343
|
+
*/
|
|
344
|
+
hoverDecoration?(ctx: CompileContext<T>): GeomHoverDecorator | null;
|
|
345
|
+
/**
|
|
346
|
+
* Emphasis-key resolver for geoms whose hover treatment is *global* (dim the
|
|
347
|
+
* others via the core's GPU emphasis uniform: bar/line/violin/...). Captured
|
|
348
|
+
* once per full compile with the same `ctx` (so it sees the same `emphasisBase`
|
|
349
|
+
* + scales the tagging used); the mount maps an active {@link HoveredHit} to the
|
|
350
|
+
* namespaced key the geom tagged its focused instance(s) with — without
|
|
351
|
+
* recompiling. Returns `null` to opt out (e.g. empty data, or `emphasisBase`
|
|
352
|
+
* absent). Mutually complementary with {@link hoverDecoration} (local focus).
|
|
353
|
+
* See {@link import("./emphasis.ts").EmphasisResolver}.
|
|
354
|
+
*/
|
|
355
|
+
emphasisResolution?(ctx: CompileContext<T>): import("./emphasis.ts").EmphasisResolver | null;
|
|
356
|
+
/**
|
|
357
|
+
* Capture a per-datum channel snapshot for use as a transition "from" frame.
|
|
358
|
+
* Called after `compile` on each stable (non-animating) frame. Returns `null`
|
|
359
|
+
* if the geom has no meaningful frame to capture (e.g. empty data).
|
|
360
|
+
*/
|
|
361
|
+
captureFrame?(ctx: CompileContext<T>): GeomFrame | null;
|
|
362
|
+
}
|