@pond-ts/charts 0.57.0 → 0.58.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 +1070 -1
- package/dist/AreaChart.d.ts +12 -1
- package/dist/AreaChart.js +131 -13
- package/dist/BarChart.js +184 -30
- package/dist/BarList.d.ts +85 -5
- package/dist/BarList.js +25 -4
- package/dist/BoxList.d.ts +70 -3
- package/dist/BoxList.js +21 -7
- package/dist/BoxPlot.d.ts +2 -1
- package/dist/BoxPlot.js +101 -9
- package/dist/Candlestick.d.ts +13 -1
- package/dist/Candlestick.js +89 -3
- package/dist/ChartContainer.d.ts +36 -48
- package/dist/ChartContainer.js +465 -59
- package/dist/ChartRow.d.ts +9 -2
- package/dist/ChartRow.js +86 -12
- package/dist/HeatMap.d.ts +176 -0
- package/dist/HeatMap.js +344 -0
- package/dist/Layers.d.ts +5 -1
- package/dist/Layers.js +1014 -253
- package/dist/Legend.js +8 -4
- package/dist/LineChart.d.ts +18 -1
- package/dist/LineChart.js +165 -4
- package/dist/ListTable.d.ts +30 -3
- package/dist/ListTable.js +381 -23
- package/dist/ScatterChart.d.ts +3 -2
- package/dist/ScatterChart.js +68 -4
- package/dist/XAxis.js +40 -22
- package/dist/area.d.ts +34 -1
- package/dist/area.js +88 -1
- package/dist/bars.d.ts +57 -3
- package/dist/bars.js +237 -26
- package/dist/box.d.ts +2 -2
- package/dist/box.js +158 -40
- package/dist/brush.d.ts +142 -0
- package/dist/brush.js +179 -0
- package/dist/child-index.d.ts +27 -0
- package/dist/child-index.js +57 -0
- package/dist/context.d.ts +859 -33
- package/dist/cursors.d.ts +161 -0
- package/dist/cursors.js +503 -0
- package/dist/decimate.d.ts +78 -1
- package/dist/decimate.js +157 -0
- package/dist/heat.d.ts +163 -0
- package/dist/heat.js +659 -0
- package/dist/index.d.ts +11 -2
- package/dist/index.js +22 -0
- package/dist/line.d.ts +137 -0
- package/dist/line.js +328 -0
- package/dist/ohlc.d.ts +16 -1
- package/dist/ohlc.js +93 -4
- package/dist/scatter.d.ts +17 -9
- package/dist/scatter.js +221 -33
- package/dist/select.d.ts +13 -5
- package/dist/select.js +14 -6
- package/dist/selection-fixtures.d.ts +174 -0
- package/dist/selection-fixtures.js +569 -0
- package/dist/selection-stories.d.ts +73 -0
- package/dist/selection-stories.js +301 -0
- package/dist/selectors.d.ts +316 -0
- package/dist/selectors.js +391 -0
- package/dist/span.d.ts +122 -0
- package/dist/span.js +203 -0
- package/dist/sweep.d.ts +154 -0
- package/dist/sweep.js +282 -0
- package/dist/theme.d.ts +456 -5
- package/dist/theme.js +217 -41
- package/dist/tracker.d.ts +6 -0
- package/dist/tracker.js +6 -0
- package/dist/tradingAxis.fixture.d.ts +78 -0
- package/dist/tradingAxis.fixture.js +215 -0
- package/dist/useChartLegend.js +18 -3
- package/package.json +3 -3
package/dist/theme.d.ts
CHANGED
|
@@ -89,6 +89,24 @@ export interface ChartTheme {
|
|
|
89
89
|
readonly default: CandleStyle;
|
|
90
90
|
readonly [semantic: string]: CandleStyle;
|
|
91
91
|
};
|
|
92
|
+
/**
|
|
93
|
+
* Map from a heat map's semantic identifier to its **interaction states**
|
|
94
|
+
* ({@link HeatMap}). Optional throughout; with no `heat` slot a live cell
|
|
95
|
+
* takes the pre-states treatment (one outline per cell, in
|
|
96
|
+
* `bar.highlight`).
|
|
97
|
+
*
|
|
98
|
+
* **Only the states, and deliberately so.** A heat map's *geometry* is
|
|
99
|
+
* bar-family — the slot gap, the minimum bin width, the outline weight —
|
|
100
|
+
* and it reads all of it from `bar[semantic] ?? bar.default`, which is
|
|
101
|
+
* right: a cell is a bar's slot with colour instead of height. What it
|
|
102
|
+
* cannot share is state styling, because a bar's fill is free and a cell's
|
|
103
|
+
* fill **is the datum** (see {@link HeatStates}). So the split is between
|
|
104
|
+
* the two things, not an accident of where the tokens landed.
|
|
105
|
+
*/
|
|
106
|
+
readonly heat?: {
|
|
107
|
+
readonly default: HeatStates;
|
|
108
|
+
readonly [semantic: string]: HeatStates;
|
|
109
|
+
};
|
|
92
110
|
/**
|
|
93
111
|
* Map from a bar's semantic identifier to its style — the fill, the
|
|
94
112
|
* selected-bar highlight, and the slot gap / minimum width ({@link BarChart}).
|
|
@@ -143,6 +161,29 @@ export interface ChartTheme {
|
|
|
143
161
|
};
|
|
144
162
|
/** Crosshair / tracker stroke colour. Falls back to {@link axis.label} if unset. */
|
|
145
163
|
readonly cursor?: string;
|
|
164
|
+
/**
|
|
165
|
+
* The **drag band** — the live region the shared brush paints while a drag
|
|
166
|
+
* is in flight (`<RangeCursor>`'s band and `<MultiSelector>`'s sweep are the
|
|
167
|
+
* same pixels; see `renderBrushBand`). `fill` washes the covered span and
|
|
168
|
+
* `edge` hairlines its two boundaries at 1px, so the band has a readable
|
|
169
|
+
* start/end while the gesture is still live.
|
|
170
|
+
*
|
|
171
|
+
* **Optional, and back-compatible when omitted:** with no `brush` the band
|
|
172
|
+
* falls back to the cursor ink at 0.12 with no edges — byte-for-byte what
|
|
173
|
+
* every theme drew before this token existed. `defaultTheme` opts in with
|
|
174
|
+
* the *selection* blue at 7%: the band is about to become a selection, so it
|
|
175
|
+
* should be the same hue as one (whereas the resting bars are teal).
|
|
176
|
+
*/
|
|
177
|
+
readonly brush?: {
|
|
178
|
+
/**
|
|
179
|
+
* The band's wash. Drawn at **full element opacity**, so carry the alpha
|
|
180
|
+
* in the colour (`rgba(…, 0.07)`) — a solid hex here paints over the marks
|
|
181
|
+
* the band is supposed to be previewing.
|
|
182
|
+
*/
|
|
183
|
+
readonly fill: string;
|
|
184
|
+
/** Stroke for the band's 1px start/end edges. Omit for a fill-only band. */
|
|
185
|
+
readonly edge?: string;
|
|
186
|
+
};
|
|
146
187
|
/**
|
|
147
188
|
* Readout chip background (the `flag` / `inline` tracker modes). The value text
|
|
148
189
|
* is the series colour; this is the panel behind it. Falls back to the plot
|
|
@@ -177,6 +218,18 @@ export interface ChartTheme {
|
|
|
177
218
|
*/
|
|
178
219
|
readonly annotation?: {
|
|
179
220
|
readonly color: string;
|
|
221
|
+
/**
|
|
222
|
+
* **EXPERIMENTAL ([PND-ANNSNAP]).** Ink for the vertical rules at a swept
|
|
223
|
+
* window's edges — a preview of what promoting the sweep to an annotation
|
|
224
|
+
* would look like. Lighter than {@link color} because these mark a
|
|
225
|
+
* *candidate* range rather than a committed mark. **Omitted ⇒ a light
|
|
226
|
+
* orange fallback.**
|
|
227
|
+
*
|
|
228
|
+
* Not settled: the rules are drawn canvas-side, under the trace ink,
|
|
229
|
+
* whereas a real annotation renders in the SVG overlay above it. If the
|
|
230
|
+
* look is kept, that mismatch has to be resolved rather than papered over.
|
|
231
|
+
*/
|
|
232
|
+
readonly spanEdge?: string;
|
|
180
233
|
readonly fillOpacity: number;
|
|
181
234
|
readonly depth: readonly [number, number, number];
|
|
182
235
|
/**
|
|
@@ -223,6 +276,58 @@ export interface ChartTheme {
|
|
|
223
276
|
readonly border: string;
|
|
224
277
|
readonly text: string;
|
|
225
278
|
};
|
|
279
|
+
/**
|
|
280
|
+
* The **row-chart register** — `<BarList>` / `<BoxList>`, whose row states
|
|
281
|
+
* live on chrome the canvas has no equivalent of.
|
|
282
|
+
*
|
|
283
|
+
* A row chart cannot signal state the way a column chart does. Two reasons,
|
|
284
|
+
* and the second is the load-bearing one:
|
|
285
|
+
*
|
|
286
|
+
* - **The row is the target, not the bar.** A vertical bar can be its own
|
|
287
|
+
* hit area because every mark spans the full column width; a row's mark
|
|
288
|
+
* is as short as its value, so a 4% row would be a 30px sliver. The
|
|
289
|
+
* label gutter, the track and the trailing value are one target, and the
|
|
290
|
+
* thing that lights has to be the whole **band**.
|
|
291
|
+
* - **The band carries selection alone.** In a multi-metric row the fill
|
|
292
|
+
* *is* the identity of the metric, so it cannot also carry state — the
|
|
293
|
+
* same channel rule the canvas marks follow. Band + rail must read as
|
|
294
|
+
* selected with no help from the fill, and designing the single-metric
|
|
295
|
+
* case that way too means one treatment covers every row chart.
|
|
296
|
+
*
|
|
297
|
+
* So the two values here are the ones with no canvas counterpart: the row
|
|
298
|
+
* **band** tints. Everything else resolves from tokens that already exist
|
|
299
|
+
* and are per-metric where they should be — a selected fill takes
|
|
300
|
+
* {@link BarStyle.highlight}, a dimmed one {@link BarStyle.dimmed} — so a
|
|
301
|
+
* consumer who themes their bars gets a coherent list without theming it
|
|
302
|
+
* twice.
|
|
303
|
+
*
|
|
304
|
+
* **The rail is deliberately NOT per-metric.** There is one rail per row
|
|
305
|
+
* and a row may carry several metrics, so it cannot resolve through
|
|
306
|
+
* `bar[as]` the way a fill does; it lives here with the bands.
|
|
307
|
+
*
|
|
308
|
+
* **Optional, and back-compatible when omitted:** with no `list` the rows
|
|
309
|
+
* keep exactly the pre-token look — a hover band from `legend.border`, a
|
|
310
|
+
* selection rail from the annotation register, and no dimmed state at all.
|
|
311
|
+
*/
|
|
312
|
+
readonly list?: {
|
|
313
|
+
/** Row stripe behind the hovered row — the whole band, gutter to value. */
|
|
314
|
+
readonly hoverBand: string;
|
|
315
|
+
/** The hovered row's 3px inset left edge. Never the selection hue. */
|
|
316
|
+
readonly hoverRail: string;
|
|
317
|
+
/** Row stripe behind a selected row. */
|
|
318
|
+
readonly selectedBand: string;
|
|
319
|
+
/** The selected row's 3px inset left edge. */
|
|
320
|
+
readonly selectedRail: string;
|
|
321
|
+
/**
|
|
322
|
+
* Reference ink — per-row target markers, thresholds, reference ticks.
|
|
323
|
+
*
|
|
324
|
+
* **Reserved away from the selection hue on purpose.** On a bullet row
|
|
325
|
+
* the marker sits *inside* the mark that selection recolors, so a tick
|
|
326
|
+
* in the selection blue is the one collision the rest of the language
|
|
327
|
+
* cannot absorb: you could not tell a target from a selected bar.
|
|
328
|
+
*/
|
|
329
|
+
readonly markerInk: string;
|
|
330
|
+
};
|
|
226
331
|
}
|
|
227
332
|
/** A resolved line style: stroke colour + width (px). */
|
|
228
333
|
export interface LineStyle {
|
|
@@ -237,6 +342,41 @@ export interface LineStyle {
|
|
|
237
342
|
* observed one at a glance.
|
|
238
343
|
*/
|
|
239
344
|
readonly dash?: readonly number[];
|
|
345
|
+
/**
|
|
346
|
+
* Stroke width when this trace is the **selected series**, and for the
|
|
347
|
+
* emphasised portion of a swept window. **Omitted ⇒ `width * 2`.**
|
|
348
|
+
*
|
|
349
|
+
* **State on a trace is WEIGHT, not hue** — the channel rule, and the same
|
|
350
|
+
* answer `<Candlestick>` got. A line's **colour is its identity**: it is how
|
|
351
|
+
* a reader tells one series from another in a multi-series plot, so a
|
|
352
|
+
* selected line that turned blue would trade the distinction they need for
|
|
353
|
+
* one they already have from the chrome. Thickening says "this one" without
|
|
354
|
+
* spending the channel that says "which one".
|
|
355
|
+
*/
|
|
356
|
+
readonly selectedWidth?: number;
|
|
357
|
+
/** Stroke width on **hover** — the transient echo of `selectedWidth`.
|
|
358
|
+
* **Omitted ⇒ `selectedWidth`**, so hover previews the committed weight. */
|
|
359
|
+
readonly hoverWidth?: number;
|
|
360
|
+
/**
|
|
361
|
+
* Alpha for a trace that is **outside** the active selection — another
|
|
362
|
+
* series is selected, or this trace is outside a swept window.
|
|
363
|
+
* **Omitted ⇒ `0.32`**, the value the rest of the palette recedes to.
|
|
364
|
+
*
|
|
365
|
+
* Alpha rather than a colour, deliberately: a muted line must still read as
|
|
366
|
+
* *which* series it is, so its hue has to survive being pushed back.
|
|
367
|
+
*/
|
|
368
|
+
readonly dimmedOpacity?: number;
|
|
369
|
+
/**
|
|
370
|
+
* Ink for the **swept window's** emphasised portion. **Omitted ⇒ the trace
|
|
371
|
+
* keeps its own colour and only thickens.**
|
|
372
|
+
*
|
|
373
|
+
* This is the one place a trace's state may take a hue, and the reason is
|
|
374
|
+
* that a window is a **region of one series** — identity is not in question
|
|
375
|
+
* there, because you can see which line you swept. So the region can read as
|
|
376
|
+
* the same act as the brush band that made it (the selection blue), where a
|
|
377
|
+
* whole-series selection cannot.
|
|
378
|
+
*/
|
|
379
|
+
readonly spanColor?: string;
|
|
240
380
|
}
|
|
241
381
|
/** A resolved band style: fill colour + opacity (0–1) for the variance envelope. */
|
|
242
382
|
export interface BandStyle {
|
|
@@ -265,6 +405,123 @@ export interface ScatterStyle {
|
|
|
265
405
|
readonly selectedWidth: number;
|
|
266
406
|
/** Colour of the optional per-point text label. */
|
|
267
407
|
readonly label: string;
|
|
408
|
+
/**
|
|
409
|
+
* The **interaction states** — fill and size per state, and the whole
|
|
410
|
+
* styling channel for a live point when set. Unset ⇒ the pre-states
|
|
411
|
+
* behaviour exactly: every point keeps its resting fill and radius, and a
|
|
412
|
+
* live one is merely re-ringed in `selectedOutline`/`selectedWidth`.
|
|
413
|
+
*
|
|
414
|
+
* A scatter can afford what a candle cannot. A candle's hue *is* its
|
|
415
|
+
* meaning (rising vs falling), so it carries state in weight and alpha
|
|
416
|
+
* alone; a heat cell's colour is its value, so it carries state in chrome.
|
|
417
|
+
* A point's colour encodes nothing by default, so it is free to recolour —
|
|
418
|
+
* and it also has a channel none of the column marks have: **size**.
|
|
419
|
+
*
|
|
420
|
+
* That is why hover and selection split the channels rather than sharing
|
|
421
|
+
* them. See {@link ScatterStates}.
|
|
422
|
+
*/
|
|
423
|
+
readonly states?: ScatterStates;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* A scatter point's per-state fill and size ({@link ScatterStyle.states}).
|
|
427
|
+
*
|
|
428
|
+
* The radii are given in px against {@link ScatterStyle.radius}, and applied
|
|
429
|
+
* as the **ratio** between them — so a data-driven `radius` encoding still
|
|
430
|
+
* grows and shrinks by the same proportion instead of being flattened to one
|
|
431
|
+
* size the moment a point goes live.
|
|
432
|
+
*/
|
|
433
|
+
export interface ScatterStates {
|
|
434
|
+
/**
|
|
435
|
+
* Fill for a **hovered** point — or one under a live drag rect, which is
|
|
436
|
+
* the same state (the sweep lights its covered marks through the plural
|
|
437
|
+
* `hovered`). A brightened form of the resting colour, not a new hue: the
|
|
438
|
+
* preview says "these are the ones", and saying it in the committed colour
|
|
439
|
+
* would make the preview and the commit read alike.
|
|
440
|
+
*/
|
|
441
|
+
readonly hover: string;
|
|
442
|
+
/** Hovered radius (px). Hover is the state that spends **size** — it is the
|
|
443
|
+
* channel a lone pointer-over can afford, and a hover does not have to
|
|
444
|
+
* survive being read against a whole field of committed marks. */
|
|
445
|
+
readonly hoverRadius: number;
|
|
446
|
+
/**
|
|
447
|
+
* Fill for a **selected** point. Its radius is deliberately left at
|
|
448
|
+
* {@link ScatterStyle.radius}: selection spends **hue** instead, so
|
|
449
|
+
* committing a sweep does not reflow the cloud under the pointer.
|
|
450
|
+
*/
|
|
451
|
+
readonly selected: string;
|
|
452
|
+
/** The ring around a live (hovered or selected) point — what keeps
|
|
453
|
+
* overlapping points countable once a whole swept region shares one fill. */
|
|
454
|
+
readonly halo: string;
|
|
455
|
+
/** Halo width (px); `0` draws none. */
|
|
456
|
+
readonly haloWidth: number;
|
|
457
|
+
/**
|
|
458
|
+
* Radius (px) of a point **outside a non-empty selection**. It shrinks as
|
|
459
|
+
* well as fading because alpha alone at these levels thins a cloud to
|
|
460
|
+
* nearly nothing, and the shape of the unselected field is the thing a
|
|
461
|
+
* scatter's background is *for*.
|
|
462
|
+
*/
|
|
463
|
+
readonly dimmedRadius: number;
|
|
464
|
+
/** Alpha of a point outside a non-empty selection. */
|
|
465
|
+
readonly dimmedOpacity: number;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* A heat map's **interaction states** ({@link ChartTheme.heat}).
|
|
469
|
+
*
|
|
470
|
+
* A cell has no spare channel at all. A bar's fill is free, so a bar swaps it;
|
|
471
|
+
* a point's colour encodes nothing by default, so a point recolours *and*
|
|
472
|
+
* resizes. A cell's colour **is** its value, and its rect is the grid — so
|
|
473
|
+
* every state here is **chrome added around the cell** or a transform applied
|
|
474
|
+
* uniformly to all of them, and none of them repaints a cell in a colour the
|
|
475
|
+
* ramp could also have produced.
|
|
476
|
+
*/
|
|
477
|
+
export interface HeatStates {
|
|
478
|
+
/**
|
|
479
|
+
* The flat overlay painted over a cell **outside a non-empty selection** —
|
|
480
|
+
* carry the alpha in the colour (`rgba(255,255,255,0.62)`), because it is
|
|
481
|
+
* composited over the cell, not applied as one.
|
|
482
|
+
*
|
|
483
|
+
* **A flat overlay, not `globalAlpha`, and the difference is the whole
|
|
484
|
+
* point.** Alpha and value are the same channel on a ramp, so fading a cell
|
|
485
|
+
* slides it along the scale — a dimmed dark cell becomes a resting mid one.
|
|
486
|
+
* An overlay is *uniform and monotonic*: every cell moves by the same
|
|
487
|
+
* transform, so the ramp's **order survives inside the veiled set** and only
|
|
488
|
+
* the cross-set comparison is ambiguous — which is exactly what the
|
|
489
|
+
* {@link perimeter} is there to disambiguate.
|
|
490
|
+
*
|
|
491
|
+
* It is also why this is a colour and not a number: opacity composites with
|
|
492
|
+
* whatever is *behind* the cell (a gridline, a non-white background, another
|
|
493
|
+
* layer), so the same value would veil to different colours in different
|
|
494
|
+
* charts. An overlay is a property of the cell.
|
|
495
|
+
*/
|
|
496
|
+
readonly veil: string;
|
|
497
|
+
/**
|
|
498
|
+
* The hovered cell's **double ring**, outer colour first — two concentric
|
|
499
|
+
* rings of {@link ringWidth}, both inside the cell.
|
|
500
|
+
*
|
|
501
|
+
* A single ring cannot work against a ramp: a light ring vanishes at the
|
|
502
|
+
* pale end and a dark one at the dark end, and a cell can be anywhere on the
|
|
503
|
+
* scale. The pair guarantees one of the two reads wherever the cell happens
|
|
504
|
+
* to sit. (The same problem `bar.binFills` has, and a better answer than
|
|
505
|
+
* picking one colour and hoping.)
|
|
506
|
+
*/
|
|
507
|
+
readonly hoverRing: readonly [string, string];
|
|
508
|
+
/** Width of each of the two hover rings, in px. */
|
|
509
|
+
readonly ringWidth: number;
|
|
510
|
+
/**
|
|
511
|
+
* The selected region's **perimeter** — one outline around the union of
|
|
512
|
+
* selected cells, not one per cell.
|
|
513
|
+
*
|
|
514
|
+
* Per-cell outlines are what this replaces, and the reason is legible in any
|
|
515
|
+
* screenshot of them: a bordered grid is mostly border, and every interior
|
|
516
|
+
* line says nothing, because it is interior to the selection. Drawn by
|
|
517
|
+
* suppressing each cell edge whose neighbour is also selected, so a
|
|
518
|
+
* selection in several disconnected pieces gets one outline **per piece**,
|
|
519
|
+
* and a hole in the middle of one gets its own — no connectivity pass, and
|
|
520
|
+
* no assumption that a selection is a single rectangle.
|
|
521
|
+
*/
|
|
522
|
+
readonly perimeter: string;
|
|
523
|
+
/** Perimeter stroke width, in px. */
|
|
524
|
+
readonly perimeterWidth: number;
|
|
268
525
|
}
|
|
269
526
|
/**
|
|
270
527
|
* A resolved box-and-whisker style ({@link BoxPlot}). The q1→q3 box is a filled
|
|
@@ -282,6 +539,68 @@ export interface BoxStyle {
|
|
|
282
539
|
readonly medianWidth: number;
|
|
283
540
|
readonly whisker: string;
|
|
284
541
|
readonly whiskerWidth: number;
|
|
542
|
+
/**
|
|
543
|
+
* The **tint ladder** — one four-step ladder per interaction state, and the
|
|
544
|
+
* whole styling channel for a box when set. Unset ⇒ the flat
|
|
545
|
+
* `fill`/`stroke`/`median`/`whisker` tokens above, unchanged.
|
|
546
|
+
*
|
|
547
|
+
* Every mark of a box reads its step from the *same* ladder
|
|
548
|
+
* ({@link BoxLadder} documents which step is which), so a state change is a
|
|
549
|
+
* **single palette swap** rather than four independent colour decisions.
|
|
550
|
+
* That is what keeps the quantile read intact across states: the ladder
|
|
551
|
+
* carries its meaning in *lightness*, so moving the whole ladder — brighter
|
|
552
|
+
* teal on hover, blue when committed — leaves every relationship between the
|
|
553
|
+
* marks untouched.
|
|
554
|
+
*
|
|
555
|
+
* Two consequences worth stating, because both are the opposite of what the
|
|
556
|
+
* multi-hue `bar` palette needs:
|
|
557
|
+
*
|
|
558
|
+
* - **Shift the ladder, not one step.** Recolouring only the median, or only
|
|
559
|
+
* the body, breaks the read. All four steps move together and keep their
|
|
560
|
+
* relative lightness spacing.
|
|
561
|
+
* - **Dim without desaturating.** A single-hue ladder has nothing to muddy
|
|
562
|
+
* into, so {@link dimmedOpacity} alone is the receded state — no
|
|
563
|
+
* desaturated companion ladder of the kind `bar.groupsDimmed` needs.
|
|
564
|
+
*/
|
|
565
|
+
readonly states?: BoxStates;
|
|
566
|
+
/**
|
|
567
|
+
* Stroke width for a **selected** box's hairlines — the body outline and the
|
|
568
|
+
* whiskers both. Unset ⇒ they keep {@link strokeWidth} / {@link whiskerWidth}.
|
|
569
|
+
*
|
|
570
|
+
* A hairline cannot carry a state in hue alone: at 1px a colour change is
|
|
571
|
+
* nearly invisible, and the whisker is the mark that reaches furthest. A
|
|
572
|
+
* weight change is legible at any width, so selection bumps it (1 → 1.5 on
|
|
573
|
+
* `defaultTheme`) alongside the ladder swap.
|
|
574
|
+
*/
|
|
575
|
+
readonly selectedStrokeWidth?: number;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* A box's four tint steps, lightest → darkest. Which mark reads which step:
|
|
579
|
+
*
|
|
580
|
+
* | step | box plot | quantile bands |
|
|
581
|
+
* | ---- | --------------- | -------------- |
|
|
582
|
+
* | `0` | body fill / the solid shape's outer bar | outer band |
|
|
583
|
+
* | `1` | the solid shape's inner q1→q3 bar | inner band |
|
|
584
|
+
* | `2` | body stroke + whiskers | — |
|
|
585
|
+
* | `3` | the median rule | median rule |
|
|
586
|
+
*
|
|
587
|
+
* Steps are *positions on one hue's lightness ramp*, not four palette entries —
|
|
588
|
+
* a ladder whose steps don't descend in lightness stops encoding anything.
|
|
589
|
+
*/
|
|
590
|
+
export type BoxLadder = readonly [string, string, string, string];
|
|
591
|
+
/** The per-state ladders (see {@link BoxStyle.states}). */
|
|
592
|
+
export interface BoxStates {
|
|
593
|
+
/** Nothing selected anywhere. */
|
|
594
|
+
readonly rest: BoxLadder;
|
|
595
|
+
/** Pointer over this box — a preview of what a click would commit, so it
|
|
596
|
+
* sits between {@link rest} and {@link selected} in strength. */
|
|
597
|
+
readonly hover: BoxLadder;
|
|
598
|
+
/** Committed. Pairs with {@link BoxStyle.selectedStrokeWidth}. */
|
|
599
|
+
readonly selected: BoxLadder;
|
|
600
|
+
/** How far a box **outside** a non-empty selection recedes — the
|
|
601
|
+
* {@link rest} ladder at this alpha. No separate ladder, and deliberately
|
|
602
|
+
* no desaturation (see {@link BoxStyle.states}). */
|
|
603
|
+
readonly dimmedOpacity: number;
|
|
285
604
|
}
|
|
286
605
|
/**
|
|
287
606
|
* A resolved candlestick style ({@link Candlestick}). A candle is unreadable in
|
|
@@ -309,6 +628,41 @@ export interface CandleStyle {
|
|
|
309
628
|
readonly body: string;
|
|
310
629
|
readonly wick: string;
|
|
311
630
|
};
|
|
631
|
+
/**
|
|
632
|
+
* The **interaction state** cues — and note what is *missing* from them.
|
|
633
|
+
*
|
|
634
|
+
* A `bar` swaps its fill and a `box` rotates its whole tint ladder, because
|
|
635
|
+
* on those marks hue is free: the meaning lives in position and in lightness
|
|
636
|
+
* ordering. **A candle's hue is its meaning** — rising vs falling is the
|
|
637
|
+
* first thing anyone reads off it — so a candle introduces *no state colour
|
|
638
|
+
* at all*, not even for its outline. Every cue here is a change of weight or
|
|
639
|
+
* of alpha:
|
|
640
|
+
*
|
|
641
|
+
* - **Live** (hovered *or* selected) — the candle **grows**: its body is
|
|
642
|
+
* stroked in its own colour and its lines thicken to
|
|
643
|
+
* {@link liveWickWidth}, so the mark gets a little heavier and nothing
|
|
644
|
+
* else about it changes. Nothing is recoloured, and nothing is added that
|
|
645
|
+
* the chart doesn't otherwise draw.
|
|
646
|
+
* - **Selected** — the same, plus the rest of the field recedes to
|
|
647
|
+
* {@link dimmedOpacity}. The dimming is what separates a committed
|
|
648
|
+
* selection from a passing hover, since the lit mark looks identical
|
|
649
|
+
* either way.
|
|
650
|
+
*
|
|
651
|
+
* That last point is deliberate but worth knowing: hover and selection are
|
|
652
|
+
* distinguished by what happens to the *other* candles, not by this one.
|
|
653
|
+
*
|
|
654
|
+
* Both optional; unset ⇒ a display-only candle exactly as before.
|
|
655
|
+
*/
|
|
656
|
+
readonly dimmedOpacity?: number;
|
|
657
|
+
/**
|
|
658
|
+
* Line weight for a **live** (hovered or selected) candle — its wick, and
|
|
659
|
+
* the stroke around its body that makes the mark grow.
|
|
660
|
+
*
|
|
661
|
+
* Unlike {@link BoxStyle.selectedStrokeWidth}, which only selection triggers,
|
|
662
|
+
* this fires on hover too: a box announces hover by moving its tint ladder,
|
|
663
|
+
* and a candle has no ladder to move.
|
|
664
|
+
*/
|
|
665
|
+
readonly liveWickWidth?: number;
|
|
312
666
|
/** Doji (open === close) — body + wick colours; falls back to `rising` if unset. */
|
|
313
667
|
readonly neutral?: {
|
|
314
668
|
readonly body: string;
|
|
@@ -343,6 +697,25 @@ export interface AreaStyle {
|
|
|
343
697
|
* a stack can be uniformly translucent — just not *graded*.)
|
|
344
698
|
*/
|
|
345
699
|
readonly flatFill?: boolean;
|
|
700
|
+
/**
|
|
701
|
+
* Interaction state, the area's counterpart of `LineStyle`'s
|
|
702
|
+
* ([PND-TRACESEL]) — and the channels differ because what carries the mark
|
|
703
|
+
* differs. An area's mark is its **fill**, so state is the fill's *strength*
|
|
704
|
+
* plus the edge's weight; a line's mark is a stroke, so state is weight alone.
|
|
705
|
+
*
|
|
706
|
+
* `selectedWidth` thickens the edge, `selectedFillOpacity` strengthens the
|
|
707
|
+
* fill, `dimmedOpacity` recedes the whole shape, and `spanColor` is the one
|
|
708
|
+
* hue a swept **window** may take (identity is not in question inside a
|
|
709
|
+
* single series — see `LineStyle.spanColor`).
|
|
710
|
+
*/
|
|
711
|
+
readonly selectedWidth?: number;
|
|
712
|
+
/** Fill opacity when selected. **Omitted ⇒ `min(fillOpacity * 2, 1)`.** */
|
|
713
|
+
readonly selectedFillOpacity?: number;
|
|
714
|
+
/** Alpha for an area outside the active selection. **Omitted ⇒ `0.32`.** */
|
|
715
|
+
readonly dimmedOpacity?: number;
|
|
716
|
+
/** Ink for a swept window's emphasised portion (edge + fill).
|
|
717
|
+
* **Omitted ⇒ the area keeps its own colours and only strengthens.** */
|
|
718
|
+
readonly spanColor?: string;
|
|
346
719
|
}
|
|
347
720
|
/**
|
|
348
721
|
* A resolved bar style: the flat `fill` (scaled by `opacity`, 0–1) plus the
|
|
@@ -412,6 +785,50 @@ export interface BarStyle {
|
|
|
412
785
|
* already one slice of a total has no defined meaning.
|
|
413
786
|
*/
|
|
414
787
|
readonly bands?: readonly string[];
|
|
788
|
+
/**
|
|
789
|
+
* The **stack group ramp** — ordered fills for a *multi-group* stack's
|
|
790
|
+
* segments, `groups[0]` for the first (bottom / left) group. Cycles when the
|
|
791
|
+
* stack has more groups than the ramp has entries.
|
|
792
|
+
*
|
|
793
|
+
* Sibling of {@link bands}, and here for the same reason (a `theme.bar`
|
|
794
|
+
* top-level key would collide with a role of that name) — but a different
|
|
795
|
+
* axis: `bands` colours one bar *along its length* against a threshold
|
|
796
|
+
* ladder, this colours *across the groups* of one bin.
|
|
797
|
+
*
|
|
798
|
+
* **Multi-group only.** A ramp exists to tell groups apart, so with one group
|
|
799
|
+
* there is nothing to tell apart and the bar keeps its {@link fill} — which
|
|
800
|
+
* is what keeps every categorical and single-series chart (both of which run
|
|
801
|
+
* the stacked draw path with `G === 1`) exactly as it was.
|
|
802
|
+
*
|
|
803
|
+
* Resolution order per group: `<BarChart colors>` → a theme role named after
|
|
804
|
+
* the group (`bar.web`) → this ramp → {@link fill}. So a named role still
|
|
805
|
+
* wins, and the ramp is the fallback that makes an *unthemed* stack legible
|
|
806
|
+
* instead of painting every segment one colour.
|
|
807
|
+
*/
|
|
808
|
+
readonly groups?: readonly string[];
|
|
809
|
+
/**
|
|
810
|
+
* The receded counterpart of {@link groups}, same order and cycling — what a
|
|
811
|
+
* segment fades to when a selection exists elsewhere.
|
|
812
|
+
*
|
|
813
|
+
* Per-group rather than the flat {@link dimmed}, because a stack dimmed to a
|
|
814
|
+
* single colour stops being a stack: the segment boundaries vanish and the
|
|
815
|
+
* unselected columns read as solid blocks. Each entry is its ramp colour
|
|
816
|
+
* desaturated and lightened, so the bin keeps its structure while clearly
|
|
817
|
+
* receding.
|
|
818
|
+
*/
|
|
819
|
+
readonly groupsDimmed?: readonly string[];
|
|
820
|
+
/**
|
|
821
|
+
* The **hovered** counterpart of {@link groups}, same order and cycling.
|
|
822
|
+
*
|
|
823
|
+
* Per-group for the reason the flat {@link hover} cannot be: one hover
|
|
824
|
+
* colour repaints whichever segment the pointer is over in a hue belonging
|
|
825
|
+
* to a different group, so pointing at a stack momentarily *erases the
|
|
826
|
+
* ramp* — and under a `<MultiSelector>`, where hover is block-scoped, it
|
|
827
|
+
* erases the whole bin at once. Each entry is its ramp colour brightened
|
|
828
|
+
* (same hue, lighter), the same relationship {@link fill} has to
|
|
829
|
+
* {@link hover}.
|
|
830
|
+
*/
|
|
831
|
+
readonly groupsHover?: readonly string[];
|
|
415
832
|
/**
|
|
416
833
|
* Stroke for a **selected** bar's outline, where the default is the bar's own
|
|
417
834
|
* resolved fill. The one selection cue that still works when the fill cannot
|
|
@@ -427,13 +844,47 @@ export interface BarStyle {
|
|
|
427
844
|
* live — which is the part that reads as emphasis.
|
|
428
845
|
*/
|
|
429
846
|
readonly emphasisOpacity?: number;
|
|
847
|
+
/**
|
|
848
|
+
* The fill for a bar that is **not** in a non-empty selection set — the
|
|
849
|
+
* "everything else recedes" state a chart used as a filter control needs
|
|
850
|
+
* ([PND-MULTISEL]).
|
|
851
|
+
*
|
|
852
|
+
* **Opt-in by construction:** a theme that sets no `dimmed` dims nothing, so
|
|
853
|
+
* existing charts are untouched (RFC `selection.md` A2.3 — the library never
|
|
854
|
+
* auto-dims; the theme carries the selection-state styling and the library
|
|
855
|
+
* references it by state). Nothing dims while the set is empty either: with
|
|
856
|
+
* no selection there is nothing to recede *from*.
|
|
857
|
+
*
|
|
858
|
+
* It exists because "not in the selection" was otherwise re-invented per
|
|
859
|
+
* component, and drifted immediately — one consumer had three charts using
|
|
860
|
+
* `color-mix` at 22%, 28% and 30% for the same concept, in the same week, for
|
|
861
|
+
* no reason. One theme value fixes that permanently.
|
|
862
|
+
*/
|
|
863
|
+
readonly dimmed?: string;
|
|
430
864
|
}
|
|
431
865
|
/**
|
|
432
|
-
* The neutral default theme.
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
*
|
|
436
|
-
* `
|
|
866
|
+
* The neutral default theme. The shared data hue is a cerulean (`#0284c7`)
|
|
867
|
+
* across `line` / `band` / `area` / `scatter` / `box` / candle-rising, chosen
|
|
868
|
+
* to clear the bar palette's *selection* blue (`#3F5BE0`) — the original M1
|
|
869
|
+
* royal blue (`#2563eb`) sat ~ΔE 5 from it, so a line drawn over bars read as
|
|
870
|
+
* nearly the selection colour. `primary` / `secondary` / `context` are a
|
|
871
|
+
* built-in generic role vocabulary; an unrecognised (e.g. domain-specific)
|
|
872
|
+
* identifier falls back to `default`.
|
|
873
|
+
*
|
|
874
|
+
* **Spreading this inherits every slot you don't override** — including colours
|
|
875
|
+
* for layers you haven't added yet, so a `{ ...defaultTheme, bar: … }` theme
|
|
876
|
+
* paints this blue the first time someone drops in a `<LineChart>`. That is the
|
|
877
|
+
* intended workflow, not a trap: take the defaults, change the one or two things
|
|
878
|
+
* that are yours. A design system that must own *every* colour should assert on
|
|
879
|
+
* that in its own test rather than catch it in review — walk the resolved theme
|
|
880
|
+
* for values outside your palette ([PND-THEMEBASE]).
|
|
881
|
+
*
|
|
882
|
+
* **The `bar` slot is the exception to "one blue".** Bars carry an interaction
|
|
883
|
+
* state (rest / hover / selected / dimmed), and encoding four states as four
|
|
884
|
+
* shades of one hue is unreadable — so `bar.default` runs its own
|
|
885
|
+
* **interaction-state palette**: teal at rest, blue when selected, brighter
|
|
886
|
+
* teal on hover. See the comment on that slot, and `brush` for the matching
|
|
887
|
+
* drag band.
|
|
437
888
|
*/
|
|
438
889
|
export declare const defaultTheme: ChartTheme;
|
|
439
890
|
/**
|