@jarenjs/charts 0.34.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 (56) hide show
  1. package/README.md +293 -0
  2. package/dist/types/component/index.d.ts +95 -0
  3. package/dist/types/core/axis.d.ts +77 -0
  4. package/dist/types/core/cartesian.d.ts +127 -0
  5. package/dist/types/core/chart.d.ts +58 -0
  6. package/dist/types/core/domain.d.ts +96 -0
  7. package/dist/types/core/marks.d.ts +86 -0
  8. package/dist/types/core/palette.d.ts +72 -0
  9. package/dist/types/core/scale.d.ts +59 -0
  10. package/dist/types/core/session.d.ts +85 -0
  11. package/dist/types/core/stream-adapter.d.ts +187 -0
  12. package/dist/types/index.d.ts +35 -0
  13. package/dist/types/transforms/benchmark-adapter.d.ts +169 -0
  14. package/dist/types/transforms/mermaid-adapter.d.ts +30 -0
  15. package/dist/types/types/bar.d.ts +213 -0
  16. package/dist/types/types/boxplot.d.ts +116 -0
  17. package/dist/types/types/candlestick.d.ts +218 -0
  18. package/dist/types/types/gauge.d.ts +68 -0
  19. package/dist/types/types/heatmap.d.ts +104 -0
  20. package/dist/types/types/line.d.ts +272 -0
  21. package/dist/types/types/map.d.ts +137 -0
  22. package/dist/types/types/pie.d.ts +146 -0
  23. package/dist/types/types/radar.d.ts +89 -0
  24. package/dist/types/types/sankey.d.ts +100 -0
  25. package/dist/types/types/scatter.d.ts +80 -0
  26. package/dist/types/types/streamgraph.d.ts +75 -0
  27. package/dist/types/types/treemap.d.ts +118 -0
  28. package/package.json +76 -0
  29. package/schemas/chart-definition.schema.json +448 -0
  30. package/src/component/index.js +125 -0
  31. package/src/core/axis.js +221 -0
  32. package/src/core/cartesian.js +192 -0
  33. package/src/core/chart.js +101 -0
  34. package/src/core/domain.js +123 -0
  35. package/src/core/marks.js +110 -0
  36. package/src/core/palette.js +126 -0
  37. package/src/core/scale.js +106 -0
  38. package/src/core/session.js +0 -0
  39. package/src/core/stream-adapter.js +613 -0
  40. package/src/index.js +40 -0
  41. package/src/transforms/benchmark-adapter.js +298 -0
  42. package/src/transforms/mermaid-adapter.js +19 -0
  43. package/src/types/bar.js +276 -0
  44. package/src/types/boxplot.js +216 -0
  45. package/src/types/candlestick.js +274 -0
  46. package/src/types/gauge.js +140 -0
  47. package/src/types/heatmap.js +176 -0
  48. package/src/types/line.js +349 -0
  49. package/src/types/map.js +378 -0
  50. package/src/types/pie.js +163 -0
  51. package/src/types/radar.js +224 -0
  52. package/src/types/sankey.js +391 -0
  53. package/src/types/scatter.js +148 -0
  54. package/src/types/streamgraph.js +158 -0
  55. package/src/types/treemap.js +322 -0
  56. package/styles/charts.css +83 -0
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @file Domain-stability policies for the streaming chart types. A
3
+ * unit-space AST stores every position as a fraction of its domain, so
4
+ * a tick that moves the domain legitimately changes every mark — a
5
+ * wholesale re-render is then correct. These policies exist so that
6
+ * most streaming ticks do NOT move the domain, which is what makes
7
+ * incremental re-render (the chart session) possible:
8
+ *
9
+ * - `x: { window, slide? }` — sliding x window of fixed span `window`,
10
+ * whose END is quantized to multiples of `slide` (default a quarter
11
+ * window). The domain therefore moves once per `slide` of x
12
+ * progress, not once per sample; samples older than the window are
13
+ * dropped from the plot.
14
+ * - `y: { min?, max? }` — pinned value bounds; samples beyond them
15
+ * clamp to the plot edge (the render's clamp01 already does this).
16
+ * - `y: 'step'` — hysteresis by quantization: the value domain snaps
17
+ * outward to nice-number multiples (decades under a log axis), so it
18
+ * changes only when a sample crosses a step boundary.
19
+ *
20
+ * All resolution is pure — policies are declared in the config and
21
+ * resolved from the data extremes on every build; stability comes from
22
+ * quantization, not hidden state.
23
+ */
24
+ export type DomainPolicy = {
25
+ /**
26
+ * sliding x span (null = none)
27
+ */
28
+ window: number | null;
29
+ /**
30
+ * window end quantum (null = window/4)
31
+ */
32
+ slide: number | null;
33
+ /**
34
+ * pinned y bounds
35
+ */
36
+ pin: {
37
+ min: number | null;
38
+ max: number | null;
39
+ } | null;
40
+ /**
41
+ * quantized y domain
42
+ */
43
+ step: boolean;
44
+ };
45
+ /**
46
+ * @typedef {object} DomainPolicy
47
+ * @property {number|null} window sliding x span (null = none)
48
+ * @property {number|null} slide window end quantum (null = window/4)
49
+ * @property {{min: number|null, max: number|null}|null} pin pinned y bounds
50
+ * @property {boolean} step quantized y domain
51
+ */
52
+ /**
53
+ * Normalize a config `domain` member into a policy object; hostile or
54
+ * absent input yields the all-null policy (today's behavior).
55
+ * @param {any} domain the config `domain` member
56
+ * @returns {DomainPolicy}
57
+ */
58
+ export declare function normalizeDomainPolicy(domain: any): DomainPolicy;
59
+ /**
60
+ * Resolve the windowed x domain `[end - window, end]`: the end is the
61
+ * smallest multiple of the slide quantum at or above the newest sample,
62
+ * so it moves once per quantum, not once per sample.
63
+ * @param {number} xMax newest x in the data (non-finite = empty data)
64
+ * @param {number} window the window span (> 0)
65
+ * @param {number|null} slide the end quantum (null = window / 4)
66
+ * @returns {[number, number]}
67
+ */
68
+ export declare function resolveWindowX(xMax: number, window: number, slide: number | null): [number, number];
69
+ /**
70
+ * Resolve the quantized (`'step'`) y domain: extremes snapped outward
71
+ * to multiples of a nice step of the span, so small new extremes
72
+ * usually land inside the current domain.
73
+ * @param {number} yMin @param {number} yMax data extremes (finite)
74
+ * @returns {[number, number]}
75
+ */
76
+ export declare function resolveStepY(yMin: number, yMax: number): [number, number];
77
+ /**
78
+ * Resolve the quantized y domain under a log axis: decade bounds
79
+ * (`10^floor` / `10^ceil`), the log counterpart of {@link resolveStepY}.
80
+ * @param {number} yMin @param {number} yMax data extremes (> 0)
81
+ * @returns {[number, number]}
82
+ */
83
+ export declare function resolveStepYLog(yMin: number, yMax: number): [number, number];
84
+ /**
85
+ * Resolve pinned y bounds over the data extremes. Under a log axis a
86
+ * non-positive pin is ignored (a hostile pin never breaks the scale);
87
+ * a pin pair that closes the domain falls back to the data extremes.
88
+ * @param {number} yMin @param {number} yMax data extremes
89
+ * @param {{min: number|null, max: number|null}} pin
90
+ * @param {boolean} log
91
+ * @returns {[number, number]}
92
+ */
93
+ export declare function resolvePinnedY(yMin: number, yMax: number, pin: {
94
+ min: number | null;
95
+ max: number | null;
96
+ }, log: boolean): [number, number];
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @file Value marks — the two things every value-carrying mark carries.
3
+ *
4
+ * 1. A `<title>` child holding the mark's hover text. Native SSR-safe
5
+ * hover: it works in a static `toSvgString()` document with no
6
+ * script, no CSS and no app, which is why it is unconditional.
7
+ * 2. Opt-in pointer **bindings** (`on`, VIEW-FORMAT §4) for a host that
8
+ * wants a positioned floating tooltip instead. Bindings are plain
9
+ * JSON built at render time, so the engine stays pure — it names an
10
+ * action, it never calls one — and `renderToString` drops `on`
11
+ * entirely, so the SSR bytes are the same either way.
12
+ *
13
+ * The binding's `with` payload is the mark descriptor: its `text` (the
14
+ * same string the `<title>` carries, so a host needs nothing else to
15
+ * draw a box) plus whatever identifies the mark for a richer host.
16
+ */
17
+ export type ChartTooltipSpec = {
18
+ /**
19
+ * action dispatched when the pointer enters a mark
20
+ */
21
+ action: string;
22
+ /**
23
+ * action dispatched when it leaves
24
+ */
25
+ leaveAction?: string;
26
+ /**
27
+ * enter event name (default `'pointerenter'`)
28
+ */
29
+ enter?: string;
30
+ /**
31
+ * leave event name (default `'pointerleave'`)
32
+ */
33
+ leave?: string;
34
+ /**
35
+ * `$event` fields to request (default
36
+ * `['clientX', 'clientY']` — what a floating box needs to position itself)
37
+ */
38
+ event?: string[];
39
+ };
40
+ export type ChartTooltip = {
41
+ action: string;
42
+ leaveAction: string | null;
43
+ enter: string;
44
+ leave: string;
45
+ event: string[];
46
+ };
47
+ /**
48
+ * Resolve a tooltip spec. Anything that does not name an action
49
+ * resolves to `null` — bindings off, `<title>` hover only — so a
50
+ * hostile or half-written spec degrades to the static rendering rather
51
+ * than emitting a binding no action answers.
52
+ * @param {ChartTooltipSpec|null|undefined|any} spec
53
+ * @returns {ChartTooltip|null}
54
+ */
55
+ export declare function normalizeTooltip(spec: ChartTooltipSpec | null | undefined | any): ChartTooltip | null;
56
+ /**
57
+ * The `on` binding object for one mark, or `undefined` when tooltips
58
+ * are off (so callers can keep passing their props object through
59
+ * untouched — an unbound chart allocates nothing extra).
60
+ * @param {ChartTooltip|null} tooltip
61
+ * @param {string} text the mark's hover text
62
+ * @param {Record<string, any>} [descriptor] extra `with` members
63
+ * @returns {Record<string, any>|undefined}
64
+ */
65
+ export declare function markBinding(tooltip: ChartTooltip | null, text: string, descriptor?: Record<string, any>): Record<string, any> | undefined;
66
+ /**
67
+ * Mark props with the tooltip bindings folded in — for a mark whose
68
+ * `<title>` sits among other children (a series or candle `<g>`).
69
+ * @param {Record<string, any>} props
70
+ * @param {ChartTooltip|null} tooltip
71
+ * @param {string} text
72
+ * @param {Record<string, any>} [descriptor]
73
+ * @returns {Record<string, any>}
74
+ */
75
+ export declare function markProps(props: Record<string, any>, tooltip: ChartTooltip | null, text: string, descriptor?: Record<string, any>): Record<string, any>;
76
+ /**
77
+ * A leaf value mark: its element, its hover `<title>`, and the tooltip
78
+ * bindings when a host asked for them.
79
+ * @param {string} tag
80
+ * @param {Record<string, any>} props
81
+ * @param {ChartTooltip|null} tooltip
82
+ * @param {string} text hover text
83
+ * @param {Record<string, any>} [descriptor] extra `with` members
84
+ * @returns {any} the mark vnode
85
+ */
86
+ export declare function valueMark(tag: string, props: Record<string, any>, tooltip: ChartTooltip | null, text: string, descriptor?: Record<string, any>): any;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @file Colors: the categorical palette and the theme token tables.
3
+ *
4
+ * The categorical palette is a concrete constant, not a set of theme
5
+ * tokens (docs/DESIGN.md §8), in the suite's anchor order — blue first,
6
+ * amber second, teal third, then green/red/navy/olive/slate — with no
7
+ * pink and no purple anywhere. It is the same palette the mermaid pie
8
+ * used before it delegated here, so a pie renders byte-identically
9
+ * through either package.
10
+ *
11
+ * The semantic tokens (text/grid/axis, the win/loss pair) resolve
12
+ * through the shared `resolveTheme` kernel with the `chart` prefix; the
13
+ * `'host'` theme links them to the site token vocabulary (docs/DESIGN.md §2,
14
+ * §7) so charts follow the host's light/dark flip live with no
15
+ * re-render. Sync invariant: the `default`/`dark` values below must
16
+ * match the `--chart-*` fallbacks in `styles/charts.css`.
17
+ */
18
+ import { inkFor } from '@jarenjs/core/color';
19
+ export { inkFor };
20
+ /**
21
+ * The categorical series palette (docs/DESIGN.md §8 anchor order).
22
+ * @type {readonly string[]}
23
+ */
24
+ export declare const CATEGORICAL: readonly string[];
25
+ /**
26
+ * Ordinal color assignment: series `i` gets the `i`-th palette entry,
27
+ * wrapping.
28
+ * @param {number} i - Series index
29
+ * @param {readonly string[]} [palette] - Palette to draw from
30
+ * @returns {string}
31
+ */
32
+ export declare function seriesColor(i: number, palette?: readonly string[]): string;
33
+ /**
34
+ * The sequential magnitude ramp: one hue (the brand blue family),
35
+ * light→dark, for value-carrying fills (heatmap cells). A concrete
36
+ * constant like {@link CATEGORICAL}, not a theme token. The stops keep
37
+ * monotone perceptual lightness with visible step gaps, and both ends
38
+ * stay legible against the light and the dark site surface (the ramp
39
+ * does not flip with the theme).
40
+ * @type {readonly string[]}
41
+ */
42
+ export declare const SEQUENTIAL: readonly string[];
43
+ /**
44
+ * Continuous color for a normalized magnitude: `t` in [0,1] maps onto
45
+ * the ramp by piecewise-linear interpolation between its stops
46
+ * (clamped; non-finite `t` reads as 0).
47
+ * @param {number} t - Normalized magnitude (0 = low, 1 = high)
48
+ * @param {readonly string[]} [ramp] - Ramp stops, light→dark
49
+ * @returns {string} a `#rrggbb` color
50
+ */
51
+ export declare function sequentialColor(t: number, ramp?: readonly string[]): string;
52
+ /** @type {Record<string, Record<string, string>>} */
53
+ declare const THEMES: Record<string, Record<string, string>>;
54
+ /**
55
+ * Host custom-property links for the `'host'` theme: token key → the
56
+ * site token it follows (docs/DESIGN.md §2). Concrete defaults remain as
57
+ * `var()` fallbacks, so the same SVG stays standalone-valid.
58
+ * @type {Record<string, string>}
59
+ */
60
+ export declare const HOST_VARS: Record<string, string>;
61
+ /**
62
+ * Resolve a chart theme. The name `'host'` resolves the default tokens
63
+ * linked to the host token vocabulary via {@link HOST_VARS}.
64
+ * @param {string | Record<string, any>} [nameOrOverrides]
65
+ * @returns {{ name: string, tokens: Record<string, string>, cssVars: Record<string, string> }}
66
+ */
67
+ export declare function createTheme(nameOrOverrides?: string | Record<string, any>): {
68
+ name: string;
69
+ tokens: Record<string, string>;
70
+ cssVars: Record<string, string>;
71
+ };
72
+ export { THEMES };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @file Scales: pure `domain -> (value) => [0,1]` closures. All pixel
3
+ * mapping happens in the render pass; the AST and these scales stay in
4
+ * abstract unit space (the geometry-free contract). Construction may
5
+ * allocate (lookup maps); the returned functions never do.
6
+ *
7
+ * Out-of-domain inputs map outside [0,1] (linear/log/time) or to `NaN`
8
+ * (unknown ordinal/band categories); `polylinePath` and `num` in
9
+ * `@jarenjs/view/helpers` are the render-side guards that keep a NaN
10
+ * from ever reaching an emitted string.
11
+ */
12
+ export type UnitScale = (value: number) => number;
13
+ /**
14
+ * @typedef {(value: number) => number} UnitScale
15
+ */
16
+ /**
17
+ * Linear scale. A zero-span domain maps every value to 0.5.
18
+ * @param {number} min - Domain minimum
19
+ * @param {number} max - Domain maximum
20
+ * @returns {UnitScale}
21
+ */
22
+ export declare function scaleLinear(min: number, max: number): UnitScale;
23
+ /**
24
+ * Logarithmic scale (base 10). The domain must be strictly positive —
25
+ * that is checked once here, not per call; a non-positive *value* maps
26
+ * to NaN (log of a non-positive number), which the render guards drop.
27
+ * @param {number} min - Domain minimum (> 0)
28
+ * @param {number} max - Domain maximum (> 0)
29
+ * @returns {UnitScale}
30
+ */
31
+ export declare function scaleLog(min: number, max: number): UnitScale;
32
+ /**
33
+ * Ordinal scale: each category maps to the center of its equal slot,
34
+ * `(i + 0.5) / n`. Unknown categories map to NaN.
35
+ * @param {readonly string[]} categories - Domain, in display order
36
+ * @returns {(category: string) => number}
37
+ */
38
+ export declare function scaleOrdinal(categories: readonly string[]): (category: string) => number;
39
+ /**
40
+ * Band scale: each category owns an equal band with inner padding. The
41
+ * returned function gives the band's start; `bandwidth` and `step` are
42
+ * exposed as properties. Unknown categories map to NaN.
43
+ * @param {readonly string[]} categories - Domain, in display order
44
+ * @param {number} [padding] - Fraction of each step left empty (0..1)
45
+ * @returns {((category: string) => number) & {bandwidth: number, step: number}}
46
+ */
47
+ export declare function scaleBand(categories: readonly string[], padding?: number): ((category: string) => number) & {
48
+ bandwidth: number;
49
+ step: number;
50
+ };
51
+ /**
52
+ * Time scale: a linear scale over epoch milliseconds that also accepts
53
+ * `Date` instances (converted once per call via `getTime`, no
54
+ * allocation).
55
+ * @param {number|Date} min - Domain minimum
56
+ * @param {number|Date} max - Domain maximum
57
+ * @returns {(value: number|Date) => number}
58
+ */
59
+ export declare function scaleTime(min: number | Date, max: number | Date): (value: number | Date) => number;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @file The incremental chart session: a stateful compile pipeline for
3
+ * the streaming chart types that consumes a change-reporting source
4
+ * (`createStreamAdapter` with `{ changes: true }`, or anything with
5
+ * the same `takeChanges()`/`getData()` pair) and produces the next
6
+ * vnode tree in O(changed marks) work — WHEN the frame is "still".
7
+ *
8
+ * The stillness test is exact, not heuristic: the session re-resolves
9
+ * the scale domains from the updated extremes with the SAME exported
10
+ * helpers the wholesale build uses, and compares against the AST's
11
+ * recorded domain. Equal domains ⇒ every existing mark's position is
12
+ * unchanged, so only touched series re-render (untouched children
13
+ * keep their references — the view patcher skips them in O(1)).
14
+ * Anything else — a moved domain, a new series, a reset — falls back
15
+ * to a wholesale rebuild, which is the correct rendering of a frame
16
+ * whose scales moved, not a failure mode. Domain-stability policies
17
+ * (`config.domain`, `core/domain.js`) exist to make most ticks still.
18
+ *
19
+ * The correctness contract is byte equality: after every `tick()`,
20
+ * serializing the session's vnode equals serializing a wholesale
21
+ * `compileChart(config, source.getData())` of the same data —
22
+ * property-tested, never assumed.
23
+ */
24
+ export type ChartSessionSource = {
25
+ takeChanges: () => {
26
+ op: string;
27
+ path: string;
28
+ value?: any;
29
+ }[];
30
+ getData: () => any;
31
+ };
32
+ export type ChartSessionResult = {
33
+ /**
34
+ * the current svg vnode (reference-stable when unchanged)
35
+ */
36
+ vnode: any;
37
+ /**
38
+ * which path produced it
39
+ */
40
+ mode: 'unchanged' | 'incremental' | 'rebuilt';
41
+ };
42
+ export type ChartSession = {
43
+ /**
44
+ * drain the source and produce the next frame
45
+ */
46
+ tick: () => ChartSessionResult;
47
+ };
48
+ /**
49
+ * @typedef {object} ChartSessionSource
50
+ * @property {() => {op: string, path: string, value?: any}[]} takeChanges
51
+ * @property {() => any} getData
52
+ */
53
+ /**
54
+ * @typedef {object} ChartSessionResult
55
+ * @property {any} vnode the current svg vnode (reference-stable when unchanged)
56
+ * @property {'unchanged'|'incremental'|'rebuilt'} mode which path produced it
57
+ */
58
+ /**
59
+ * @typedef {object} ChartSession
60
+ * @property {() => ChartSessionResult} tick drain the source and produce the next frame
61
+ */
62
+ /**
63
+ * Create an incremental session for a streaming chart. Supported
64
+ * `config.type`: `'line'` (append/evict traffic), `'bar'` (live counts
65
+ * and sums) and `'candlestick'` (keyed kline upserts). The config is
66
+ * treated as immutable for the session's lifetime.
67
+ * @param {{type: string, [k: string]: any}} config
68
+ * @param {ChartSessionSource} source
69
+ * @param {{theme?: any, palette?: readonly string[], width?: number,
70
+ * rootClass?: string, keyPrefix?: string,
71
+ * tooltip?: import('./marks.js').ChartTooltipSpec}} [options]
72
+ * @returns {ChartSession}
73
+ * @throws {TypeError} On an unsupported chart type
74
+ */
75
+ export declare function createChartSession(config: {
76
+ type: string;
77
+ [k: string]: any;
78
+ }, source: ChartSessionSource, options?: {
79
+ theme?: any;
80
+ palette?: readonly string[];
81
+ width?: number;
82
+ rootClass?: string;
83
+ keyPrefix?: string;
84
+ tooltip?: import('./marks.js').ChartTooltipSpec;
85
+ }): ChartSession;
@@ -0,0 +1,187 @@
1
+ /**
2
+ * @file The streaming adapter: unified reader events in, chart data
3
+ * out. Source-agnostic by design — it consumes the `pair` event shape
4
+ * that the JOSL reader (`createStreamReader`) and the JSONX/strict-JSON
5
+ * reader (`createJsonxStreamReader`) both emit, so one adapter serves
6
+ * every syntax and this package never depends on a parser (it sees
7
+ * events, never a reader; pair it with `@jarenjs/josl` at the call
8
+ * site).
9
+ *
10
+ * Two record-boundary modes cover the two streaming shapes:
11
+ *
12
+ * - `recordBoundary: 'path'` — one large document arriving in chunks;
13
+ * a record is the subtree at `recordPath + [index]` (a JOSL `[[run]]`
14
+ * array-of-tables and a JSON `{"run": […]}` array produce the same
15
+ * pair paths — that is the point of the unified events), and closes
16
+ * when the event path leaves it.
17
+ * - `recordBoundary: 'document'` — many small complete documents over
18
+ * time (e.g. one WebSocket message each); every document IS one
19
+ * record — the fields directly under `recordPath` (default: the
20
+ * document root) — closed by an `endDocument()` call after the
21
+ * reader's `end()`. A message that fails mid-parse is discarded with
22
+ * `abortDocument()`, leaving the accumulated snapshot untouched.
23
+ *
24
+ * Accumulators: `line` (records → per-series points, ring-buffer
25
+ * eviction), `bar` (live category counts or sums), `heatmap` (the same
26
+ * counts or sums under TWO grouping keys — the column is `xField`, the
27
+ * row `seriesField`), `gauge` (the latest reading, nothing kept),
28
+ * `candlestick` (records keyed by open time; a re-delivered key
29
+ * REPLACES its candle, which is exactly how exchange kline updates
30
+ * behave), and `map` (whole GeoJSON Features, projected and simplified
31
+ * on arrival — see below).
32
+ *
33
+ * The `map` accumulator is the odd one out in two ways. Its record is
34
+ * not flat pair fields but a complete Feature, so it consumes the
35
+ * reader's `object-end` events at `recordPath + [index]` (default
36
+ * `['features']`) — pair the reader with `detach: ['features', '*']` so
37
+ * the document root keeps nothing and the accumulator is the only
38
+ * retention. And what it keeps is *reduced*: each feature's geometry is
39
+ * simplified on arrival to the vertices a drawing of the current extent
40
+ * could distinguish, so memory is bounded by the drawn detail, not the
41
+ * source detail. The projection cannot be fitted before the last
42
+ * feature has been seen, so the design is refit-on-growth: the running
43
+ * bbox sets the simplification tolerance, and when it grows enough to
44
+ * double the tolerance, the kept features are re-simplified against the
45
+ * new extent (a coarsening of already-kept vertices — never a re-read
46
+ * of dropped ones, which is why early features can only ever be finer
47
+ * than needed, not wrong).
48
+ *
49
+ * A record is emitted into the snapshot only when its required fields
50
+ * are present; `getData()` returns a FRESH object shaped for
51
+ * `compileChart(config, adapter.getData())`, so identity-keyed memos
52
+ * re-render per snapshot.
53
+ *
54
+ * Change reporting (`{ changes: true }`): every snapshot mutation is
55
+ * also buffered as an RFC 6902 operation against the `getData()`
56
+ * shape, collected with `takeChanges()` — the feed the incremental
57
+ * chart session consumes. The contract is replay equivalence: applying
58
+ * a `takeChanges()` batch to the previous snapshot yields exactly the
59
+ * next one (`reset()` buffers a whole-document replace). The ops are
60
+ * plain data; this module never imports a patch applier.
61
+ */
62
+ export type StreamAdapterConfig = {
63
+ /**
64
+ * path prefix owning the
65
+ * records: in path mode, e.g. `['run']` for `{"run": […]}` / `[[run]]`;
66
+ * in document mode, the object whose direct fields form the record
67
+ * (e.g. `['data', 'k']` for a combined-stream kline payload)
68
+ */
69
+ recordPath?: (string | number)[];
70
+ /**
71
+ * default 'path'
72
+ */
73
+ recordBoundary?: 'path' | 'document';
74
+ /**
75
+ * record field for x (line/candlestick) or
76
+ * the category (bar) / column (heatmap)
77
+ */
78
+ xField?: string;
79
+ /**
80
+ * record field for y (line), the summed
81
+ * value (bar/heatmap; omitted = count records), or the reading (gauge)
82
+ */
83
+ yField?: string;
84
+ /**
85
+ * record field naming the series
86
+ * (line) or the row (heatmap)
87
+ */
88
+ seriesField?: string;
89
+ /**
90
+ * candlestick fields (defaults
91
+ * 'open'/'high'/'low'/'close')
92
+ */
93
+ openField?: string;
94
+ highField?: string;
95
+ lowField?: string;
96
+ closeField?: string;
97
+ /**
98
+ * ring-buffer size (line: per series;
99
+ * candlestick: total candles)
100
+ */
101
+ maxPoints?: number;
102
+ /**
103
+ * buffer RFC 6902 ops per snapshot
104
+ * mutation for {@link StreamAdapter#takeChanges}
105
+ */
106
+ changes?: boolean;
107
+ /**
108
+ * map: the feature property naming a
109
+ * feature (default 'name')
110
+ */
111
+ labelField?: string;
112
+ /**
113
+ * map: the feature property to shade by
114
+ */
115
+ valueField?: string;
116
+ /**
117
+ * map: simplification tolerance as a
118
+ * fraction of the frame's width (default the map chart's own; `false`
119
+ * keeps every vertex, which unbounds memory)
120
+ */
121
+ simplify?: number | false;
122
+ /**
123
+ * map: frame width:height ratio the drawing
124
+ * will use (default 1.6, the map chart's own)
125
+ */
126
+ aspect?: number;
127
+ };
128
+ export type StreamAdapter = {
129
+ /**
130
+ * the reader event sink
131
+ */
132
+ onEvent: (event: any) => void;
133
+ /**
134
+ * close the current record
135
+ * (document mode: call once per completed document; path mode: call
136
+ * once at end of stream)
137
+ */
138
+ endDocument: () => void;
139
+ /**
140
+ * discard the record in progress
141
+ * (a message that failed to parse)
142
+ */
143
+ abortDocument: () => void;
144
+ /**
145
+ * a fresh chart-data snapshot
146
+ */
147
+ getData: () => any;
148
+ /**
149
+ * drain the buffered ops since the last call (requires
150
+ * `{ changes: true }`; throws a TypeError otherwise)
151
+ */
152
+ takeChanges: () => {
153
+ op: string;
154
+ path: string;
155
+ value?: any;
156
+ }[];
157
+ /**
158
+ * drop all accumulated state
159
+ */
160
+ reset: () => void;
161
+ };
162
+ /**
163
+ * Create a streaming accumulator for a chart type.
164
+ * @param {'line'|'bar'|'heatmap'|'gauge'|'candlestick'|'map'} chartType
165
+ * @param {StreamAdapterConfig} [config]
166
+ * @returns {StreamAdapter}
167
+ */
168
+ export declare function createStreamAdapter(chartType: 'line' | 'bar' | 'heatmap' | 'gauge' | 'candlestick' | 'map', config?: StreamAdapterConfig): StreamAdapter;
169
+ /**
170
+ * Lift a temporal coordinate to its epoch-millisecond number, passing every
171
+ * other value through untouched so a downstream `Number.isFinite` still
172
+ * decides what is plottable.
173
+ *
174
+ * A `Date` and an **RFC 3339 string** both lift, because both say
175
+ * unambiguously that they are an instant — which is what a time axis asked
176
+ * for, and JSON has no other way to spell one. A *numeric* string still does
177
+ * not: unlike `numish`, this refuses to accept `"5"` where the config asked
178
+ * for a number, because that is a type confusion rather than a date.
179
+ *
180
+ * A date with no time (`2026-07-27`) reads as UTC midnight, and a value
181
+ * carrying an offset is shifted to its instant, so points spelled in
182
+ * different zones land in the right order on one axis.
183
+ *
184
+ * @param {any} v
185
+ * @returns {any}
186
+ */
187
+ export declare function numOf(v: any): any;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @file `@jarenjs/charts` — headless charts. This is the **engine**:
3
+ * pure functions over data — definition + data ⇄ geometry-free AST ⇄
4
+ * pure-vnode SVG — that know only the `@jarenjs/view` vnode shape. It
5
+ * imports nothing from the component layer, `@jarenjs/app`, or the DOM
6
+ * (the two-layer component rule).
7
+ *
8
+ * The pipeline mirrors `@jarenjs/mermaid`:
9
+ *
10
+ * {config, data} ──build{Type}AST──▶ geometry-free AST (abstract
11
+ * fractions/angles, no pixels)
12
+ * │
13
+ * ▼
14
+ * render{Type}AST ──▶ pure-vnode SVG (toVnode /
15
+ * toSvgString via compileChart)
16
+ */
17
+ export { compileChart, chartTypes } from './core/chart.js';
18
+ export { scaleLinear, scaleLog, scaleOrdinal, scaleBand, scaleTime } from './core/scale.js';
19
+ export { niceStep, axisTicksLinear, axisTicksLog, axisTicksOrdinal, formatTickValue, formatTimeTick, axisTicksTime, niceTimeStep, } from './core/axis.js';
20
+ export { CATEGORICAL, SEQUENTIAL, seriesColor, sequentialColor, inkFor, createTheme, THEMES, HOST_VARS } from './core/palette.js';
21
+ export { buildPieAST, renderPieAST } from './types/pie.js';
22
+ export { buildBarAST, renderBarAST } from './types/bar.js';
23
+ export { buildLineAST, renderLineAST } from './types/line.js';
24
+ export { buildScatterAST, renderScatterAST } from './types/scatter.js';
25
+ export { buildCandlestickAST, renderCandlestickAST } from './types/candlestick.js';
26
+ export { buildRadarAST, renderRadarAST } from './types/radar.js';
27
+ export { buildGaugeAST, renderGaugeAST } from './types/gauge.js';
28
+ export { buildBoxplotAST, renderBoxplotAST, quantileSorted } from './types/boxplot.js';
29
+ export { buildHeatmapAST, renderHeatmapAST } from './types/heatmap.js';
30
+ export { buildTreemapAST, renderTreemapAST } from './types/treemap.js';
31
+ export { buildStreamgraphAST, renderStreamgraphAST } from './types/streamgraph.js';
32
+ export { buildSankeyAST, renderSankeyAST } from './types/sankey.js';
33
+ export { buildMapAST, renderMapAST } from './types/map.js';
34
+ export { createStreamAdapter } from './core/stream-adapter.js';
35
+ export { createChartSession } from './core/session.js';