@pond-ts/charts 0.57.0 → 0.59.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/API.md +576 -0
- package/CHANGELOG.md +1213 -1
- package/dist/AreaChart.d.ts +12 -1
- package/dist/AreaChart.js +131 -13
- package/dist/BarChart.d.ts +56 -7
- package/dist/BarChart.js +263 -39
- 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 +176 -14
- 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/YAxis.d.ts +58 -2
- package/dist/YAxis.js +3 -1
- package/dist/area.d.ts +34 -1
- package/dist/area.js +88 -1
- package/dist/bars.d.ts +67 -6
- package/dist/bars.js +250 -35
- 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 +870 -39
- package/dist/cursors.d.ts +161 -0
- package/dist/cursors.js +503 -0
- package/dist/data.d.ts +38 -0
- package/dist/data.js +43 -0
- package/dist/decimate.d.ts +78 -1
- package/dist/decimate.js +157 -0
- package/dist/format.d.ts +15 -0
- package/dist/format.js +16 -1
- package/dist/heat.d.ts +163 -0
- package/dist/heat.js +659 -0
- package/dist/index.d.ts +13 -4
- package/dist/index.js +27 -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/range.d.ts +14 -1
- package/dist/range.js +24 -3
- 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 +510 -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/dist/yticks.d.ts +3 -0
- package/dist/yticks.js +104 -0
- package/package.json +6 -5
package/dist/BoxList.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type ReactNode } from 'react';
|
|
|
2
2
|
import type { SeriesSchema, ValueSeriesSchema } from 'pond-ts';
|
|
3
3
|
import { type BoxListColumn, type ListCellSpec, type ListMarker, type ListRow, type ListSortDirection } from './list.js';
|
|
4
4
|
import { type ListRowsSource, type ListSeriesSource } from './list-source.js';
|
|
5
|
+
import type { SelectModifiers } from './context.js';
|
|
5
6
|
import { type ChartTheme } from './theme.js';
|
|
6
7
|
/** The props both BoxList source doors share. */
|
|
7
8
|
export interface BoxListCommon<R extends ListRow = ListRow> {
|
|
@@ -41,10 +42,76 @@ export interface BoxListCommon<R extends ListRow = ListRow> {
|
|
|
41
42
|
defaultExpanded?: readonly string[];
|
|
42
43
|
/** Observe a toggle (`expanded` is the row's new state). */
|
|
43
44
|
onExpandToggle?: (key: string, expanded: boolean) => void;
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
/**
|
|
46
|
+
* The selected row(s), marked with an inset edge in the annotation (marks)
|
|
47
|
+
* register — selection is a user's mark, not data. Consumer-owned state:
|
|
48
|
+
* pair with {@link onRowClick}. `null` / omitted ⇒ none.
|
|
49
|
+
*
|
|
50
|
+
* **Accepts one key or a set**, the same union {@link hovered} takes
|
|
51
|
+
* ([PND-INTERACTCONF] / RFC `interaction.md` A3.1 — the list family speaks
|
|
52
|
+
* the canvas's interaction vocabulary, not a parallel one). Plural because
|
|
53
|
+
* a range of rows can be selected at once; passing a bare key still means
|
|
54
|
+
* exactly what it looks like.
|
|
55
|
+
*
|
|
56
|
+
* The library applies **no set arithmetic** — it renders what you hand back.
|
|
57
|
+
*/
|
|
58
|
+
selected?: string | readonly string[] | null;
|
|
59
|
+
/** Row click (also gates the pointer affordance). */
|
|
47
60
|
onRowClick?: (row: R) => void;
|
|
61
|
+
/**
|
|
62
|
+
* **Plural select** — the list's answer to `<MultiSelector>`, and how a user
|
|
63
|
+
* produces a multi-row {@link selected}.
|
|
64
|
+
*
|
|
65
|
+
* Fires with the rows the gesture took plus its modifiers:
|
|
66
|
+
*
|
|
67
|
+
* - a **click** reports `[row]` — so this is a strict *superset* of
|
|
68
|
+
* {@link onRowClick}, the way `<MultiSelector>` is of `<Selector>`;
|
|
69
|
+
* - a **drag across rows** reports the whole inclusive run, in display
|
|
70
|
+
* order.
|
|
71
|
+
*
|
|
72
|
+
* **Mounting it is what enables the drag** (interaction RFC A4.2 rule 1 —
|
|
73
|
+
* the same rule that makes a bare `<MultiSelector />` enable the canvas
|
|
74
|
+
* sweep). A list with only `onRowClick` behaves exactly as it always has.
|
|
75
|
+
*
|
|
76
|
+
* **Crossing into another row is what makes it a range**, not a pixel slop:
|
|
77
|
+
* a row is tall and discrete, so a press-and-release on one row is always a
|
|
78
|
+
* click, and a horizontal wobble — which on a stack of rows means nothing —
|
|
79
|
+
* can never commit one. While the drag runs, the covered rows light as
|
|
80
|
+
* *hovered*: that is the live preview of what releasing would take, and it
|
|
81
|
+
* out-ranks {@link hovered} for the duration without touching it.
|
|
82
|
+
*
|
|
83
|
+
* **The library holds no state and applies no set arithmetic.** You get the
|
|
84
|
+
* run and the modifiers; you decide whether to replace or union, and feed
|
|
85
|
+
* the result back through {@link selected}:
|
|
86
|
+
*
|
|
87
|
+
* ```tsx
|
|
88
|
+
* onRowSelect={(rows, m) =>
|
|
89
|
+
* setSel((cur) => {
|
|
90
|
+
* const keys = rows.map((r) => r.key);
|
|
91
|
+
* return m.additive ? [...new Set([...cur, ...keys])] : keys;
|
|
92
|
+
* })
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* `modifiers.additive` is the platform-idiomatic add chord already resolved
|
|
97
|
+
* (⌘ on macOS, Ctrl elsewhere). **`shiftKey` is reported but carries no
|
|
98
|
+
* built-in meaning** — an ordinal range is a gesture here, not a modifier
|
|
99
|
+
* (see `SelectModifiers`), so a shift-click extend is yours to define if you
|
|
100
|
+
* want one.
|
|
101
|
+
*/
|
|
102
|
+
onRowSelect?: (rows: readonly R[], modifiers: SelectModifiers) => void;
|
|
103
|
+
/**
|
|
104
|
+
* Controlled **hover-highlight** — the lit row key(s), or `null`; **omitted
|
|
105
|
+
* ⇒ uncontrolled**. Accepts one key or a set, the same union
|
|
106
|
+
* `<Selector hovered>` takes, so an external hover (a chart mark, a map
|
|
107
|
+
* segment) lights rows from outside. See `<BarList>`'s `hovered` for the
|
|
108
|
+
* full note.
|
|
109
|
+
*/
|
|
110
|
+
hovered?: string | readonly string[] | null;
|
|
111
|
+
/** Hover out: the entered row, or `null` on leaving the rows — deduped by
|
|
112
|
+
* row key, fires controlled or uncontrolled. Pair with {@link hovered} to
|
|
113
|
+
* sync hover both ways. */
|
|
114
|
+
onHover?: (row: R | null) => void;
|
|
48
115
|
/** Each box line's height in px. **Omitted ⇒ `10`.** */
|
|
49
116
|
barHeight?: number;
|
|
50
117
|
/** Rule between rows. **Omitted ⇒ `true`.** */
|
package/dist/BoxList.js
CHANGED
|
@@ -35,7 +35,7 @@ export function BoxList(props) {
|
|
|
35
35
|
// One normalized view of the union — `isSeriesSource` is the runtime
|
|
36
36
|
// narrowing; the doors are mutually exclusive by construction now.
|
|
37
37
|
const source = props;
|
|
38
|
-
const { rows, series, label, columns, domain, sortBy, sortDirection = 'desc', sort, before, after, renderExpanded, defaultExpanded, onExpandToggle, selected, onRowClick, markers, barHeight = 10, divided, baseline = true, theme = defaultTheme, } = source;
|
|
38
|
+
const { rows, series, label, columns, domain, sortBy, sortDirection = 'desc', sort, before, after, renderExpanded, defaultExpanded, onExpandToggle, selected, onRowClick, onRowSelect, hovered, onHover, markers, barHeight = 10, divided, baseline = true, theme = defaultTheme, } = source;
|
|
39
39
|
// A runtime guard for JS consumers and `any`-typed call sites — the
|
|
40
40
|
// props union makes both branches unreachable from typed TS, but a
|
|
41
41
|
// silently-ignored source prop is a worse failure than a throw.
|
|
@@ -58,13 +58,10 @@ export function BoxList(props) {
|
|
|
58
58
|
frac: listFraction(m.value, scale),
|
|
59
59
|
...(m.label !== undefined ? { label: m.label } : {}),
|
|
60
60
|
})), [markers, scale]);
|
|
61
|
-
return (_jsx(ListTable, { rows: sorted, kind: "box", markers: resolvedMarkers, before: before, after: after, renderExpanded: renderExpanded, defaultExpanded: defaultExpanded, onExpandToggle: onExpandToggle, selected: selected, onRowClick: onRowClick, divided: divided, baseline: baseline, theme: theme, renderGlyphs: (row) => (_jsx(_Fragment, { children: columns.map((col, ci) => (_jsx(BoxLine
|
|
62
|
-
// Index-qualified so two lines over the same quantile names
|
|
63
|
-
// (say, styled differently) never collide.
|
|
64
|
-
, { row: row, col: col, scale: scale, height: barHeight, style: theme.box[col.as ?? 'default'] ?? theme.box.default, ink: listInk(theme), fontSize: theme.font.size }, `${ci} ${col.lower} ${col.upper}`))) })) }));
|
|
61
|
+
return (_jsx(ListTable, { rows: sorted, kind: "box", markers: resolvedMarkers, before: before, after: after, renderExpanded: renderExpanded, defaultExpanded: defaultExpanded, onExpandToggle: onExpandToggle, selected: selected, onRowClick: onRowClick, onRowSelect: onRowSelect, hovered: hovered, onHover: onHover, divided: divided, baseline: baseline, theme: theme, renderGlyphs: (row, state) => (_jsx(_Fragment, { children: columns.map((col, ci) => (_jsx(BoxLine, { dimmed: state.dimmed, row: row, col: col, scale: scale, height: barHeight, style: theme.box[col.as ?? 'default'] ?? theme.box.default, ink: listInk(theme), fontSize: theme.font.size }, `${ci} ${col.lower} ${col.upper}`))) })) }));
|
|
65
62
|
}
|
|
66
63
|
/** One horizontal box line: range band → body → median → current tick + label. */
|
|
67
|
-
function BoxLine({ row, col, scale, height, style, ink, fontSize, }) {
|
|
64
|
+
function BoxLine({ row, col, scale, height, style, ink, fontSize, dimmed, }) {
|
|
68
65
|
const at = (name) => name === undefined ? null : listFraction(row.values[name], scale);
|
|
69
66
|
const lo = at(col.lower);
|
|
70
67
|
const hi = at(col.upper);
|
|
@@ -77,6 +74,21 @@ function BoxLine({ row, col, scale, height, style, ink, fontSize, }) {
|
|
|
77
74
|
? col.format(raw)
|
|
78
75
|
: null;
|
|
79
76
|
const pct = (f) => `${f * 100}%`;
|
|
77
|
+
/**
|
|
78
|
+
* The dim multiplier for this line's **marks** — body, median, tick.
|
|
79
|
+
*
|
|
80
|
+
* Not the range band below it: that is the row's *scale*, the thing that
|
|
81
|
+
* makes one row comparable with the next, and receding it alongside the
|
|
82
|
+
* marks is exactly the mistake `ChartTheme.list`'s track rule names. It is
|
|
83
|
+
* the box list's track.
|
|
84
|
+
*
|
|
85
|
+
* **Selection is deliberately absent here.** Rule 2 is that band + rail
|
|
86
|
+
* read as selected with no help from the fill, and a box has four inks
|
|
87
|
+
* (whisker, body, median, tick) rather than the one a bar has — "the fill
|
|
88
|
+
* goes blue" has no single referent. So a selected box row is signalled by
|
|
89
|
+
* its chrome alone, which the rule says is sufficient by design.
|
|
90
|
+
*/
|
|
91
|
+
const dim = dimmed ? 0.32 : 1;
|
|
80
92
|
// The row keeps its slot height even when everything is missing — a gap
|
|
81
93
|
// reads as an empty line, not a collapsed row.
|
|
82
94
|
return (_jsxs("div", { "data-list-boxline": "", style: { position: 'relative', height: height + 4, margin: '2px 0' }, children: [lo !== null && hi !== null && (_jsx("div", { "data-list-range": "", style: {
|
|
@@ -95,7 +107,7 @@ function BoxLine({ row, col, scale, height, style, ink, fontSize, }) {
|
|
|
95
107
|
left: pct(q1),
|
|
96
108
|
width: pct(Math.max(q3 - q1, 0)),
|
|
97
109
|
background: style.fill,
|
|
98
|
-
opacity: Math.min(style.fillOpacity * 2, 1),
|
|
110
|
+
opacity: Math.min(style.fillOpacity * 2, 1) * dim,
|
|
99
111
|
borderRadius: 1,
|
|
100
112
|
} })), med !== null && (_jsx("div", { "data-list-median": "", style: {
|
|
101
113
|
position: 'absolute',
|
|
@@ -104,6 +116,7 @@ function BoxLine({ row, col, scale, height, style, ink, fontSize, }) {
|
|
|
104
116
|
left: `calc(${pct(med)} - ${style.medianWidth / 2}px)`,
|
|
105
117
|
width: style.medianWidth,
|
|
106
118
|
background: style.median,
|
|
119
|
+
opacity: dim,
|
|
107
120
|
} })), tick !== null && (_jsxs(_Fragment, { children: [_jsx("div", { "data-list-tick": "", style: {
|
|
108
121
|
position: 'absolute',
|
|
109
122
|
top: 0,
|
|
@@ -112,6 +125,7 @@ function BoxLine({ row, col, scale, height, style, ink, fontSize, }) {
|
|
|
112
125
|
width: 3,
|
|
113
126
|
background: style.stroke,
|
|
114
127
|
borderRadius: 1,
|
|
128
|
+
opacity: dim,
|
|
115
129
|
} }), label !== null && (_jsx("span", { "data-list-value": "", style: {
|
|
116
130
|
position: 'absolute',
|
|
117
131
|
left: `calc(${pct(tick)} + 8px)`,
|
package/dist/BoxPlot.d.ts
CHANGED
|
@@ -66,7 +66,8 @@ export interface BoxPlotCommon<S extends SeriesSchema = SeriesSchema, VS extends
|
|
|
66
66
|
* contract `<BarChart>` / `<ScatterChart>` carry. With an `id`, a click on a
|
|
67
67
|
* box (body or whisker — a range-only bid→ask segment included) selects it
|
|
68
68
|
* (`selected`/`onSelect`) and pointer-over lights it (`hovered`/`onHover`);
|
|
69
|
-
*
|
|
69
|
+
* **every** box matching a selection member's `(id, key)` outlines, so a
|
|
70
|
+
* multi-mark `selected` set lights all of it. **Omitted ⇒
|
|
70
71
|
* display-only** (a click resolves to empty space). `key` is the box's `x`
|
|
71
72
|
* (its `begin`).
|
|
72
73
|
*/
|
package/dist/BoxPlot.js
CHANGED
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
import { useContext, useEffect, useMemo } from 'react';
|
|
2
|
-
import { ValueSeries } from 'pond-ts';
|
|
2
|
+
import { Interval, ValueSeries } from 'pond-ts';
|
|
3
|
+
import { sweep1D } from './sweep.js';
|
|
3
4
|
import { boxFromTimeSeries, boxFromValueSeries } from './data.js';
|
|
4
5
|
import { boxAt, boxExtent, boxIndexAtTime, drawBox, isFiniteBox, } from './box.js';
|
|
6
|
+
import { spansForLayer } from './span.js';
|
|
5
7
|
import { ContainerContext, LayersContext, } from './context.js';
|
|
6
8
|
import { legendLabelFor, useLegendItems, } from './swatch.js';
|
|
7
9
|
import { useSlotKey } from './use-slot-key.js';
|
|
8
10
|
/** Whisker collapse floor (px) — a too-thin box still draws a 1px mark. */
|
|
9
11
|
const MIN_BOX_WIDTH_PX = 1;
|
|
12
|
+
/** Stable identity for "no keys of ours in this set" — the resting case, so the
|
|
13
|
+
* layer doesn't re-register (and the canvas doesn't repaint) every time some
|
|
14
|
+
* *other* layer's selection changes. */
|
|
15
|
+
const NO_KEYS = [];
|
|
16
|
+
/**
|
|
17
|
+
* The keys of every member of `set` naming this layer (`m.id === id`) — the
|
|
18
|
+
* narrowing that keeps `box.ts` free of the selection identity, exactly as
|
|
19
|
+
* `barAt` / `boxAt` keep it free of the theme.
|
|
20
|
+
*
|
|
21
|
+
* A box's identity within its series is its `x` (its `begin`), so the key is the
|
|
22
|
+
* whole match; a `SelectInfo.mark` is `undefined` for a box (see its docs) and
|
|
23
|
+
* has nothing to add here. Linear over the set — see `includesKey` in `box.ts`.
|
|
24
|
+
*/
|
|
25
|
+
function keysOf(set, id) {
|
|
26
|
+
if (id === undefined || set.length === 0)
|
|
27
|
+
return NO_KEYS;
|
|
28
|
+
const out = [];
|
|
29
|
+
for (let i = 0; i < set.length; i += 1) {
|
|
30
|
+
const m = set[i];
|
|
31
|
+
if (m.id === id)
|
|
32
|
+
out.push(m.key);
|
|
33
|
+
}
|
|
34
|
+
return out.length === 0 ? NO_KEYS : out;
|
|
35
|
+
}
|
|
10
36
|
/**
|
|
11
37
|
* A discrete box-and-whisker draw layer — the bar-chart analog of the variance
|
|
12
38
|
* band. Reads **pre-computed quantile columns** of `series` (typically a
|
|
@@ -64,13 +90,42 @@ export function BoxPlot({ series, lower, q1, median, q3, upper, as: semantic, ax
|
|
|
64
90
|
// The series identity for selection/legend: the `as` role, else the range
|
|
65
91
|
// columns as a span (matches the legend row's label).
|
|
66
92
|
const label = semantic ?? `${lower}–${upper}`;
|
|
67
|
-
// Current selection / hover narrowed to this layer's box
|
|
68
|
-
// `
|
|
69
|
-
// the canvas repaints the
|
|
93
|
+
// Current selection / hover narrowed to this layer's box keys (each box's
|
|
94
|
+
// `x`) — matched by the series `id`, so a change re-registers the layer and
|
|
95
|
+
// the canvas repaints the outlines. A no-`id` layer never matches.
|
|
70
96
|
const sel = container.selected;
|
|
71
97
|
const hov = container.hovered;
|
|
72
|
-
|
|
73
|
-
|
|
98
|
+
// **Every** selected key belonging to this series, not just the first: the
|
|
99
|
+
// container's `selected` has been a set since [PND-MULTISEL] and `hovered`
|
|
100
|
+
// since RFC A4.3, and a draw path that reads `[0]` silently drops the rest —
|
|
101
|
+
// a consumer pinning three boxes saw one outline and no error.
|
|
102
|
+
const selectedKeys = useMemo(() => keysOf(sel, id), [sel, id]);
|
|
103
|
+
const hoveredKeys = useMemo(() => keysOf(hov, id), [hov, id]);
|
|
104
|
+
// The selection's span entries, narrowed to this layer (interaction RFC
|
|
105
|
+
// A5.2). Every box shares one label (the series label), so a span's `rows`
|
|
106
|
+
// channel resolves here once; `x`/`y` ride through for the draw's per-box
|
|
107
|
+
// test. Reference-stable when empty — see `keysOf`.
|
|
108
|
+
const layerSpans = useMemo(() => spansForLayer(container.selectedSpans, id, label), [container.selectedSpans, id, label]);
|
|
109
|
+
// The box's **column** — its `[x, xEnd)` slot, published as snap buckets
|
|
110
|
+
// exactly as a bar layer publishes its bins. A box *is* a bar that isn't
|
|
111
|
+
// grounded to the axis: an aggregation owning one interval of the key axis,
|
|
112
|
+
// drawn floating between two quantiles instead of rising from the baseline.
|
|
113
|
+
// That the ink doesn't reach the axis says nothing about which column the
|
|
114
|
+
// mark owns, so the region cursor snaps to boxes and a sweep cuts them
|
|
115
|
+
// slot-edge to slot-edge, same as bars (RFC A7.6's edge rule).
|
|
116
|
+
//
|
|
117
|
+
// Memoized off the shape alone, so a hover / selection change (which
|
|
118
|
+
// rebuilds the layer entry) doesn't re-allocate the intervals.
|
|
119
|
+
const binBuckets = useMemo(() => {
|
|
120
|
+
if (bx.length === 0)
|
|
121
|
+
return null;
|
|
122
|
+
const out = new Array(bx.length);
|
|
123
|
+
for (let i = 0; i < bx.length; i += 1) {
|
|
124
|
+
const b = bx.x[i];
|
|
125
|
+
out[i] = new Interval({ value: b, start: b, end: bx.xEnd[i] });
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}, [bx]);
|
|
74
129
|
const entry = useMemo(() => ({
|
|
75
130
|
layer: {
|
|
76
131
|
as: semantic,
|
|
@@ -79,6 +134,7 @@ export function BoxPlot({ series, lower, q1, median, q3, upper, as: semantic, ax
|
|
|
79
134
|
// infers the shared x kind from its layers.
|
|
80
135
|
xKind: isValue ? 'value' : 'time',
|
|
81
136
|
xExtent: () => bx.length === 0 ? null : [bx.x[0], bx.xEnd[bx.length - 1]],
|
|
137
|
+
...(binBuckets !== null ? { binIntervals: () => binBuckets } : {}),
|
|
82
138
|
sampleAt: (x) => {
|
|
83
139
|
// The readout reads the box **under the cursor** (boxIndexAtTime — span
|
|
84
140
|
// containment, not nearest-by-begin which flips past a wide box's
|
|
@@ -142,13 +198,48 @@ export function BoxPlot({ series, lower, q1, median, q3, upper, as: semantic, ax
|
|
|
142
198
|
const [, begin, value] = hit;
|
|
143
199
|
return { id, key: begin, value, color: style.whisker, label };
|
|
144
200
|
},
|
|
201
|
+
// The `<MultiSelector>` sweep's range query, identical in shape
|
|
202
|
+
// to the bar layer's: boxes are sorted, non-overlapping key
|
|
203
|
+
// intervals, so the covered set is a contiguous run and
|
|
204
|
+
// `sweep1D`'s two binary searches find it. Each materialised hit
|
|
205
|
+
// is EXACTLY what `hitTest` reports for that box, so a swept box
|
|
206
|
+
// and a clicked box are the same currency.
|
|
207
|
+
beginSweep: () => bx.length === 0
|
|
208
|
+
? null
|
|
209
|
+
: sweep1D({
|
|
210
|
+
id,
|
|
211
|
+
begin: bx.x,
|
|
212
|
+
end: bx.xEnd,
|
|
213
|
+
length: bx.length,
|
|
214
|
+
// A gap box (its present quantiles not all finite) draws
|
|
215
|
+
// nothing and owns no membership — the same rule
|
|
216
|
+
// `hitTest` and the flag already apply.
|
|
217
|
+
selectable: (i) => isFiniteBox(bx, i),
|
|
218
|
+
materialize: (lo, hi) => {
|
|
219
|
+
const out = [];
|
|
220
|
+
for (let i = lo; i < hi; i += 1) {
|
|
221
|
+
if (!isFiniteBox(bx, i))
|
|
222
|
+
continue;
|
|
223
|
+
out.push({
|
|
224
|
+
id,
|
|
225
|
+
key: bx.x[i],
|
|
226
|
+
// `upper`, matching what `hitTest` reports.
|
|
227
|
+
value: bx.upper[i],
|
|
228
|
+
color: style.whisker,
|
|
229
|
+
label,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
return out;
|
|
233
|
+
},
|
|
234
|
+
}),
|
|
145
235
|
}),
|
|
146
|
-
draw: (ctx, xScale, yScale) => drawBox(ctx, bx, xScale, yScale, style, gap, MIN_BOX_WIDTH_PX, shape, showMedian, offset, capWidth,
|
|
236
|
+
draw: (ctx, xScale, yScale) => drawBox(ctx, bx, xScale, yScale, style, gap, MIN_BOX_WIDTH_PX, shape, showMedian, offset, capWidth, selectedKeys, hoveredKeys, decimate, layerSpans),
|
|
147
237
|
},
|
|
148
238
|
axisId: axis,
|
|
149
239
|
index,
|
|
150
240
|
}), [
|
|
151
241
|
bx,
|
|
242
|
+
binBuckets,
|
|
152
243
|
isValue,
|
|
153
244
|
series,
|
|
154
245
|
lower,
|
|
@@ -165,8 +256,9 @@ export function BoxPlot({ series, lower, q1, median, q3, upper, as: semantic, ax
|
|
|
165
256
|
capWidth,
|
|
166
257
|
id,
|
|
167
258
|
label,
|
|
168
|
-
|
|
169
|
-
|
|
259
|
+
selectedKeys,
|
|
260
|
+
hoveredKeys,
|
|
261
|
+
layerSpans,
|
|
170
262
|
decimate,
|
|
171
263
|
axis,
|
|
172
264
|
index,
|
package/dist/Candlestick.d.ts
CHANGED
|
@@ -77,6 +77,18 @@ export interface CandlestickProps<S extends SeriesSchema> {
|
|
|
77
77
|
* up/down candle pair.
|
|
78
78
|
*/
|
|
79
79
|
legend?: boolean | string;
|
|
80
|
+
/**
|
|
81
|
+
* Stable series identity — **gates selection + hover**, the same id-gated
|
|
82
|
+
* contract `<BarChart>` / `<BoxPlot>` / `<ScatterChart>` carry. With an `id`,
|
|
83
|
+
* a click inside a candle's slot selects it (`selected`/`onSelect`),
|
|
84
|
+
* pointer-over lights it (`hovered`/`onHover`), and a `<MultiSelector>` can
|
|
85
|
+
* sweep a run of candles. **Omitted ⇒ display-only.** `key` is the candle's
|
|
86
|
+
* `x` (its slot begin).
|
|
87
|
+
*
|
|
88
|
+
* The state cues never touch the candle's colour — see {@link CandleStyle}
|
|
89
|
+
* for why a candle is the one mark whose hue cannot carry its state.
|
|
90
|
+
*/
|
|
91
|
+
id?: string;
|
|
80
92
|
/**
|
|
81
93
|
* @internal Declaration position among the `<Layers>` children, injected by
|
|
82
94
|
* `Layers` so z-order follows JSX order. Do not set.
|
|
@@ -110,5 +122,5 @@ export interface CandlestickProps<S extends SeriesSchema> {
|
|
|
110
122
|
* </Layers>
|
|
111
123
|
* ```
|
|
112
124
|
*/
|
|
113
|
-
export declare function Candlestick<S extends SeriesSchema>({ series, open, high, low, close, as: semantic, axis, variant, colorBy, gap, showOHLC, decimate, legend, index, }: CandlestickProps<S>): null;
|
|
125
|
+
export declare function Candlestick<S extends SeriesSchema>({ series, open, high, low, close, as: semantic, axis, variant, colorBy, gap, showOHLC, decimate, id, legend, index, }: CandlestickProps<S>): null;
|
|
114
126
|
//# sourceMappingURL=Candlestick.d.ts.map
|
package/dist/Candlestick.js
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
import { useContext, useEffect, useMemo } from 'react';
|
|
2
|
+
import { Interval } from 'pond-ts';
|
|
2
3
|
import { ohlcFromTimeSeries } from './data.js';
|
|
3
|
-
import { drawCandles, isFiniteOhlc, ohlcExtent, ohlcIndexAtTime, resolveCandleStyle, } from './ohlc.js';
|
|
4
|
+
import { drawCandles, isFiniteOhlc, ohlcAt, ohlcExtent, ohlcIndexAtTime, resolveCandleStyle, } from './ohlc.js';
|
|
4
5
|
import { ContainerContext, LayersContext, } from './context.js';
|
|
5
6
|
import { legendLabelFor, useLegendItems, } from './swatch.js';
|
|
6
7
|
import { useSlotKey } from './use-slot-key.js';
|
|
8
|
+
import { sweep1D } from './sweep.js';
|
|
9
|
+
const NO_KEYS = [];
|
|
10
|
+
/** This layer's keys within a selection / hover set — see `<BoxPlot>`'s twin.
|
|
11
|
+
* Reference-stable when empty, so an untouched set doesn't rebuild the layer. */
|
|
12
|
+
function keysOf(set, id) {
|
|
13
|
+
if (id === undefined || set.length === 0)
|
|
14
|
+
return NO_KEYS;
|
|
15
|
+
const out = [];
|
|
16
|
+
for (let i = 0; i < set.length; i += 1) {
|
|
17
|
+
const m = set[i];
|
|
18
|
+
if (m.id === id)
|
|
19
|
+
out.push(m.key);
|
|
20
|
+
}
|
|
21
|
+
return out.length === 0 ? NO_KEYS : out;
|
|
22
|
+
}
|
|
23
|
+
import { spansForLayer } from './span.js';
|
|
7
24
|
/**
|
|
8
25
|
* A first-class OHLC **candlestick** draw layer — the financial sibling of
|
|
9
26
|
* {@link BoxPlot}. Reads four price columns (`open`/`high`/`low`/`close`) of
|
|
@@ -31,7 +48,7 @@ import { useSlotKey } from './use-slot-key.js';
|
|
|
31
48
|
* </Layers>
|
|
32
49
|
* ```
|
|
33
50
|
*/
|
|
34
|
-
export function Candlestick({ series, open = 'open', high = 'high', low = 'low', close = 'close', as: semantic, axis, variant = 'candle', colorBy = 'direction', gap = 0, showOHLC = false, decimate = true, legend, index = 0, }) {
|
|
51
|
+
export function Candlestick({ series, open = 'open', high = 'high', low = 'low', close = 'close', as: semantic, axis, variant = 'candle', colorBy = 'direction', gap = 0, showOHLC = false, decimate = true, id, legend, index = 0, }) {
|
|
35
52
|
const container = useContext(ContainerContext);
|
|
36
53
|
if (container === null) {
|
|
37
54
|
throw new Error('<Candlestick> must be rendered inside a <ChartContainer>');
|
|
@@ -47,12 +64,32 @@ export function Candlestick({ series, open = 'open', high = 'high', low = 'low',
|
|
|
47
64
|
// Series identity for the readout (the `as` role, else the close column name) —
|
|
48
65
|
// the primary `close` pill keys on this, like every other layer.
|
|
49
66
|
const label = semantic ?? close;
|
|
67
|
+
// Current selection / hover narrowed to this layer's candle keys (each
|
|
68
|
+
// candle's `x`), and the selection's span entries — the same three channels
|
|
69
|
+
// the bar and box layers narrow. A no-`id` layer never matches.
|
|
70
|
+
const selectedKeys = useMemo(() => keysOf(container.selected, id), [container.selected, id]);
|
|
71
|
+
const hoveredKeys = useMemo(() => keysOf(container.hovered, id), [container.hovered, id]);
|
|
72
|
+
const layerSpans = useMemo(() => spansForLayer(container.selectedSpans, id, label), [container.selectedSpans, id, label]);
|
|
73
|
+
// A candle owns one `[x, xEnd)` column of the key axis — an aggregation, the
|
|
74
|
+
// same as a box — so it publishes its slots as snap buckets and the region
|
|
75
|
+
// cursor / sweep band land on candle edges rather than centre-to-centre.
|
|
76
|
+
const binBuckets = useMemo(() => {
|
|
77
|
+
if (ohlc.length === 0)
|
|
78
|
+
return null;
|
|
79
|
+
const out = new Array(ohlc.length);
|
|
80
|
+
for (let i = 0; i < ohlc.length; i += 1) {
|
|
81
|
+
const b = ohlc.x[i];
|
|
82
|
+
out[i] = new Interval({ value: b, start: b, end: ohlc.xEnd[i] });
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}, [ohlc]);
|
|
50
86
|
const entry = useMemo(() => ({
|
|
51
87
|
layer: {
|
|
52
88
|
as: semantic,
|
|
53
89
|
yExtent: () => ohlcExtent(ohlc),
|
|
54
90
|
xKind: 'time',
|
|
55
91
|
xExtent: () => ohlc.length === 0 ? null : [ohlc.x[0], ohlc.xEnd[ohlc.length - 1]],
|
|
92
|
+
...(binBuckets !== null ? { binIntervals: () => binBuckets } : {}),
|
|
56
93
|
sampleAt: (time) => {
|
|
57
94
|
// The readout reads the candle **under the cursor** (containment span,
|
|
58
95
|
// not nearest-by-begin), anchored at the slot centre. Outside every
|
|
@@ -84,7 +121,51 @@ export function Candlestick({ series, open = 'open', high = 'high', low = 'low',
|
|
|
84
121
|
];
|
|
85
122
|
return samples;
|
|
86
123
|
},
|
|
87
|
-
|
|
124
|
+
...(id === undefined
|
|
125
|
+
? {}
|
|
126
|
+
: {
|
|
127
|
+
// Rect containment over the candle's slot (`ohlcAt`) — a candle
|
|
128
|
+
// is a discrete interval mark, so this is the box's rule, not
|
|
129
|
+
// the continuous nearest-point one. `key` is its `x`, `value`
|
|
130
|
+
// its `close` (the price the default readout reports).
|
|
131
|
+
hitTest: (px, py, xScale, yScale) => {
|
|
132
|
+
const hit = ohlcAt(ohlc, px, py, xScale, yScale, gap, 1);
|
|
133
|
+
if (hit === null)
|
|
134
|
+
return null;
|
|
135
|
+
const [i, begin, value] = hit;
|
|
136
|
+
const { body } = resolveCandleStyle(style, ohlc.open[i], ohlc.close[i], colorBy);
|
|
137
|
+
return { id, key: begin, value, color: body, label };
|
|
138
|
+
},
|
|
139
|
+
// Candles are sorted, non-overlapping columns, so a sweep is
|
|
140
|
+
// `sweep1D`'s two binary searches — identical to the bar and box
|
|
141
|
+
// layers, and each materialised hit is exactly what `hitTest`
|
|
142
|
+
// reports for that candle.
|
|
143
|
+
beginSweep: () => ohlc.length === 0
|
|
144
|
+
? null
|
|
145
|
+
: sweep1D({
|
|
146
|
+
id,
|
|
147
|
+
begin: ohlc.x,
|
|
148
|
+
end: ohlc.xEnd,
|
|
149
|
+
length: ohlc.length,
|
|
150
|
+
selectable: (i) => isFiniteOhlc(ohlc, i),
|
|
151
|
+
materialize: (lo, hi) => {
|
|
152
|
+
const out = [];
|
|
153
|
+
for (let i = lo; i < hi; i += 1) {
|
|
154
|
+
if (!isFiniteOhlc(ohlc, i))
|
|
155
|
+
continue;
|
|
156
|
+
out.push({
|
|
157
|
+
id,
|
|
158
|
+
key: ohlc.x[i],
|
|
159
|
+
value: ohlc.close[i],
|
|
160
|
+
color: resolveCandleStyle(style, ohlc.open[i], ohlc.close[i], colorBy).body,
|
|
161
|
+
label,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
},
|
|
166
|
+
}),
|
|
167
|
+
}),
|
|
168
|
+
draw: (ctx, xScale, yScale) => drawCandles(ctx, ohlc, xScale, yScale, style, variant, colorBy, gap, undefined, decimate, selectedKeys, hoveredKeys, layerSpans),
|
|
88
169
|
},
|
|
89
170
|
axisId: axis,
|
|
90
171
|
index,
|
|
@@ -100,6 +181,11 @@ export function Candlestick({ series, open = 'open', high = 'high', low = 'low',
|
|
|
100
181
|
decimate,
|
|
101
182
|
axis,
|
|
102
183
|
index,
|
|
184
|
+
id,
|
|
185
|
+
binBuckets,
|
|
186
|
+
selectedKeys,
|
|
187
|
+
hoveredKeys,
|
|
188
|
+
layerSpans,
|
|
103
189
|
]);
|
|
104
190
|
// Stable per-instance slot (see useSlotKey): keeps this candle layer's
|
|
105
191
|
// z-position + identity across prop updates; the injected index drives the sort.
|
package/dist/ChartContainer.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type ReactNode } from 'react';
|
|
|
2
2
|
import { type DiscontinuityProvider, type TradingCalendarLike } from './tradingTimeScale.js';
|
|
3
3
|
import { Sequence, BoundedSequence } from 'pond-ts';
|
|
4
4
|
import type { TimeRange } from 'pond-ts';
|
|
5
|
-
import { type AnnotationKind, type CreateSpec, type CursorMode, type
|
|
5
|
+
import { type AnnotationKind, type CreateSpec, type CursorMode, type TrackerInfo, type DrawStatsFrame } from './context.js';
|
|
6
6
|
import { type AxisFormat, type CursorFormat } from './format.js';
|
|
7
7
|
import { type ChartTheme } from './theme.js';
|
|
8
8
|
export interface ChartContainerProps {
|
|
@@ -165,6 +165,13 @@ export interface ChartContainerProps {
|
|
|
165
165
|
* `'point'` / `'inline'` / `'flag'` add per-series marks; `'none'` hides it.
|
|
166
166
|
* `'region'` shades the bucket under the pointer (needs {@link cursorSequence}).
|
|
167
167
|
* See {@link CursorMode}.
|
|
168
|
+
*
|
|
169
|
+
* @deprecated Mount a **cursor component** instead — `<LineCursor>` /
|
|
170
|
+
* `<PointCursor>` / `<InlineCursor>` / `<FlagCursor>` / `<CrosshairCursor>` /
|
|
171
|
+
* `<RangeCursor>` as a child of the container (or inside a `<ChartRow>` for
|
|
172
|
+
* the per-row override); mount nothing for `'none'`. This prop keeps working
|
|
173
|
+
* for one more minor by synthesizing the equivalent preset internally; a
|
|
174
|
+
* mounted cursor component overrides it. See `docs/rfcs/interaction.md` §9.
|
|
168
175
|
*/
|
|
169
176
|
cursor?: CursorMode;
|
|
170
177
|
/**
|
|
@@ -187,6 +194,10 @@ export interface ChartContainerProps {
|
|
|
187
194
|
* re-realizes the buckets on each pointer move (harmless for a coarse
|
|
188
195
|
* day/session sequence, wasteful for a fine one over a wide view) — hoist it or
|
|
189
196
|
* `useMemo` it.
|
|
197
|
+
*
|
|
198
|
+
* @deprecated Use `<RangeCursor sequence={…}>` — the prop moved onto the
|
|
199
|
+
* component that uses it, where it is no longer mode-conditional. Works for
|
|
200
|
+
* one more minor; a mounted `<RangeCursor>`'s sequence wins over this.
|
|
190
201
|
*/
|
|
191
202
|
cursorSequence?: Sequence | BoundedSequence;
|
|
192
203
|
/**
|
|
@@ -209,6 +220,12 @@ export interface ChartContainerProps {
|
|
|
209
220
|
* domain is meaningless), so a **value** axis is always freeform. No-op unless
|
|
210
221
|
* `cursor="region"` on a **time** or **value** x-axis (a **category** axis is
|
|
211
222
|
* excluded — an ordinal-slot select is a different gesture).
|
|
223
|
+
*
|
|
224
|
+
* @deprecated Use `<RangeCursor onDragRelease>` — the drag moved onto the
|
|
225
|
+
* component, and the payload becomes `{ x: [lo, hi] }` (a {@link RangeSpan},
|
|
226
|
+
* forward-compatible with the 2-D drag's optional `y`) instead of the bare
|
|
227
|
+
* pair. Works for one more minor; a mounted `<RangeCursor onDragRelease>`
|
|
228
|
+
* takes over the gesture.
|
|
212
229
|
*/
|
|
213
230
|
onRegionSelect?: (range: readonly [number, number]) => void;
|
|
214
231
|
/**
|
|
@@ -219,6 +236,9 @@ export interface ChartContainerProps {
|
|
|
219
236
|
* selects). **Omitted** ⇒ a region-drag
|
|
220
237
|
* **preempts** pan (drag always selects; document that precedence for users).
|
|
221
238
|
* Wheel-zoom is unaffected in every case.
|
|
239
|
+
*
|
|
240
|
+
* @deprecated Use `<RangeCursor dragModifier>` — the prop moved onto the
|
|
241
|
+
* component alongside `onDragRelease`. Works for one more minor.
|
|
222
242
|
*/
|
|
223
243
|
regionSelectModifier?: 'shift';
|
|
224
244
|
/**
|
|
@@ -237,51 +257,6 @@ export interface ChartContainerProps {
|
|
|
237
257
|
* frame); route it to a ref/store rather than doing React state work per frame.
|
|
238
258
|
*/
|
|
239
259
|
onDrawStats?: (frame: DrawStatsFrame) => void;
|
|
240
|
-
/**
|
|
241
|
-
* Controlled selection — the selected mark (echo the `onSelect` arg back), or
|
|
242
|
-
* `null`. **Omitted ⇒ uncontrolled** (a click on a selectable layer manages it
|
|
243
|
-
* internally; pass `null` to force nothing selected). A layer is **selectable
|
|
244
|
-
* only when it carries an `id`** (the stable series identity) — `BarChart` /
|
|
245
|
-
* `ScatterChart` highlight the mark matching the selection's `id` (the series)
|
|
246
|
-
* and its `key` (the sample), so two series sharing a timestamp don't both
|
|
247
|
-
* light up, and the selection survives a data update (it keys on the stable
|
|
248
|
-
* `id`, not the sample `key`). A layer with no `id` renders + reads out but
|
|
249
|
-
* can't be selected.
|
|
250
|
-
*/
|
|
251
|
-
selected?: SelectInfo | null;
|
|
252
|
-
/**
|
|
253
|
-
* Fires when a selectable layer's mark is clicked, with the hit mark, or `null`
|
|
254
|
-
* when a click misses every mark (or hits a layer with no `id` — display-only,
|
|
255
|
-
* so it reads as empty space). Notification only — works in both controlled and
|
|
256
|
-
* uncontrolled mode. If this or `selected` is set but no layer has an `id`, a
|
|
257
|
-
* dev-warning notes that nothing is selectable.
|
|
258
|
-
*/
|
|
259
|
-
onSelect?: (hit: SelectInfo | null) => void;
|
|
260
|
-
/**
|
|
261
|
-
* Controlled hover-highlight — the transiently lit mark (echo the `onHover` arg
|
|
262
|
-
* back), or `null`. **Omitted ⇒ uncontrolled** (the pointer over a selectable
|
|
263
|
-
* layer manages it internally). The hover analog of {@link selected}: pass it to
|
|
264
|
-
* **pin** a lit mark from outside the chart (e.g. hovering a legend / list row
|
|
265
|
-
* lights the matching {@link BarChart} bar). Only layers with a hover-highlight
|
|
266
|
-
* (currently `BarChart`) render it; keyed by the same {@link SelectInfo} identity
|
|
267
|
-
* as selection.
|
|
268
|
-
*/
|
|
269
|
-
hovered?: SelectInfo | null;
|
|
270
|
-
/**
|
|
271
|
-
* Fires when the pointer enters a selectable layer's mark (the hit mark) or
|
|
272
|
-
* leaves every mark (`null`) — the hover analog of {@link onSelect}. Notification
|
|
273
|
-
* only (works controlled or uncontrolled), and **deduped**: it fires on a mark
|
|
274
|
-
* transition, not on every pointer move. Wire it to mirror hover out-of-band
|
|
275
|
-
* (e.g. a list row ↔ the bar), pairing with {@link hovered} to sync both ways.
|
|
276
|
-
* (The annotation counterpart is {@link onHoverAnnotation}.)
|
|
277
|
-
*
|
|
278
|
-
* **Dedup key:** by the mark's `key` + `label` only (not `value`/`color`). So on
|
|
279
|
-
* a live chart where a bar's value changes while the cursor stays on it, this
|
|
280
|
-
* won't re-fire — read the current value from your series, not the last
|
|
281
|
-
* `onHover` payload. (Matches the internal hover-highlight, which repaints on
|
|
282
|
-
* key transitions.)
|
|
283
|
-
*/
|
|
284
|
-
onHover?: (hit: SelectInfo | null) => void;
|
|
285
260
|
/**
|
|
286
261
|
* Which pan/zoom gestures the plot captures:
|
|
287
262
|
*
|
|
@@ -296,7 +271,7 @@ export interface ChartContainerProps {
|
|
|
296
271
|
* `false` ⇒ `'none'`). Bound the reachable range with {@link bounds}
|
|
297
272
|
* (zoom-out / pan extent) and {@link minDuration} (zoom-in floor).
|
|
298
273
|
*/
|
|
299
|
-
panZoom?: boolean | 'none' | 'pan' | 'panZoom';
|
|
274
|
+
panZoom?: boolean | 'none' | 'pan' | 'panZoom' | 'panZoomX' | 'panZoomY' | 'panZoomXY';
|
|
300
275
|
/**
|
|
301
276
|
* **Outer pan/zoom extent** — `[min, max]` (same units as {@link range}) the
|
|
302
277
|
* view can never move outside. Panning into an edge stops there (the window
|
|
@@ -327,6 +302,10 @@ export interface ChartContainerProps {
|
|
|
327
302
|
* Show the cursor's time atop the in-chart readout (when a row's `cursor` draws
|
|
328
303
|
* one). **Default `false`.** Formatted by {@link timeFormat} to match the time
|
|
329
304
|
* axis.
|
|
305
|
+
*
|
|
306
|
+
* @deprecated Use `showTime` on the mounted cursor component
|
|
307
|
+
* (`<LineCursor showTime>` / `<FlagCursor showTime>` / …). Works for one
|
|
308
|
+
* more minor via the shim.
|
|
330
309
|
*/
|
|
331
310
|
cursorTime?: boolean;
|
|
332
311
|
/**
|
|
@@ -337,6 +316,10 @@ export interface ChartContainerProps {
|
|
|
337
316
|
* the vertical line snaps its **x** to the data grid (so the time readout is
|
|
338
317
|
* clean), and both draw a full-height dashed vertical + full-width dashed
|
|
339
318
|
* horizontal line.
|
|
319
|
+
*
|
|
320
|
+
* @deprecated Use `<CrosshairCursor snap={…}>` — the prop moved onto the
|
|
321
|
+
* component, where it is no longer mode-conditional. Works for one more
|
|
322
|
+
* minor via the shim.
|
|
340
323
|
*/
|
|
341
324
|
crosshairSnap?: boolean;
|
|
342
325
|
/**
|
|
@@ -418,6 +401,11 @@ export interface ChartContainerProps {
|
|
|
418
401
|
* {@link timeFormat} owns the labels. (A category axis reads names, and a
|
|
419
402
|
* `transform`ed axis's pill speaks its derived unit — neither consults
|
|
420
403
|
* `cursorFormat`.)
|
|
404
|
+
*
|
|
405
|
+
* @deprecated Use `format` on the mounted cursor (`<CrosshairCursor
|
|
406
|
+
* format={…}>`) — it feeds the same shared readout channel (marker
|
|
407
|
+
* indicators and annotation auto-labels included). Works for one more
|
|
408
|
+
* minor; a mounted cursor's `format` wins over this.
|
|
421
409
|
*/
|
|
422
410
|
cursorFormat?: CursorFormat;
|
|
423
411
|
/**
|
|
@@ -462,5 +450,5 @@ export interface ChartContainerProps {
|
|
|
462
450
|
* {@link TimeAxis} at the bottom, aligned under the plots. Y axes are per-row
|
|
463
451
|
* (`<YAxis>`).
|
|
464
452
|
*/
|
|
465
|
-
export declare function ChartContainer({ range, maxBandWidth, bandAlign, width, rowGap, showAxis, trackerPosition, onTrackerChanged, onDrawStats,
|
|
453
|
+
export declare function ChartContainer({ range, maxBandWidth, bandAlign, width, rowGap, showAxis, trackerPosition, onTrackerChanged, onDrawStats, panZoom, bounds, onTimeRangeChange, minDuration, cursor: cursorProp, cursorSequence: cursorSequenceProp, onRegionSelect, regionSelectModifier, cursorTime: cursorTimeProp, crosshairSnap: crosshairSnapProp, editAnnotations, creating, onCreate, onSelectAnnotation, onHoverAnnotation, onEditAnnotation, snap, timeFormat, cursorFormat: cursorFormatProp, origin, theme, discontinuities, calendar, spacing, grid, sessionDividers, children, }: ChartContainerProps): import("react/jsx-runtime").JSX.Element;
|
|
466
454
|
//# sourceMappingURL=ChartContainer.d.ts.map
|