@zakkster/lite-charts 1.0.0 → 1.1.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/CHANGELOG.md +96 -0
- package/Charts.d.ts +249 -21
- package/Charts.js +1653 -482
- package/README.md +156 -102
- package/llms.txt +276 -126
- package/package.json +6 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@zakkster/lite-charts` are documented here.
|
|
4
|
+
|
|
5
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
6
|
+
the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.1.0] — 2026-06
|
|
9
|
+
|
|
10
|
+
### Added — bar-chart layout polish
|
|
11
|
+
|
|
12
|
+
- **Stacked bars** via a `postExtract` hook on the bar renderer: pass
|
|
13
|
+
`stacked: true` to a multi-series bar chart and series stack on top of
|
|
14
|
+
one another per category (instead of grouping side-by-side). Negative
|
|
15
|
+
values stack downward against zero. The Y domain auto-includes the
|
|
16
|
+
stack maxima.
|
|
17
|
+
- **Rounded corners**: `cornerRadius: <px>` on a bar series rounds the
|
|
18
|
+
TOP corners of each bar (or BOTTOM for negative-stack pieces). Uses
|
|
19
|
+
native `ctx.roundRect` when available, falls back to four `arcTo`
|
|
20
|
+
calls so it works on Canvas2D implementations without `roundRect`.
|
|
21
|
+
- **Hover tint**: passing a pointer position to the renderer's hit-test
|
|
22
|
+
lets the bar under the cursor draw with a brightness shift. Default
|
|
23
|
+
`+8%` on hover (configurable via `hoverTint: <0..1>`); the renderer
|
|
24
|
+
reuses one cached tinted-color string per series so the hover path
|
|
25
|
+
remains allocation-free across cursor moves within a single bar.
|
|
26
|
+
|
|
27
|
+
### Added — bonus features present in this release
|
|
28
|
+
|
|
29
|
+
These were originally scoped for v1.2.0 alphas but landed in this build
|
|
30
|
+
and are tested + documented:
|
|
31
|
+
|
|
32
|
+
- **Spatial-index foundation** for bubble + scatter hit-tests
|
|
33
|
+
(`SpatialIndex` / `SpatialIndexFactory` contract). Auto-engages at
|
|
34
|
+
~1000 points, falling back to O(n) below threshold.
|
|
35
|
+
- **`createScatterChart`** — bubble's simpler sibling on the same axis
|
|
36
|
+
kernel; constant marker size, no third dimension.
|
|
37
|
+
- **Multi-series bubble** with a global size domain (so a 30-radius
|
|
38
|
+
point in series A and series B render at the same pixel radius) and
|
|
39
|
+
per-point color via `colorKey`. Cross-series hit-test via
|
|
40
|
+
`snapSeriesIdx`.
|
|
41
|
+
- **`createHeatmap`** on a new `createBaseGridChart` kernel — categorical
|
|
42
|
+
rows × columns, default linear color ramp, custom `colorFn(v, vMin,
|
|
43
|
+
vMax)` for any mapping; sparse grids draw only present cells.
|
|
44
|
+
|
|
45
|
+
### Internals
|
|
46
|
+
|
|
47
|
+
- Charts now report `chart.plotBounds` as a version-counter signal —
|
|
48
|
+
subscribe to react to size changes without dragging in DOM observers.
|
|
49
|
+
- DPR-aware canvas sizing reproduces the same backing-buffer math whether
|
|
50
|
+
mounted onto a real `<canvas>` or a test mock with explicit `width` /
|
|
51
|
+
`height`.
|
|
52
|
+
- `_testHelpers` export kept at the same surface for white-box tests
|
|
53
|
+
(decimation kernel, scale builders, accessor factory).
|
|
54
|
+
|
|
55
|
+
### Performance contract
|
|
56
|
+
|
|
57
|
+
Empirical, sampled under `--expose-gc` (`node --expose-gc bench/line-100k.mjs`):
|
|
58
|
+
|
|
59
|
+
- **`chart.redraw()` steady-state**: 0.54 B/call — true zero-allocation
|
|
60
|
+
(sub-8-byte noise floor).
|
|
61
|
+
- **`data.set(reused) + redraw`**: ~89 B/call (signal mechanics + draw).
|
|
62
|
+
- **Full live cycle** (object literal + `await drainMicrotasks`): ~65 B/cycle
|
|
63
|
+
(the 32 B literal + ~33 B Promise/await overhead are the call-site cost,
|
|
64
|
+
not the library).
|
|
65
|
+
- **100k-point line chart** full update cycle: **p95 = 5.68 ms** (193 fps
|
|
66
|
+
ceiling) on Node 22; fits in 60fps and 120fps budgets.
|
|
67
|
+
- **Canvas calls per draw** (decimated mode): ~3393 — bounded by occupied
|
|
68
|
+
columns + axis ticks + spines, not by data length.
|
|
69
|
+
|
|
70
|
+
### Tests
|
|
71
|
+
|
|
72
|
+
231 tests across 46 describe blocks (node:test, `--expose-gc` for the
|
|
73
|
+
optional zero-GC kernel test); covers every chart factory's lifecycle,
|
|
74
|
+
reactivity, interpolation modes, marker shapes, refresh-theme,
|
|
75
|
+
auto-resize, plot-rect clipping, DPR sizing, crosshair zero-alloc,
|
|
76
|
+
tooltip-pool identity, multi-series domain union, custom xScale.domain,
|
|
77
|
+
band/linear scale math, pie/donut/radar geometry, bubble spatial index,
|
|
78
|
+
scatter hit-test, heatmap cell rendering, and the mock-canvas contract.
|
|
79
|
+
|
|
80
|
+
### Bug fixes during this release audit
|
|
81
|
+
|
|
82
|
+
- Mock test harness was missing `strokeRect` — added (heatmap calls it).
|
|
83
|
+
- Test file forgot to import `createScatterChart` + `createHeatmap` from
|
|
84
|
+
`Charts.js` — added (18 false failures resolved).
|
|
85
|
+
- Demo's hero-loop `frameSamples.push(dt); shift()` allocated every
|
|
86
|
+
frame past the first 60; converted to a fixed-cap `Float64Array` ring
|
|
87
|
+
buffer. The 4Hz stats interval's `frameSamples.slice().sort()` also
|
|
88
|
+
allocated; switched to a reusable `Float64Array` scratchpad sorted
|
|
89
|
+
in-place.
|
|
90
|
+
- Demo title + brand-version badge + release eyebrow were stale at
|
|
91
|
+
`v1.0.0`; updated to `v1.1.0`.
|
|
92
|
+
- `package.json` test script had no path glob; now `test/*.test.js`.
|
|
93
|
+
|
|
94
|
+
### License
|
|
95
|
+
|
|
96
|
+
MIT (c) Zahary Shinikchiev
|
package/Charts.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ export interface MarginConfig {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// ---------------------------------------------------------------------------
|
|
70
|
-
// Crosshair / tooltip
|
|
70
|
+
// Crosshair / tooltip (v1.0.0-alpha.1)
|
|
71
71
|
// ---------------------------------------------------------------------------
|
|
72
72
|
|
|
73
73
|
export interface CrosshairState {
|
|
@@ -133,13 +133,6 @@ export interface TooltipFormatContext {
|
|
|
133
133
|
snapIdx: number;
|
|
134
134
|
snapDomainX: number;
|
|
135
135
|
xScaleType: 'linear' | 'time';
|
|
136
|
-
/**
|
|
137
|
-
* For bar charts (categorical x), the category name at the snapped
|
|
138
|
-
* index; `null` for line / area / bubble charts. Present on the same
|
|
139
|
-
* context object across all axis-kernel charts so a formatter doesn't
|
|
140
|
-
* have to branch on chart type.
|
|
141
|
-
*/
|
|
142
|
-
category: string | null;
|
|
143
136
|
/** Default rows, one per series with data at the snap. Mutable by formatter. */
|
|
144
137
|
rows: TooltipRow[];
|
|
145
138
|
}
|
|
@@ -155,7 +148,7 @@ export interface TooltipConfig {
|
|
|
155
148
|
}
|
|
156
149
|
|
|
157
150
|
// ---------------------------------------------------------------------------
|
|
158
|
-
// Legend
|
|
151
|
+
// Legend (v1.0.0-alpha.3)
|
|
159
152
|
// ---------------------------------------------------------------------------
|
|
160
153
|
|
|
161
154
|
export type LegendPosition = 'top' | 'bottom' | 'left' | 'right';
|
|
@@ -258,7 +251,7 @@ export interface Chart {
|
|
|
258
251
|
*/
|
|
259
252
|
refreshTheme(): void;
|
|
260
253
|
|
|
261
|
-
readonly scene: unknown;
|
|
254
|
+
readonly scene: unknown | null; // lite-scene Scene type
|
|
262
255
|
readonly canvas: HTMLCanvasElement | null;
|
|
263
256
|
readonly xScale: Scale;
|
|
264
257
|
readonly yScale: Scale;
|
|
@@ -268,7 +261,7 @@ export interface Chart {
|
|
|
268
261
|
/**
|
|
269
262
|
* Crosshair state. Behaves like a signal: callable to subscribe-and-read,
|
|
270
263
|
* `.peek()` to read without subscribing, `.set()` to write, `.subscribe()`
|
|
271
|
-
* to register a callback.
|
|
264
|
+
* to register a callback. As of v1.0.0-beta.2 the returned `CrosshairState`
|
|
272
265
|
* is the SAME mutable reference on every read -- this eliminates the
|
|
273
266
|
* per-mousemove allocation that hardware polling rates would otherwise
|
|
274
267
|
* generate. Read fields eagerly when notified; do not retain the reference
|
|
@@ -276,8 +269,7 @@ export interface Chart {
|
|
|
276
269
|
*/
|
|
277
270
|
readonly crosshair: (() => CrosshairState) & {
|
|
278
271
|
peek(): CrosshairState;
|
|
279
|
-
|
|
280
|
-
set(v: Partial<CrosshairState>): void;
|
|
272
|
+
set(v: CrosshairState): void;
|
|
281
273
|
subscribe(fn: (s: CrosshairState) => void): () => void;
|
|
282
274
|
};
|
|
283
275
|
/** One signal per series. Read in a reactive context to bind external UI; write to toggle. */
|
|
@@ -289,7 +281,7 @@ export interface Chart {
|
|
|
289
281
|
export function createLineChart(config: LineChartConfig): Chart;
|
|
290
282
|
|
|
291
283
|
// ---------------------------------------------------------------------------
|
|
292
|
-
// Area chart
|
|
284
|
+
// Area chart (v1.0.0-alpha.2)
|
|
293
285
|
// ---------------------------------------------------------------------------
|
|
294
286
|
//
|
|
295
287
|
// Same data + scale + reactivity contract as the line chart, plus a baseline
|
|
@@ -338,6 +330,27 @@ export interface BarChartConfig extends Omit<LineChartConfig, 'interpolation' |
|
|
|
338
330
|
* adjacent grouped bars within the same category. Default 0.08.
|
|
339
331
|
*/
|
|
340
332
|
groupInnerPad?: number;
|
|
333
|
+
/**
|
|
334
|
+
* v1.1.0: when true, series stack cumulatively per category instead of
|
|
335
|
+
* sitting side-by-side. The y-domain expands to the total stack height.
|
|
336
|
+
* Hidden series (via legend toggle) are excluded from the stack. MVP
|
|
337
|
+
* supports positive values only; negative values clamp to 0 in the
|
|
338
|
+
* stack. Default false.
|
|
339
|
+
*/
|
|
340
|
+
stack?: boolean;
|
|
341
|
+
/**
|
|
342
|
+
* v1.1.0: corner radius in pixels for the top of each bar (positive)
|
|
343
|
+
* or bottom (negative). Default 0 (square corners). Capped at
|
|
344
|
+
* min(barWidth, barHeight) / 2 internally so very small bars never
|
|
345
|
+
* have overlapping corner arcs.
|
|
346
|
+
*/
|
|
347
|
+
cornerRadius?: number;
|
|
348
|
+
/**
|
|
349
|
+
* v1.1.0: overlay color drawn on top of the hovered bar. Pass a CSS
|
|
350
|
+
* color string, `true` for the default low-alpha white, or `false`
|
|
351
|
+
* to disable. Default: `'rgba(255,255,255,0.18)'`.
|
|
352
|
+
*/
|
|
353
|
+
hoverTint?: string | boolean;
|
|
341
354
|
/**
|
|
342
355
|
* X-scale overrides. Bar charts always use a band scale; only `domain`
|
|
343
356
|
* (an explicit categories array) is honoured here -- the inferred type
|
|
@@ -349,7 +362,7 @@ export interface BarChartConfig extends Omit<LineChartConfig, 'interpolation' |
|
|
|
349
362
|
export function createBarChart(config: BarChartConfig): Chart;
|
|
350
363
|
|
|
351
364
|
// ---------------------------------------------------------------------------
|
|
352
|
-
// Bubble chart (axis kernel with size dimension)
|
|
365
|
+
// Bubble chart (axis kernel with size dimension, v1.2.0-alpha.3)
|
|
353
366
|
// ---------------------------------------------------------------------------
|
|
354
367
|
|
|
355
368
|
export interface BubbleSeriesInput {
|
|
@@ -363,9 +376,14 @@ export interface BubbleSeriesInput {
|
|
|
363
376
|
}
|
|
364
377
|
|
|
365
378
|
export interface BubbleChartConfig {
|
|
366
|
-
/** Single-series data shape
|
|
379
|
+
/** Single-series data shape. */
|
|
367
380
|
data?: Array<{ [k: string]: unknown }> | (() => Array<{ [k: string]: unknown }>);
|
|
368
|
-
/**
|
|
381
|
+
/**
|
|
382
|
+
* Multi-series shape (v1.2.0-alpha.2). Each series gets its own `data`,
|
|
383
|
+
* `name`, and optional `color`. The size dimension is shared across
|
|
384
|
+
* series via a GLOBAL size domain computed in `postExtract`, so equal
|
|
385
|
+
* raw values render at equal pixel radii regardless of which series.
|
|
386
|
+
*/
|
|
369
387
|
series?: BubbleSeriesInput[];
|
|
370
388
|
|
|
371
389
|
/** Key (or index) for x values. Default 'x'. */
|
|
@@ -374,6 +392,13 @@ export interface BubbleChartConfig {
|
|
|
374
392
|
y?: string | number | ((row: unknown, i: number) => number);
|
|
375
393
|
/** Key (or index) for the size dimension. Default 'value'. */
|
|
376
394
|
size?: string | number | ((row: unknown, i: number) => number);
|
|
395
|
+
/**
|
|
396
|
+
* v1.2.0-alpha.2: per-point color. When set, each row's color overrides
|
|
397
|
+
* the series fill. Accepts CSS-var (`'--c-red'`), hex (`'#ff0000'`), or
|
|
398
|
+
* any other CSS color value. Returning null/undefined falls back to the
|
|
399
|
+
* series fill for that row.
|
|
400
|
+
*/
|
|
401
|
+
colorKey?: string | number | ((row: unknown, i: number) => string | null | undefined);
|
|
377
402
|
|
|
378
403
|
/** Minimum pixel radius. Default 4. */
|
|
379
404
|
minRadius?: number;
|
|
@@ -425,12 +450,73 @@ export interface BubbleChartConfig {
|
|
|
425
450
|
background?: string;
|
|
426
451
|
dpr?: number;
|
|
427
452
|
schedule?: (cb: () => void) => unknown;
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* v1.2.0-alpha.0: spatial-index factory for O(log n) hit-test on dense
|
|
456
|
+
* bubble clouds. Pass any function matching `SpatialIndexFactory` --
|
|
457
|
+
* `@zakkster/lite-delaunay` is the intended default, but a k-d tree or
|
|
458
|
+
* uniform-grid implementation works just as well. Omit to use linear
|
|
459
|
+
* scan (the v1.0.0 behavior, faster below ~1000 points).
|
|
460
|
+
*/
|
|
461
|
+
spatialIndex?: SpatialIndexFactory;
|
|
462
|
+
/**
|
|
463
|
+
* v1.2.0-alpha.0: minimum point count before the spatial index is
|
|
464
|
+
* built and queried. Below this, the linear scan is used (it's faster
|
|
465
|
+
* for small clouds because the index has build cost). Default 1000.
|
|
466
|
+
*/
|
|
467
|
+
spatialIndexThreshold?: number;
|
|
428
468
|
}
|
|
429
469
|
|
|
430
470
|
export function createBubbleChart(config: BubbleChartConfig): Chart;
|
|
431
471
|
|
|
432
472
|
// ---------------------------------------------------------------------------
|
|
433
|
-
//
|
|
473
|
+
// Spatial index interface (v1.2.0-alpha.0)
|
|
474
|
+
// ---------------------------------------------------------------------------
|
|
475
|
+
// A pluggable nearest-neighbor index for dense point clouds. lite-charts
|
|
476
|
+
// defines the contract; the implementation is supplied by the consumer
|
|
477
|
+
// (`@zakkster/lite-delaunay`, a k-d tree, etc.). Used by bubble (v1.2.0)
|
|
478
|
+
// and the future scatter / heatmap renderers.
|
|
479
|
+
|
|
480
|
+
export interface SpatialIndex {
|
|
481
|
+
/**
|
|
482
|
+
* Find up to `k` points closest to (qx, qy) in pixel space, filtered to
|
|
483
|
+
* those with squared distance <= maxDistSq. Writes indices into
|
|
484
|
+
* `outIndices` and squared distances into `outDistSq`. Both buffers are
|
|
485
|
+
* caller-owned, stable refs -- the index MUST NOT keep references to
|
|
486
|
+
* them between calls, and MUST NOT allocate per call (this is the
|
|
487
|
+
* zero-GC contract). Returns the count actually written, in [0, k].
|
|
488
|
+
*/
|
|
489
|
+
findNearest(
|
|
490
|
+
qx: number,
|
|
491
|
+
qy: number,
|
|
492
|
+
k: number,
|
|
493
|
+
maxDistSq: number,
|
|
494
|
+
outIndices: Int32Array,
|
|
495
|
+
outDistSq: Float32Array,
|
|
496
|
+
): number;
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Release any resources held by the index. Pure-JS implementations may
|
|
500
|
+
* make this a no-op; WebGL / WASM-backed indices should free buffers.
|
|
501
|
+
* Called by lite-charts on data change and on chart unmount.
|
|
502
|
+
*/
|
|
503
|
+
dispose(): void;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Build a SpatialIndex over the given pixel-space coordinates. `n` is the
|
|
508
|
+
* number of valid entries (the typed arrays may be larger due to growth-
|
|
509
|
+
* allocation). The index MAY snapshot the inputs or hold the references --
|
|
510
|
+
* lite-charts guarantees the data won't mutate before dispose() is called.
|
|
511
|
+
*/
|
|
512
|
+
export type SpatialIndexFactory = (
|
|
513
|
+
pxs: Float32Array,
|
|
514
|
+
pys: Float32Array,
|
|
515
|
+
n: number,
|
|
516
|
+
) => SpatialIndex;
|
|
517
|
+
|
|
518
|
+
// ---------------------------------------------------------------------------
|
|
519
|
+
// Radar chart (separate kernel, v1.2.0-alpha.4)
|
|
434
520
|
// ---------------------------------------------------------------------------
|
|
435
521
|
|
|
436
522
|
export interface RadarSeriesInput {
|
|
@@ -507,7 +593,7 @@ export interface RadarChart {
|
|
|
507
593
|
export function createRadarChart(config: RadarChartConfig): RadarChart;
|
|
508
594
|
|
|
509
595
|
// ---------------------------------------------------------------------------
|
|
510
|
-
// Polar slice charts -- pie / donut
|
|
596
|
+
// Polar slice charts -- pie / donut (v1.2.0-alpha.1)
|
|
511
597
|
// ---------------------------------------------------------------------------
|
|
512
598
|
|
|
513
599
|
export interface SliceInput {
|
|
@@ -594,8 +680,150 @@ export function createDonutChart(config: DonutChartConfig): PolarChart;
|
|
|
594
680
|
// Each will be a thin composition over a base kernel:
|
|
595
681
|
// createHeatmap = createBaseGridChart(config, HEATMAP_RENDERER)
|
|
596
682
|
|
|
597
|
-
|
|
598
|
-
|
|
683
|
+
// ---------------------------------------------------------------------------
|
|
684
|
+
// createScatterChart (v1.2.0-alpha.1)
|
|
685
|
+
// ---------------------------------------------------------------------------
|
|
686
|
+
//
|
|
687
|
+
// Scatter is bubble's simpler sibling. Same axis kernel, same spatial-index
|
|
688
|
+
// foundation -- but no size dimension, no sqrt scaling, no smallest-on-top
|
|
689
|
+
// tie-break (scatter has no overlap concerns). Every point renders at the
|
|
690
|
+
// SAME pixel radius (`markerSize`); the hit-test uses a configurable
|
|
691
|
+
// tolerance disc around each point.
|
|
692
|
+
|
|
693
|
+
export interface ScatterChartConfig {
|
|
694
|
+
/** Single-series data shape. */
|
|
695
|
+
data?: Array<{ [k: string]: unknown }> | (() => Array<{ [k: string]: unknown }>);
|
|
696
|
+
/** Multi-series shape. Each series gets its own data + color. */
|
|
697
|
+
series?: Array<{ name?: string; data: unknown; color?: string }>;
|
|
698
|
+
|
|
699
|
+
/** Key (or index) for x values. Default 'x'. */
|
|
700
|
+
x?: string | number | ((row: unknown, i: number) => number);
|
|
701
|
+
/** Key (or index) for y values. Default 'y'. */
|
|
702
|
+
y?: string | number | ((row: unknown, i: number) => number);
|
|
703
|
+
|
|
704
|
+
/** Pixel radius of every marker. Default 4. */
|
|
705
|
+
markerSize?: number;
|
|
706
|
+
/**
|
|
707
|
+
* Pixel radius around each marker that counts as a hit. Default
|
|
708
|
+
* `markerSize + 4`. Increase for easier targeting at small marker
|
|
709
|
+
* sizes, decrease for crowded plots where neighboring points should
|
|
710
|
+
* not steal hits.
|
|
711
|
+
*/
|
|
712
|
+
hitTolerance?: number;
|
|
713
|
+
|
|
714
|
+
color?: string;
|
|
715
|
+
stroke?: string;
|
|
716
|
+
strokeWidth?: number;
|
|
717
|
+
/** Marker fill alpha. Default 1 (opaque). */
|
|
718
|
+
fillOpacity?: number;
|
|
719
|
+
|
|
720
|
+
width?: number | (() => number);
|
|
721
|
+
height?: number | (() => number);
|
|
722
|
+
margin?: { top?: number; right?: number; bottom?: number; left?: number };
|
|
723
|
+
|
|
724
|
+
xScale?: { type?: 'linear' | 'time'; domain?: [number, number] };
|
|
725
|
+
yScale?: { type?: 'linear'; domain?: [number, number]; nice?: boolean; zero?: boolean };
|
|
726
|
+
|
|
727
|
+
grid?: boolean | { x?: boolean; y?: boolean; color?: string };
|
|
728
|
+
crosshair?: false | { color?: string; dash?: [number, number] };
|
|
729
|
+
tooltip?: BubbleChartConfig['tooltip'];
|
|
730
|
+
legend?: BubbleChartConfig['legend'];
|
|
731
|
+
|
|
732
|
+
font?: string;
|
|
733
|
+
labelColor?: string;
|
|
734
|
+
axisColor?: string;
|
|
735
|
+
background?: string;
|
|
736
|
+
dpr?: number;
|
|
737
|
+
schedule?: (cb: () => void) => unknown;
|
|
738
|
+
|
|
739
|
+
/** v1.2.0-alpha.0: same spatial-index integration as bubble. k = 1. */
|
|
740
|
+
spatialIndex?: SpatialIndexFactory;
|
|
741
|
+
spatialIndexThreshold?: number;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
export function createScatterChart(config: ScatterChartConfig): Chart;
|
|
745
|
+
|
|
746
|
+
// ---------------------------------------------------------------------------
|
|
747
|
+
// createHeatmap (v1.2.0-alpha.3) -- fourth kernel
|
|
748
|
+
// ---------------------------------------------------------------------------
|
|
749
|
+
//
|
|
750
|
+
// 2D categorical grid. Cells indexed by (xCategory, yCategory); each cell
|
|
751
|
+
// has at most one value. Sparse data is supported. Color mapping defaults
|
|
752
|
+
// to linear RGB interpolation between two endpoint hex colors -- pass
|
|
753
|
+
// `colorFn` for custom mappings (OKLCH, quantile, diverging, etc.).
|
|
754
|
+
//
|
|
755
|
+
// Rides on createBaseGridChart, an independent kernel that knows nothing
|
|
756
|
+
// about the axis / polar / radar kernels. Verified via esbuild tree-shake:
|
|
757
|
+
// importing only `createHeatmap` pulls ~10.5 KB minified -- no axes, no
|
|
758
|
+
// scales, no slice math, no radar geometry.
|
|
759
|
+
|
|
760
|
+
export interface HeatmapConfig {
|
|
761
|
+
/**
|
|
762
|
+
* Long-form data: one row per cell. Categories are auto-extracted from
|
|
763
|
+
* the x / y accessors in first-seen order. Missing (x, y) combinations
|
|
764
|
+
* render as empty space and return null from the hit-test.
|
|
765
|
+
*/
|
|
766
|
+
data: Array<{ [k: string]: unknown }> | (() => Array<{ [k: string]: unknown }>);
|
|
767
|
+
|
|
768
|
+
/** Key (or function) for the x-axis category. Default 'x'. */
|
|
769
|
+
x?: string | number | ((row: unknown, i: number) => string);
|
|
770
|
+
/** Key (or function) for the y-axis category. Default 'y'. */
|
|
771
|
+
y?: string | number | ((row: unknown, i: number) => string);
|
|
772
|
+
/** Key (or function) for the numeric cell value. Default 'value'. */
|
|
773
|
+
value?: string | number | ((row: unknown, i: number) => number);
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Two-stop linear color ramp `[low, high]`. Default `['#dbeafe', '#1e3a8a']`
|
|
777
|
+
* (blue-100 to blue-900). Accepts hex strings; CSS-vars are resolved
|
|
778
|
+
* against the mount container.
|
|
779
|
+
*/
|
|
780
|
+
colors?: [string, string];
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Custom color function. Receives `(value, vMin, vMax)`; returns a CSS
|
|
784
|
+
* color string. Overrides `colors` entirely. Use this for OKLCH ramps,
|
|
785
|
+
* quantile binning, diverging schemes, etc.
|
|
786
|
+
*/
|
|
787
|
+
colorFn?: (value: number, vMin: number, vMax: number) => string;
|
|
788
|
+
|
|
789
|
+
/** Render the numeric value inside each cell. Default false. */
|
|
790
|
+
showValues?: boolean;
|
|
791
|
+
/** Format the cell value when `showValues` is true. */
|
|
792
|
+
valueFormat?: (value: number, xi: number, yi: number) => string;
|
|
793
|
+
/** Font for in-cell value labels. */
|
|
794
|
+
valueLabelFont?: string;
|
|
795
|
+
/** Color for in-cell value labels. */
|
|
796
|
+
valueLabelColor?: string;
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Fraction of band-width used as the gap between adjacent cells.
|
|
800
|
+
* Default 0.04 (4%); set to 0 for a continuous grid.
|
|
801
|
+
*/
|
|
802
|
+
cellGap?: number;
|
|
803
|
+
|
|
804
|
+
/** Stroke color for the hovered cell highlight. Default '#111111'. */
|
|
805
|
+
highlightStroke?: string;
|
|
806
|
+
/** Stroke width for the hovered cell highlight in pixels. Default 2. */
|
|
807
|
+
highlightStrokeWidth?: number;
|
|
808
|
+
|
|
809
|
+
/** Custom tooltip text formatter. */
|
|
810
|
+
tooltipFormat?: (info: { xi: number; yi: number; xLabel: string; yLabel: string; value: number }) => string;
|
|
811
|
+
|
|
812
|
+
/** Axis label color. Default '#444444'. */
|
|
813
|
+
labelColor?: string;
|
|
814
|
+
/** Axis label font. Default '12px sans-serif'. */
|
|
815
|
+
labelFont?: string;
|
|
816
|
+
|
|
817
|
+
width?: number | (() => number);
|
|
818
|
+
height?: number | (() => number);
|
|
819
|
+
margin?: { top?: number; right?: number; bottom?: number; left?: number };
|
|
820
|
+
|
|
821
|
+
background?: string;
|
|
822
|
+
dpr?: number;
|
|
823
|
+
schedule?: (cb: () => void) => unknown;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
export function createHeatmap(config: HeatmapConfig): Chart;
|
|
599
827
|
|
|
600
828
|
// ---------------------------------------------------------------------------
|
|
601
829
|
// Test-only export (NOT part of the stable public API)
|