@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.
- package/README.md +293 -0
- package/dist/types/component/index.d.ts +95 -0
- package/dist/types/core/axis.d.ts +77 -0
- package/dist/types/core/cartesian.d.ts +127 -0
- package/dist/types/core/chart.d.ts +58 -0
- package/dist/types/core/domain.d.ts +96 -0
- package/dist/types/core/marks.d.ts +86 -0
- package/dist/types/core/palette.d.ts +72 -0
- package/dist/types/core/scale.d.ts +59 -0
- package/dist/types/core/session.d.ts +85 -0
- package/dist/types/core/stream-adapter.d.ts +187 -0
- package/dist/types/index.d.ts +35 -0
- package/dist/types/transforms/benchmark-adapter.d.ts +169 -0
- package/dist/types/transforms/mermaid-adapter.d.ts +30 -0
- package/dist/types/types/bar.d.ts +213 -0
- package/dist/types/types/boxplot.d.ts +116 -0
- package/dist/types/types/candlestick.d.ts +218 -0
- package/dist/types/types/gauge.d.ts +68 -0
- package/dist/types/types/heatmap.d.ts +104 -0
- package/dist/types/types/line.d.ts +272 -0
- package/dist/types/types/map.d.ts +137 -0
- package/dist/types/types/pie.d.ts +146 -0
- package/dist/types/types/radar.d.ts +89 -0
- package/dist/types/types/sankey.d.ts +100 -0
- package/dist/types/types/scatter.d.ts +80 -0
- package/dist/types/types/streamgraph.d.ts +75 -0
- package/dist/types/types/treemap.d.ts +118 -0
- package/package.json +76 -0
- package/schemas/chart-definition.schema.json +448 -0
- package/src/component/index.js +125 -0
- package/src/core/axis.js +221 -0
- package/src/core/cartesian.js +192 -0
- package/src/core/chart.js +101 -0
- package/src/core/domain.js +123 -0
- package/src/core/marks.js +110 -0
- package/src/core/palette.js +126 -0
- package/src/core/scale.js +106 -0
- package/src/core/session.js +0 -0
- package/src/core/stream-adapter.js +613 -0
- package/src/index.js +40 -0
- package/src/transforms/benchmark-adapter.js +298 -0
- package/src/transforms/mermaid-adapter.js +19 -0
- package/src/types/bar.js +276 -0
- package/src/types/boxplot.js +216 -0
- package/src/types/candlestick.js +274 -0
- package/src/types/gauge.js +140 -0
- package/src/types/heatmap.js +176 -0
- package/src/types/line.js +349 -0
- package/src/types/map.js +378 -0
- package/src/types/pie.js +163 -0
- package/src/types/radar.js +224 -0
- package/src/types/sankey.js +391 -0
- package/src/types/scatter.js +148 -0
- package/src/types/streamgraph.js +158 -0
- package/src/types/treemap.js +322 -0
- package/styles/charts.css +83 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The candlestick chart type: OHLC records on a time x-scale and
|
|
3
|
+
* a linear y-scale. Up/down candles use the win/loss semantic pair —
|
|
4
|
+
* gain and loss are exactly what the tokens mean, and the pair is
|
|
5
|
+
* host-linked (`--ok`/`--fail`) like every semantic color. Data shape:
|
|
6
|
+
*
|
|
7
|
+
* data = { candles: [{t, open, high, low, close}] }
|
|
8
|
+
* config = { type:'candlestick', title?, xLabel?, yLabel?, domain? }
|
|
9
|
+
*
|
|
10
|
+
* Candle width comes from the band-width math: an equal share of the
|
|
11
|
+
* axis per candle (klines arrive at a fixed interval, so equal bands
|
|
12
|
+
* and true time positions coincide).
|
|
13
|
+
*
|
|
14
|
+
* `config.domain` declares a domain-stability policy (`core/domain.js`):
|
|
15
|
+
* a quantized sliding `x` window (candles older than it are dropped —
|
|
16
|
+
* a clamped candle would misstate its prices), pinned or
|
|
17
|
+
* step-quantized `y` bounds. The AST records the resolved domain so a
|
|
18
|
+
* later build — or the incremental session — can detect "unchanged".
|
|
19
|
+
*
|
|
20
|
+
* The extremes scan, domain resolution and per-candle mapping are
|
|
21
|
+
* exported (`scanCandleExtremes` / `resolveCandleDomains` /
|
|
22
|
+
* `candleUnit`) because the session must make the same decisions from
|
|
23
|
+
* the same numbers. Each candle renders as one keyed
|
|
24
|
+
* `<g class="chart-candle">` (wick line, then body rect) — the candle
|
|
25
|
+
* is the replaceable unit a kline upsert patches; `buildCandlestickRender`
|
|
26
|
+
* is the render variant that also returns that geometry.
|
|
27
|
+
*/
|
|
28
|
+
export type CandleAST = {
|
|
29
|
+
/**
|
|
30
|
+
* open time (epoch ms — the candle's identity)
|
|
31
|
+
*/
|
|
32
|
+
t: number;
|
|
33
|
+
/**
|
|
34
|
+
* center position (0..1)
|
|
35
|
+
*/
|
|
36
|
+
u: number;
|
|
37
|
+
/**
|
|
38
|
+
* body width (0..1)
|
|
39
|
+
*/
|
|
40
|
+
w: number;
|
|
41
|
+
openV: number;
|
|
42
|
+
closeV: number;
|
|
43
|
+
highV: number;
|
|
44
|
+
lowV: number;
|
|
45
|
+
open: number;
|
|
46
|
+
high: number;
|
|
47
|
+
low: number;
|
|
48
|
+
/**
|
|
49
|
+
* raw prices, which the
|
|
50
|
+
* hover text reports (a clamped unit value cannot be read back to one)
|
|
51
|
+
*/
|
|
52
|
+
close: number;
|
|
53
|
+
/**
|
|
54
|
+
* close >= open
|
|
55
|
+
*/
|
|
56
|
+
up: boolean;
|
|
57
|
+
};
|
|
58
|
+
export type CandlestickAST = {
|
|
59
|
+
type: 'candlestick';
|
|
60
|
+
title: string | null;
|
|
61
|
+
x: {
|
|
62
|
+
ticks: {
|
|
63
|
+
pos: number;
|
|
64
|
+
label: string;
|
|
65
|
+
}[];
|
|
66
|
+
label: string | null;
|
|
67
|
+
};
|
|
68
|
+
y: {
|
|
69
|
+
ticks: {
|
|
70
|
+
pos: number;
|
|
71
|
+
label: string;
|
|
72
|
+
}[];
|
|
73
|
+
label: string | null;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* resolved scale bounds
|
|
77
|
+
*/
|
|
78
|
+
domain: {
|
|
79
|
+
x: [number, number];
|
|
80
|
+
y: [number, number];
|
|
81
|
+
};
|
|
82
|
+
candles: CandleAST[];
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* @typedef {object} CandleAST
|
|
86
|
+
* @property {number} t open time (epoch ms — the candle's identity)
|
|
87
|
+
* @property {number} u center position (0..1)
|
|
88
|
+
* @property {number} w body width (0..1)
|
|
89
|
+
* @property {number} openV @property {number} closeV
|
|
90
|
+
* @property {number} highV @property {number} lowV
|
|
91
|
+
* @property {number} open @property {number} high
|
|
92
|
+
* @property {number} low @property {number} close raw prices, which the
|
|
93
|
+
* hover text reports (a clamped unit value cannot be read back to one)
|
|
94
|
+
* @property {boolean} up close >= open
|
|
95
|
+
*/
|
|
96
|
+
/**
|
|
97
|
+
* @typedef {object} CandlestickAST
|
|
98
|
+
* @property {'candlestick'} type
|
|
99
|
+
* @property {string|null} title
|
|
100
|
+
* @property {{ticks: {pos:number,label:string}[], label: string|null}} x
|
|
101
|
+
* @property {{ticks: {pos:number,label:string}[], label: string|null}} y
|
|
102
|
+
* @property {{x: [number, number], y: [number, number]}} domain resolved scale bounds
|
|
103
|
+
* @property {CandleAST[]} candles
|
|
104
|
+
*/
|
|
105
|
+
/**
|
|
106
|
+
* Scan the candle extremes the domain resolution needs: t bounds over
|
|
107
|
+
* every well-formed candle, price bounds over the candles a window
|
|
108
|
+
* keeps — and the kept list itself (windowed-out candles are dropped
|
|
109
|
+
* entirely; a candle clamped to the edge would misstate its prices).
|
|
110
|
+
* @param {any[]} rawCandles
|
|
111
|
+
* @param {import('../core/domain.js').DomainPolicy} policy
|
|
112
|
+
* @returns {{t0:number, t1:number, lo:number, hi:number, kept: any[]}}
|
|
113
|
+
*/
|
|
114
|
+
export declare function scanCandleExtremes(rawCandles: any[], policy: import('../core/domain.js').DomainPolicy): {
|
|
115
|
+
t0: number;
|
|
116
|
+
t1: number;
|
|
117
|
+
lo: number;
|
|
118
|
+
hi: number;
|
|
119
|
+
kept: any[];
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Resolve the scale domains (and their tick values) from the scanned
|
|
123
|
+
* extremes under the domain policy — the single place the candlestick
|
|
124
|
+
* type decides its bounds.
|
|
125
|
+
* @param {{t0:number, t1:number, lo:number, hi:number}} ext
|
|
126
|
+
* @param {import('../core/domain.js').DomainPolicy} policy
|
|
127
|
+
* @returns {{x: [number,number], y: [number,number],
|
|
128
|
+
* xTickValues: number[], yTickValues: number[]}}
|
|
129
|
+
*/
|
|
130
|
+
export declare function resolveCandleDomains(ext: {
|
|
131
|
+
t0: number;
|
|
132
|
+
t1: number;
|
|
133
|
+
lo: number;
|
|
134
|
+
hi: number;
|
|
135
|
+
}, policy: import('../core/domain.js').DomainPolicy): {
|
|
136
|
+
x: [number, number];
|
|
137
|
+
y: [number, number];
|
|
138
|
+
xTickValues: number[];
|
|
139
|
+
yTickValues: number[];
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Map one OHLC record onto its unit-space candle — the per-candle half
|
|
143
|
+
* of the build, shared with the session.
|
|
144
|
+
* @param {any} c a well-formed `{t, open, high, low, close}` record
|
|
145
|
+
* @param {(v:number)=>number} xScale @param {(v:number)=>number} yScale
|
|
146
|
+
* @param {number} w candle width (0..1)
|
|
147
|
+
* @returns {CandleAST}
|
|
148
|
+
*/
|
|
149
|
+
export declare function candleUnit(c: any, xScale: (v: number) => number, yScale: (v: number) => number, w: number): CandleAST;
|
|
150
|
+
/**
|
|
151
|
+
* Build the geometry-free candlestick AST.
|
|
152
|
+
* @param {any} data
|
|
153
|
+
* @param {any} [config]
|
|
154
|
+
* @returns {CandlestickAST}
|
|
155
|
+
*/
|
|
156
|
+
export declare function buildCandlestickAST(data: any, config?: any): CandlestickAST;
|
|
157
|
+
/**
|
|
158
|
+
* Render one candle as its keyed `<g>` group: an OHLC hover `<title>`,
|
|
159
|
+
* then the wick line under the body rect, up/down tones from the
|
|
160
|
+
* theme's win/loss pair.
|
|
161
|
+
* @param {CandleAST} c
|
|
162
|
+
* @param {{x:number,y:number,w:number,h:number}} plot
|
|
163
|
+
* @param {{tokens: Record<string,string>}} theme
|
|
164
|
+
* @param {import('../core/marks.js').ChartTooltip|null} [tooltip]
|
|
165
|
+
* @returns {any}
|
|
166
|
+
*/
|
|
167
|
+
export declare function candleRender(c: CandleAST, plot: {
|
|
168
|
+
x: number;
|
|
169
|
+
y: number;
|
|
170
|
+
w: number;
|
|
171
|
+
h: number;
|
|
172
|
+
}, theme: {
|
|
173
|
+
tokens: Record<string, string>;
|
|
174
|
+
}, tooltip?: import('../core/marks.js').ChartTooltip | null): any;
|
|
175
|
+
/**
|
|
176
|
+
* Render a candlestick AST and return the svg WITH the geometry a
|
|
177
|
+
* session needs to patch it per candle.
|
|
178
|
+
* @param {CandlestickAST} ast
|
|
179
|
+
* @param {{tokens: Record<string,string>, cssVars: Record<string,string>}} theme
|
|
180
|
+
* @param {string} hash
|
|
181
|
+
* @param {{rootClass?: string, keyPrefix?: string, width?: number,
|
|
182
|
+
* tooltip?: import('../core/marks.js').ChartTooltipSpec}} [options]
|
|
183
|
+
* @returns {{svg: any, plot: {x:number,y:number,w:number,h:number}, chromeLen: number}}
|
|
184
|
+
*/
|
|
185
|
+
export declare function buildCandlestickRender(ast: CandlestickAST, theme: {
|
|
186
|
+
tokens: Record<string, string>;
|
|
187
|
+
cssVars: Record<string, string>;
|
|
188
|
+
}, hash: string, options?: {
|
|
189
|
+
rootClass?: string;
|
|
190
|
+
keyPrefix?: string;
|
|
191
|
+
width?: number;
|
|
192
|
+
tooltip?: import('../core/marks.js').ChartTooltipSpec;
|
|
193
|
+
}): {
|
|
194
|
+
svg: any;
|
|
195
|
+
plot: {
|
|
196
|
+
x: number;
|
|
197
|
+
y: number;
|
|
198
|
+
w: number;
|
|
199
|
+
h: number;
|
|
200
|
+
};
|
|
201
|
+
chromeLen: number;
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Render a candlestick AST to a pure-vnode SVG.
|
|
205
|
+
* @param {CandlestickAST} ast
|
|
206
|
+
* @param {{tokens: Record<string,string>, cssVars: Record<string,string>}} theme
|
|
207
|
+
* @param {string} hash
|
|
208
|
+
* @param {{rootClass?: string, keyPrefix?: string, width?: number}} [options]
|
|
209
|
+
* @returns {any}
|
|
210
|
+
*/
|
|
211
|
+
export declare function renderCandlestickAST(ast: CandlestickAST, theme: {
|
|
212
|
+
tokens: Record<string, string>;
|
|
213
|
+
cssVars: Record<string, string>;
|
|
214
|
+
}, hash: string, options?: {
|
|
215
|
+
rootClass?: string;
|
|
216
|
+
keyPrefix?: string;
|
|
217
|
+
width?: number;
|
|
218
|
+
}): any;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The gauge chart type: a single value on a semicircular dial —
|
|
3
|
+
* the "how full is it" headline mark. Data shape:
|
|
4
|
+
*
|
|
5
|
+
* data = { value: number }
|
|
6
|
+
* config = { type:'gauge', title?, min?, max?, unit?, tone? }
|
|
7
|
+
*
|
|
8
|
+
* The domain is `[min, max]` (0..100 when unset); the AST carries the
|
|
9
|
+
* clamped fill fraction and tick fractions only — the dial radius and
|
|
10
|
+
* stroke widths are render decisions. `tone` colors the fill through
|
|
11
|
+
* the semantic win/loss pair; the default is the first categorical
|
|
12
|
+
* anchor (the brand blue).
|
|
13
|
+
*/
|
|
14
|
+
export type GaugeAST = {
|
|
15
|
+
type: 'gauge';
|
|
16
|
+
title: string | null;
|
|
17
|
+
value: number;
|
|
18
|
+
unit: string | null;
|
|
19
|
+
min: number;
|
|
20
|
+
max: number;
|
|
21
|
+
/**
|
|
22
|
+
* clamped fill fraction (0..1)
|
|
23
|
+
*/
|
|
24
|
+
frac: number;
|
|
25
|
+
ticks: {
|
|
26
|
+
frac: number;
|
|
27
|
+
label: string;
|
|
28
|
+
}[];
|
|
29
|
+
tone: 'win' | 'loss' | null;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {object} GaugeAST
|
|
33
|
+
* @property {'gauge'} type
|
|
34
|
+
* @property {string|null} title
|
|
35
|
+
* @property {number} value
|
|
36
|
+
* @property {string|null} unit
|
|
37
|
+
* @property {number} min @property {number} max
|
|
38
|
+
* @property {number} frac clamped fill fraction (0..1)
|
|
39
|
+
* @property {{frac: number, label: string}[]} ticks
|
|
40
|
+
* @property {'win'|'loss'|null} tone
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Build the geometry-free gauge AST.
|
|
44
|
+
* @param {any} data
|
|
45
|
+
* @param {any} [config]
|
|
46
|
+
* @returns {GaugeAST}
|
|
47
|
+
*/
|
|
48
|
+
export declare function buildGaugeAST(data: any, config?: any): GaugeAST;
|
|
49
|
+
/**
|
|
50
|
+
* Render a gauge AST to a pure-vnode SVG: a semicircular track, the
|
|
51
|
+
* value arc over it, outward tick marks with labels, and the value as
|
|
52
|
+
* the headline figure in the dial's mouth.
|
|
53
|
+
* @param {GaugeAST} ast
|
|
54
|
+
* @param {{tokens: Record<string,string>, cssVars: Record<string,string>}} theme
|
|
55
|
+
* @param {string} hash
|
|
56
|
+
* @param {{rootClass?: string, keyPrefix?: string, palette?: readonly string[],
|
|
57
|
+
* tooltip?: import('../core/marks.js').ChartTooltipSpec}} [options]
|
|
58
|
+
* @returns {any}
|
|
59
|
+
*/
|
|
60
|
+
export declare function renderGaugeAST(ast: GaugeAST, theme: {
|
|
61
|
+
tokens: Record<string, string>;
|
|
62
|
+
cssVars: Record<string, string>;
|
|
63
|
+
}, hash: string, options?: {
|
|
64
|
+
rootClass?: string;
|
|
65
|
+
keyPrefix?: string;
|
|
66
|
+
palette?: readonly string[];
|
|
67
|
+
tooltip?: import('../core/marks.js').ChartTooltipSpec;
|
|
68
|
+
}): any;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The heatmap chart type: a category × category matrix of
|
|
3
|
+
* magnitudes on the sequential blue ramp — the alternative reading of
|
|
4
|
+
* the benchmark scenario matrices that ship as grouped bars. Data
|
|
5
|
+
* shape:
|
|
6
|
+
*
|
|
7
|
+
* data = { xLabels: string[], yLabels: string[],
|
|
8
|
+
* values: number[][] } // values[yi][xi], row-major
|
|
9
|
+
* config = { type:'heatmap', title?, xLabel?, yLabel?, log? }
|
|
10
|
+
*
|
|
11
|
+
* The AST is unit-space cell bands plus a normalized magnitude `t` per
|
|
12
|
+
* cell; the color (the sequential ramp), the cell inset and the ramp
|
|
13
|
+
* legend are render decisions. Rows read top-down: `yLabels[0]` is the
|
|
14
|
+
* top row. Non-finite cells (and non-positive ones under `log`) are
|
|
15
|
+
* simply absent — the surface shows through, which is the honest
|
|
16
|
+
* rendering of "no measurement".
|
|
17
|
+
*/
|
|
18
|
+
export type HeatCellAST = {
|
|
19
|
+
xi: number;
|
|
20
|
+
yi: number;
|
|
21
|
+
u0: number;
|
|
22
|
+
u1: number;
|
|
23
|
+
v0: number;
|
|
24
|
+
v1: number;
|
|
25
|
+
/**
|
|
26
|
+
* normalized magnitude (0..1)
|
|
27
|
+
*/
|
|
28
|
+
t: number;
|
|
29
|
+
value: number;
|
|
30
|
+
};
|
|
31
|
+
export type HeatmapAST = {
|
|
32
|
+
type: 'heatmap';
|
|
33
|
+
title: string | null;
|
|
34
|
+
xLabels: string[];
|
|
35
|
+
yLabels: string[];
|
|
36
|
+
x: {
|
|
37
|
+
ticks: {
|
|
38
|
+
pos: number;
|
|
39
|
+
label: string;
|
|
40
|
+
}[];
|
|
41
|
+
label: string | null;
|
|
42
|
+
};
|
|
43
|
+
y: {
|
|
44
|
+
ticks: {
|
|
45
|
+
pos: number;
|
|
46
|
+
label: string;
|
|
47
|
+
}[];
|
|
48
|
+
label: string | null;
|
|
49
|
+
};
|
|
50
|
+
cells: HeatCellAST[];
|
|
51
|
+
/**
|
|
52
|
+
* finite-value extent (null = no data)
|
|
53
|
+
*/
|
|
54
|
+
domain: {
|
|
55
|
+
min: number;
|
|
56
|
+
max: number;
|
|
57
|
+
} | null;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* @typedef {object} HeatCellAST
|
|
61
|
+
* @property {number} xi @property {number} yi
|
|
62
|
+
* @property {number} u0 @property {number} u1
|
|
63
|
+
* @property {number} v0 @property {number} v1
|
|
64
|
+
* @property {number} t normalized magnitude (0..1)
|
|
65
|
+
* @property {number} value
|
|
66
|
+
*/
|
|
67
|
+
/**
|
|
68
|
+
* @typedef {object} HeatmapAST
|
|
69
|
+
* @property {'heatmap'} type
|
|
70
|
+
* @property {string|null} title
|
|
71
|
+
* @property {string[]} xLabels @property {string[]} yLabels
|
|
72
|
+
* @property {{ticks: {pos:number,label:string}[], label: string|null}} x
|
|
73
|
+
* @property {{ticks: {pos:number,label:string}[], label: string|null}} y
|
|
74
|
+
* @property {HeatCellAST[]} cells
|
|
75
|
+
* @property {{min: number, max: number}|null} domain finite-value extent (null = no data)
|
|
76
|
+
*/
|
|
77
|
+
/**
|
|
78
|
+
* Build the geometry-free heatmap AST.
|
|
79
|
+
* @param {any} data
|
|
80
|
+
* @param {any} [config]
|
|
81
|
+
* @returns {HeatmapAST}
|
|
82
|
+
*/
|
|
83
|
+
export declare function buildHeatmapAST(data: any, config?: any): HeatmapAST;
|
|
84
|
+
/**
|
|
85
|
+
* Render a heatmap AST to a pure-vnode SVG: inset cell rects colored by
|
|
86
|
+
* the sequential ramp, a labeled min→max ramp key in the legend slot,
|
|
87
|
+
* and a `<title>` per cell with the exact value.
|
|
88
|
+
* @param {HeatmapAST} ast
|
|
89
|
+
* @param {{tokens: Record<string,string>, cssVars: Record<string,string>}} theme
|
|
90
|
+
* @param {string} hash
|
|
91
|
+
* @param {{rootClass?: string, keyPrefix?: string, ramp?: readonly string[], width?: number,
|
|
92
|
+
* tooltip?: import('../core/marks.js').ChartTooltipSpec}} [options]
|
|
93
|
+
* @returns {any}
|
|
94
|
+
*/
|
|
95
|
+
export declare function renderHeatmapAST(ast: HeatmapAST, theme: {
|
|
96
|
+
tokens: Record<string, string>;
|
|
97
|
+
cssVars: Record<string, string>;
|
|
98
|
+
}, hash: string, options?: {
|
|
99
|
+
rootClass?: string;
|
|
100
|
+
keyPrefix?: string;
|
|
101
|
+
ramp?: readonly string[];
|
|
102
|
+
width?: number;
|
|
103
|
+
tooltip?: import('../core/marks.js').ChartTooltipSpec;
|
|
104
|
+
}): any;
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The line chart type: multi-series polylines over a linear or
|
|
3
|
+
* time x axis, linear or log y axis, optional point markers. This is
|
|
4
|
+
* the streaming-critical type — a live feed re-renders it per snapshot
|
|
5
|
+
* — so build and render stay allocation-light (one pass per series,
|
|
6
|
+
* `polylinePath` breaks the line on unplottable samples instead of
|
|
7
|
+
* filtering arrays). Data shape:
|
|
8
|
+
*
|
|
9
|
+
* data = { series: [{ name, points: [{x, y}] }] }
|
|
10
|
+
* config = { type:'line', title?, x?: 'linear'|'time', log?,
|
|
11
|
+
* markers?, xLabel?, yLabel?, domain? }
|
|
12
|
+
*
|
|
13
|
+
* `config.domain` declares a domain-stability policy (`core/domain.js`)
|
|
14
|
+
* so most streaming ticks keep the scales still: a quantized sliding
|
|
15
|
+
* `x` window (samples older than it become null vertices), pinned or
|
|
16
|
+
* step-quantized `y` bounds. The AST records the resolved domain so a
|
|
17
|
+
* later build — or the incremental session — can detect "unchanged".
|
|
18
|
+
*
|
|
19
|
+
* The extremes scan, domain resolution and scale construction are
|
|
20
|
+
* exported (`scanLineExtremes` / `resolveLineDomains` / `lineScales`)
|
|
21
|
+
* because the incremental session must make the SAME decisions from
|
|
22
|
+
* the same numbers — one implementation, no drift. Each series
|
|
23
|
+
* renders as one `<g class="chart-series">` (path, then marker dots),
|
|
24
|
+
* so a session — and the view patcher — can treat a series as one
|
|
25
|
+
* replaceable unit; `buildLineRender` is the render variant that also
|
|
26
|
+
* returns that per-series geometry.
|
|
27
|
+
*/
|
|
28
|
+
export type LineAST = {
|
|
29
|
+
type: 'line';
|
|
30
|
+
title: string | null;
|
|
31
|
+
x: {
|
|
32
|
+
ticks: {
|
|
33
|
+
pos: number;
|
|
34
|
+
label: string;
|
|
35
|
+
}[];
|
|
36
|
+
label: string | null;
|
|
37
|
+
};
|
|
38
|
+
y: {
|
|
39
|
+
ticks: {
|
|
40
|
+
pos: number;
|
|
41
|
+
label: string;
|
|
42
|
+
}[];
|
|
43
|
+
label: string | null;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* resolved scale bounds
|
|
47
|
+
*/
|
|
48
|
+
domain: {
|
|
49
|
+
x: [number, number];
|
|
50
|
+
y: [number, number];
|
|
51
|
+
};
|
|
52
|
+
legend: {
|
|
53
|
+
name: string;
|
|
54
|
+
swatch: number;
|
|
55
|
+
}[] | null;
|
|
56
|
+
series: {
|
|
57
|
+
name: string;
|
|
58
|
+
points: ({
|
|
59
|
+
u: number;
|
|
60
|
+
v: number;
|
|
61
|
+
} | null)[];
|
|
62
|
+
}[];
|
|
63
|
+
markers: boolean;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* @typedef {object} LineAST
|
|
67
|
+
* @property {'line'} type
|
|
68
|
+
* @property {string|null} title
|
|
69
|
+
* @property {{ticks: {pos:number,label:string}[], label: string|null}} x
|
|
70
|
+
* @property {{ticks: {pos:number,label:string}[], label: string|null}} y
|
|
71
|
+
* @property {{x: [number, number], y: [number, number]}} domain resolved scale bounds
|
|
72
|
+
* @property {{name: string, swatch: number}[]|null} legend
|
|
73
|
+
* @property {{name: string, points: ({u:number,v:number}|null)[]}[]} series
|
|
74
|
+
* @property {boolean} markers
|
|
75
|
+
*/
|
|
76
|
+
/**
|
|
77
|
+
* Scan the data extremes the domain resolution needs: raw x bounds
|
|
78
|
+
* over every finite sample, y bounds over the samples a window keeps
|
|
79
|
+
* (windowed-out samples must not pin the value axis). Under `log`,
|
|
80
|
+
* non-positive y values never join the y extremes (they still extend
|
|
81
|
+
* x, as unplottable vertices on a real time axis do).
|
|
82
|
+
* @param {{points: any[]}[]} input series with array points
|
|
83
|
+
* @param {import('../core/domain.js').DomainPolicy} policy
|
|
84
|
+
* @param {boolean} log
|
|
85
|
+
* @returns {{x0:number, x1:number, y0:number, y1:number}}
|
|
86
|
+
*/
|
|
87
|
+
export declare function scanLineExtremes(input: {
|
|
88
|
+
points: any[];
|
|
89
|
+
}[], policy: import('../core/domain.js').DomainPolicy, log: boolean): {
|
|
90
|
+
x0: number;
|
|
91
|
+
x1: number;
|
|
92
|
+
y0: number;
|
|
93
|
+
y1: number;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Resolve the scale domains (and their tick values) from the scanned
|
|
97
|
+
* extremes under the domain policy — the single place the line type
|
|
98
|
+
* decides its bounds; the incremental session compares the result
|
|
99
|
+
* against the AST's recorded domain to detect a still frame.
|
|
100
|
+
* @param {{x0:number, x1:number, y0:number, y1:number}} ext
|
|
101
|
+
* @param {import('../core/domain.js').DomainPolicy} policy
|
|
102
|
+
* @param {boolean} time
|
|
103
|
+
* @param {boolean} log
|
|
104
|
+
* @returns {{x: [number,number], y: [number,number], xDrop: number|null,
|
|
105
|
+
* xTickValues: number[], yTickValues: number[]}}
|
|
106
|
+
*/
|
|
107
|
+
export declare function resolveLineDomains(ext: {
|
|
108
|
+
x0: number;
|
|
109
|
+
x1: number;
|
|
110
|
+
y0: number;
|
|
111
|
+
y1: number;
|
|
112
|
+
}, policy: import('../core/domain.js').DomainPolicy, time: boolean, log: boolean): {
|
|
113
|
+
x: [number, number];
|
|
114
|
+
y: [number, number];
|
|
115
|
+
xDrop: number | null;
|
|
116
|
+
xTickValues: number[];
|
|
117
|
+
yTickValues: number[];
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Unit scales over a resolved domain — the same closures the build
|
|
121
|
+
* uses, reconstructable by the session from the AST's domain alone.
|
|
122
|
+
* @param {{x: [number,number], y: [number,number]}} domains
|
|
123
|
+
* @param {boolean} time
|
|
124
|
+
* @param {boolean} log
|
|
125
|
+
* @returns {{xScale: (v:number)=>number, yScale: (v:number)=>number}}
|
|
126
|
+
*/
|
|
127
|
+
export declare function lineScales(domains: {
|
|
128
|
+
x: [number, number];
|
|
129
|
+
y: [number, number];
|
|
130
|
+
}, time: boolean, log: boolean): {
|
|
131
|
+
xScale: (v: number) => number;
|
|
132
|
+
yScale: (v: number) => number;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Map one sample onto a unit vertex (or null for an unplottable one) —
|
|
136
|
+
* the per-point half of the build, shared with the session.
|
|
137
|
+
* @param {any} p the `{x, y}` sample
|
|
138
|
+
* @param {number|null} xDrop window low bound (drop older samples)
|
|
139
|
+
* @param {(v:number)=>number} xScale @param {(v:number)=>number} yScale
|
|
140
|
+
* @returns {{u:number, v:number}|null}
|
|
141
|
+
*/
|
|
142
|
+
export declare function lineVertex(p: any, xDrop: number | null, xScale: (v: number) => number, yScale: (v: number) => number): {
|
|
143
|
+
u: number;
|
|
144
|
+
v: number;
|
|
145
|
+
} | null;
|
|
146
|
+
/**
|
|
147
|
+
* Build the geometry-free line AST.
|
|
148
|
+
* @param {any} data
|
|
149
|
+
* @param {any} [config]
|
|
150
|
+
* @returns {LineAST}
|
|
151
|
+
*/
|
|
152
|
+
export declare function buildLineAST(data: any, config?: any): LineAST;
|
|
153
|
+
export type LineSeriesRender = {
|
|
154
|
+
/**
|
|
155
|
+
* the series' `<g>` vnode
|
|
156
|
+
*/
|
|
157
|
+
group: any;
|
|
158
|
+
/**
|
|
159
|
+
* the polyline path data
|
|
160
|
+
*/
|
|
161
|
+
d: string;
|
|
162
|
+
/**
|
|
163
|
+
* true when the last vertex was drawable (the
|
|
164
|
+
* next appended token is an `L`, not an `M`)
|
|
165
|
+
*/
|
|
166
|
+
pen: boolean;
|
|
167
|
+
/**
|
|
168
|
+
* marker circle vnodes (empty when markers off)
|
|
169
|
+
*/
|
|
170
|
+
dots: any[];
|
|
171
|
+
/**
|
|
172
|
+
* the series color
|
|
173
|
+
*/
|
|
174
|
+
color: string;
|
|
175
|
+
/**
|
|
176
|
+
* the series name (its hover text)
|
|
177
|
+
*/
|
|
178
|
+
name: string;
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* @typedef {object} LineSeriesRender
|
|
182
|
+
* @property {any} group the series' `<g>` vnode
|
|
183
|
+
* @property {string} d the polyline path data
|
|
184
|
+
* @property {boolean} pen true when the last vertex was drawable (the
|
|
185
|
+
* next appended token is an `L`, not an `M`)
|
|
186
|
+
* @property {any[]} dots marker circle vnodes (empty when markers off)
|
|
187
|
+
* @property {string} color the series color
|
|
188
|
+
* @property {string} name the series name (its hover text)
|
|
189
|
+
*/
|
|
190
|
+
/**
|
|
191
|
+
* The children of one series `<g>`: the hover `<title>`, the polyline
|
|
192
|
+
* path (when it has one), then the marker dots. The series — not the
|
|
193
|
+
* individual sample — is the value mark here: a live line carries tens
|
|
194
|
+
* of thousands of vertices, and a `<title>` per vertex would put a
|
|
195
|
+
* label allocation on the streaming path for text no reader can aim at.
|
|
196
|
+
* Shared with the incremental session, which rebuilds these children in
|
|
197
|
+
* place, so the two cannot drift.
|
|
198
|
+
* @param {string} name @param {string} d @param {any[]} dots @param {string} color
|
|
199
|
+
* @returns {any[]}
|
|
200
|
+
*/
|
|
201
|
+
export declare function lineSeriesChildren(name: string, d: string, dots: any[], color: string): any[];
|
|
202
|
+
/**
|
|
203
|
+
* Render one series as its `<g>` group.
|
|
204
|
+
* @param {{name?: string, points: ({u:number,v:number}|null)[]}} s
|
|
205
|
+
* @param {number} si series index
|
|
206
|
+
* @param {{x:number,y:number,w:number,h:number}} plot
|
|
207
|
+
* @param {readonly string[]} palette
|
|
208
|
+
* @param {boolean} markers
|
|
209
|
+
* @param {import('../core/marks.js').ChartTooltip|null} [tooltip]
|
|
210
|
+
* @returns {LineSeriesRender}
|
|
211
|
+
*/
|
|
212
|
+
export declare function lineSeriesRender(s: {
|
|
213
|
+
name?: string;
|
|
214
|
+
points: ({
|
|
215
|
+
u: number;
|
|
216
|
+
v: number;
|
|
217
|
+
} | null)[];
|
|
218
|
+
}, si: number, plot: {
|
|
219
|
+
x: number;
|
|
220
|
+
y: number;
|
|
221
|
+
w: number;
|
|
222
|
+
h: number;
|
|
223
|
+
}, palette: readonly string[], markers: boolean, tooltip?: import('../core/marks.js').ChartTooltip | null): LineSeriesRender;
|
|
224
|
+
/**
|
|
225
|
+
* Render a line AST and return the svg WITH the geometry a session
|
|
226
|
+
* needs to patch it incrementally: the plot rect, how many chrome
|
|
227
|
+
* children precede the series groups, and each series' render parts.
|
|
228
|
+
* @param {LineAST} ast
|
|
229
|
+
* @param {{tokens: Record<string,string>, cssVars: Record<string,string>}} theme
|
|
230
|
+
* @param {string} hash
|
|
231
|
+
* @param {{rootClass?: string, keyPrefix?: string, palette?: readonly string[], width?: number,
|
|
232
|
+
* tooltip?: import('../core/marks.js').ChartTooltipSpec}} [options]
|
|
233
|
+
* @returns {{svg: any, plot: {x:number,y:number,w:number,h:number},
|
|
234
|
+
* chromeLen: number, series: LineSeriesRender[]}}
|
|
235
|
+
*/
|
|
236
|
+
export declare function buildLineRender(ast: LineAST, theme: {
|
|
237
|
+
tokens: Record<string, string>;
|
|
238
|
+
cssVars: Record<string, string>;
|
|
239
|
+
}, hash: string, options?: {
|
|
240
|
+
rootClass?: string;
|
|
241
|
+
keyPrefix?: string;
|
|
242
|
+
palette?: readonly string[];
|
|
243
|
+
width?: number;
|
|
244
|
+
tooltip?: import('../core/marks.js').ChartTooltipSpec;
|
|
245
|
+
}): {
|
|
246
|
+
svg: any;
|
|
247
|
+
plot: {
|
|
248
|
+
x: number;
|
|
249
|
+
y: number;
|
|
250
|
+
w: number;
|
|
251
|
+
h: number;
|
|
252
|
+
};
|
|
253
|
+
chromeLen: number;
|
|
254
|
+
series: LineSeriesRender[];
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Render a line AST to a pure-vnode SVG.
|
|
258
|
+
* @param {LineAST} ast
|
|
259
|
+
* @param {{tokens: Record<string,string>, cssVars: Record<string,string>}} theme
|
|
260
|
+
* @param {string} hash
|
|
261
|
+
* @param {{rootClass?: string, keyPrefix?: string, palette?: readonly string[], width?: number}} [options]
|
|
262
|
+
* @returns {any}
|
|
263
|
+
*/
|
|
264
|
+
export declare function renderLineAST(ast: LineAST, theme: {
|
|
265
|
+
tokens: Record<string, string>;
|
|
266
|
+
cssVars: Record<string, string>;
|
|
267
|
+
}, hash: string, options?: {
|
|
268
|
+
rootClass?: string;
|
|
269
|
+
keyPrefix?: string;
|
|
270
|
+
palette?: readonly string[];
|
|
271
|
+
width?: number;
|
|
272
|
+
}): any;
|