@pond-ts/charts 0.69.0 → 0.71.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/AGENTS.md +3 -1
- package/API.md +55 -56
- package/CHANGELOG.md +177 -1
- package/dist/AreaChart.d.ts +30 -22
- package/dist/AreaChart.js +37 -22
- package/dist/BandChart.d.ts +20 -1
- package/dist/BandChart.js +18 -2
- package/dist/BoxPlot.js +5 -3
- package/dist/Candlestick.d.ts +3 -3
- package/dist/Candlestick.js +5 -5
- package/dist/ChartContainer.d.ts +8 -149
- package/dist/ChartContainer.js +68 -111
- package/dist/ChartRow.d.ts +1 -12
- package/dist/ChartRow.js +15 -30
- package/dist/HeatMap.d.ts +3 -3
- package/dist/HeatMap.js +3 -3
- package/dist/Layers.js +84 -34
- package/dist/XAxis.js +1 -0
- package/dist/area.d.ts +6 -5
- package/dist/area.js +13 -6
- package/dist/axis-events.d.ts +4 -4
- package/dist/band.d.ts +10 -2
- package/dist/band.js +38 -10
- package/dist/brush.d.ts +13 -21
- package/dist/brush.js +22 -36
- package/dist/context.d.ts +81 -96
- package/dist/cursors.d.ts +81 -51
- package/dist/cursors.js +164 -127
- package/dist/decimate.d.ts +10 -1
- package/dist/decimate.js +51 -10
- package/dist/elapsed.d.ts +1 -1
- package/dist/elapsed.js +1 -1
- package/dist/format.d.ts +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/selection-fixtures.d.ts +4 -7
- package/dist/selection-fixtures.js +0 -9
- package/dist/selection-stories.d.ts +4 -6
- package/dist/selection-stories.js +4 -4
- package/dist/selectors.d.ts +2 -3
- package/dist/selectors.js +2 -3
- package/dist/tracker.d.ts +10 -28
- package/dist/tracker.js +17 -40
- package/dist/tradingAxis.fixture.d.ts +19 -0
- package/dist/tradingAxis.fixture.js +24 -0
- package/dist/tradingTimeScale.d.ts +2 -2
- package/package.json +3 -3
package/dist/AreaChart.js
CHANGED
|
@@ -16,8 +16,9 @@ import { useBandLadder } from './use-band-ladder.js';
|
|
|
16
16
|
* it to the call signature, so this reads the bound through a localized,
|
|
17
17
|
* documented shape rather than widening `drawArea`'s contract to d3-scale. */
|
|
18
18
|
/**
|
|
19
|
-
* The area's baseline in **data** units: the caller's `baseline
|
|
20
|
-
* finite position on this axis
|
|
19
|
+
* The area's baseline in **data** units: the caller's `baseline`, clamped into
|
|
20
|
+
* the axis domain, when it has a finite position on this axis; else the axis
|
|
21
|
+
* floor.
|
|
21
22
|
*
|
|
22
23
|
* The fallback is not defensive padding — it's the log case. `baseline={0}` is
|
|
23
24
|
* the natural thing to write and is correct on a linear axis; on a log axis
|
|
@@ -28,14 +29,20 @@ import { useBandLadder } from './use-band-ladder.js';
|
|
|
28
29
|
* layer's meaning ("fill from the bottom") on both scale kinds.
|
|
29
30
|
*/
|
|
30
31
|
export function resolveAreaBaseline(baseline, yScale) {
|
|
31
|
-
const
|
|
32
|
+
const d = yScale.domain?.();
|
|
33
|
+
const floor = d && d.length > 0 ? d[0] : 0;
|
|
32
34
|
if (baseline === undefined)
|
|
33
35
|
return floor;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
if (!Number.isFinite(yScale(baseline)))
|
|
37
|
+
return floor;
|
|
38
|
+
if (!d || d.length === 0)
|
|
39
|
+
return baseline;
|
|
40
|
+
// Clamped into the domain, as a bar's baseline is: under an explicit
|
|
41
|
+
// `<YAxis min={40}>` the default 0 is off the plot, and a fill resting
|
|
42
|
+
// there would anchor its fade (and a gap's `'fade'` connector) off-plot.
|
|
43
|
+
const lo = Math.min(d[0], d[d.length - 1]);
|
|
44
|
+
const hi = Math.max(d[0], d[d.length - 1]);
|
|
45
|
+
return Math.min(hi, Math.max(lo, baseline));
|
|
39
46
|
}
|
|
40
47
|
/**
|
|
41
48
|
* An area draw layer: fills between a value `column` and a `baseline`, with a
|
|
@@ -45,15 +52,15 @@ function domainFloor(yScale) {
|
|
|
45
52
|
* against its `axis`), and renders nothing to the DOM — the row draws it. The
|
|
46
53
|
* fill + outline break at gaps rather than spanning them.
|
|
47
54
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* traffic look composes two layers, each with its own `as` role:
|
|
55
|
+
* The fill rests on `baseline` (see {@link AreaChartProps.baseline}): **`0`
|
|
56
|
+
* by default** (positive up, negative down), any other number for a different
|
|
57
|
+
* reference level, or `'floor'` for the bottom of the plot. The esnet
|
|
58
|
+
* two-colour traffic look composes two layers, each with its own `as` role:
|
|
52
59
|
*
|
|
53
60
|
* ```tsx
|
|
54
61
|
* <Layers>
|
|
55
|
-
* <AreaChart series={s} column="in"
|
|
56
|
-
* <AreaChart series={s} column="out"
|
|
62
|
+
* <AreaChart series={s} column="in" as="in" />
|
|
63
|
+
* <AreaChart series={s} column="out" as="out" />
|
|
57
64
|
* </Layers>
|
|
58
65
|
* ```
|
|
59
66
|
*/
|
|
@@ -66,6 +73,8 @@ export function AreaChart({ series, column, readout, as: semantic, axis, id, bas
|
|
|
66
73
|
if (layers === null) {
|
|
67
74
|
throw new Error('<AreaChart> must be rendered inside a <Layers>');
|
|
68
75
|
}
|
|
76
|
+
// `undefined` below means "the axis floor" — the internal helpers' spelling.
|
|
77
|
+
const baseValue = baseline === 'floor' ? undefined : (baseline ?? 0);
|
|
69
78
|
const cs = useMemo(() => series instanceof ValueSeries
|
|
70
79
|
? fromValueSeries(series, column)
|
|
71
80
|
: fromTimeSeries(series, column), [series, column]);
|
|
@@ -141,7 +150,13 @@ export function AreaChart({ series, column, readout, as: semantic, axis, id, bas
|
|
|
141
150
|
const entry = useMemo(() => ({
|
|
142
151
|
layer: {
|
|
143
152
|
as: semantic,
|
|
144
|
-
|
|
153
|
+
// A baseline with no position on a log axis (zero, the default) is
|
|
154
|
+
// left out of the fit: the draw rests it on the floor anyway, and an
|
|
155
|
+
// extent of `[0, max]` gives the log fit no positive low end, so it
|
|
156
|
+
// would collapse the domain onto the max and clip the series.
|
|
157
|
+
yExtent: (scale) => areaExtent(cs, scale === 'log' && baseValue !== undefined && baseValue <= 0
|
|
158
|
+
? undefined
|
|
159
|
+
: baseValue),
|
|
145
160
|
// The container infers the shared x scale's kind from its layers — a
|
|
146
161
|
// ValueSeries plots on a value axis, a TimeSeries on time.
|
|
147
162
|
xKind: series instanceof ValueSeries ? 'value' : 'time',
|
|
@@ -155,7 +170,7 @@ export function AreaChart({ series, column, readout, as: semantic, axis, id, bas
|
|
|
155
170
|
sweepAxis: 'x',
|
|
156
171
|
sweepSpanOnly: true,
|
|
157
172
|
hitTest: (px, py, xScale, yScale) => {
|
|
158
|
-
const i = areaHitIndex(cs,
|
|
173
|
+
const i = areaHitIndex(cs, baseValue, px, py, xScale, yScale);
|
|
159
174
|
if (i === null)
|
|
160
175
|
return null;
|
|
161
176
|
return {
|
|
@@ -266,15 +281,15 @@ export function AreaChart({ series, column, readout, as: semantic, axis, id, bas
|
|
|
266
281
|
: { ...inStyle, color: style.spanColor, fill: style.spanColor }, 1), true, 0, plotExtentOf(ctx, xScale, yScale).width);
|
|
267
282
|
function drawAreaWith(st) {
|
|
268
283
|
return drawArea(ctx, cs, xScale, yScale, st,
|
|
269
|
-
//
|
|
270
|
-
// scale, so it tracks the auto-fit domain); a
|
|
271
|
-
// verbatim.
|
|
284
|
+
// `'floor'` rests on the axis floor (resolved late from the
|
|
285
|
+
// scale, so it tracks the auto-fit domain); a number (default 0)
|
|
286
|
+
// is used verbatim.
|
|
272
287
|
// A log axis has no position for zero — or anything at or below
|
|
273
288
|
// it — so an explicit out-of-domain `baseline` would scale to
|
|
274
289
|
// `NaN` and poison every coordinate in the fill path. Fall back
|
|
275
|
-
// to the axis floor, which is exactly what
|
|
290
|
+
// to the axis floor, which is exactly what `'floor'`
|
|
276
291
|
// already resolves to.
|
|
277
|
-
resolveAreaBaseline(
|
|
292
|
+
resolveAreaBaseline(baseValue, yScale), curveFactory, gaps, gapConnectorOpacity, decimate, bandLadder);
|
|
278
293
|
}
|
|
279
294
|
},
|
|
280
295
|
},
|
|
@@ -288,7 +303,7 @@ export function AreaChart({ series, column, readout, as: semantic, axis, id, bas
|
|
|
288
303
|
readoutY,
|
|
289
304
|
style,
|
|
290
305
|
label,
|
|
291
|
-
|
|
306
|
+
baseValue,
|
|
292
307
|
curveFactory,
|
|
293
308
|
gaps,
|
|
294
309
|
gapConnectorOpacity,
|
package/dist/BandChart.d.ts
CHANGED
|
@@ -27,6 +27,23 @@ export interface BandChartCommon<S extends SeriesSchema = SeriesSchema, VS exten
|
|
|
27
27
|
* Denoise the underlying values with `smooth()`, not this.
|
|
28
28
|
*/
|
|
29
29
|
curve?: Curve;
|
|
30
|
+
/**
|
|
31
|
+
* Break the envelope at each **trading-axis discontinuity** (a session / day /
|
|
32
|
+
* lunch close→open) when the container renders on a trading-time axis (a
|
|
33
|
+
* `discontinuities` / `calendar` provider). **Omitted ⇒ `false`**: the fill
|
|
34
|
+
* connects the last pre-close sample straight to the next open across the
|
|
35
|
+
* collapsed gap (a near-vertical sliver). `true` ends the fill at the close
|
|
36
|
+
* and re-starts it at the open — the intraday look, where one session's
|
|
37
|
+
* envelope shouldn't visually flow into the next. Same semantics as
|
|
38
|
+
* {@link LineChart}'s `sessionBreaks`, so a band and its centre line break in
|
|
39
|
+
* step.
|
|
40
|
+
*
|
|
41
|
+
* This is a **scale** break (driven by the axis's collapsed gaps), orthogonal
|
|
42
|
+
* to a **data** break (a NaN run on either edge, which a band always breaks
|
|
43
|
+
* at). A no-op on a continuous axis (no provider) or a provider without
|
|
44
|
+
* `boundaries`.
|
|
45
|
+
*/
|
|
46
|
+
sessionBreaks?: boolean;
|
|
30
47
|
/**
|
|
31
48
|
* **M4 viewport decimation** (charts decimator wave). **Omitted ⇒ `true`**:
|
|
32
49
|
* once the visible envelope is denser than ~2 samples per device pixel, it is
|
|
@@ -34,6 +51,8 @@ export interface BandChartCommon<S extends SeriesSchema = SeriesSchema, VS exten
|
|
|
34
51
|
* the samples span, so it covers the same pixels from O(plot width) points.
|
|
35
52
|
* Applies with a linear `curve`; pass `false` to always fill every sample, or
|
|
36
53
|
* `{ threshold }` to tune. Shares {@link LineChart}'s `DecimateOption`.
|
|
54
|
+
* Composes with {@link sessionBreaks}: the break instants are folded into the
|
|
55
|
+
* pixel-column edges so no column merges two sessions' envelopes.
|
|
37
56
|
*/
|
|
38
57
|
decimate?: DecimateOption;
|
|
39
58
|
/**
|
|
@@ -92,6 +111,6 @@ export type BandChartProps<S extends SeriesSchema = SeriesSchema, VS extends Val
|
|
|
92
111
|
* </Layers>
|
|
93
112
|
* ```
|
|
94
113
|
*/
|
|
95
|
-
export declare function BandChart<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema>({ series, lower, upper, as: semantic, axis, curve, decimate, legend, index, }: BandChartProps<S, VS>): null;
|
|
114
|
+
export declare function BandChart<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema>({ series, lower, upper, as: semantic, axis, curve, sessionBreaks, decimate, legend, index, }: BandChartProps<S, VS>): null;
|
|
96
115
|
export {};
|
|
97
116
|
//# sourceMappingURL=BandChart.d.ts.map
|
package/dist/BandChart.js
CHANGED
|
@@ -6,6 +6,9 @@ import { resolveCurve } from './curve.js';
|
|
|
6
6
|
import { ContainerContext, LayersContext } from './context.js';
|
|
7
7
|
import { legendLabelFor, useLegendItems, } from './swatch.js';
|
|
8
8
|
import { useSlotKey } from './use-slot-key.js';
|
|
9
|
+
/** Stable empty boundary list — so `sessionBreaks={false}` keeps a referentially
|
|
10
|
+
* constant array and the layer entry isn't rebuilt every render. */
|
|
11
|
+
const NO_BREAKS = [];
|
|
9
12
|
/**
|
|
10
13
|
* A variance-band draw layer: fills the envelope between the `lower` and `upper`
|
|
11
14
|
* columns of `series` (typically `rollingByColumn` percentiles), gap-aware, and
|
|
@@ -23,7 +26,7 @@ import { useSlotKey } from './use-slot-key.js';
|
|
|
23
26
|
* </Layers>
|
|
24
27
|
* ```
|
|
25
28
|
*/
|
|
26
|
-
export function BandChart({ series, lower, upper, as: semantic, axis, curve, decimate = true, legend, index = 0, }) {
|
|
29
|
+
export function BandChart({ series, lower, upper, as: semantic, axis, curve, sessionBreaks = false, decimate = true, legend, index = 0, }) {
|
|
27
30
|
const container = useContext(ContainerContext);
|
|
28
31
|
if (container === null) {
|
|
29
32
|
throw new Error('<BandChart> must be rendered inside a <ChartContainer>');
|
|
@@ -35,6 +38,18 @@ export function BandChart({ series, lower, upper, as: semantic, axis, curve, dec
|
|
|
35
38
|
const bs = useMemo(() => series instanceof ValueSeries
|
|
36
39
|
? bandFromValueSeries(series, lower, upper)
|
|
37
40
|
: bandFromTimeSeries(series, lower, upper), [series, lower, upper]);
|
|
41
|
+
// Trading-axis session breaks: the collapse instants inside this band's span
|
|
42
|
+
// (session/day/lunch opens the axis skips). Data instants, not pixels — so the
|
|
43
|
+
// set is view-independent (pan/zoom reuse it). Only computed when opted in and
|
|
44
|
+
// the container carries a boundary-reporting discontinuity provider. The same
|
|
45
|
+
// lookup `<LineChart>` does, so a band and its centre line break identically.
|
|
46
|
+
const sessionBreakInstants = useMemo(() => {
|
|
47
|
+
const provider = container.discontinuities;
|
|
48
|
+
if (!sessionBreaks || provider?.boundaries === undefined || bs.length < 2) {
|
|
49
|
+
return NO_BREAKS;
|
|
50
|
+
}
|
|
51
|
+
return provider.boundaries(bs.x[0], bs.x[bs.length - 1]);
|
|
52
|
+
}, [sessionBreaks, container.discontinuities, bs]);
|
|
38
53
|
// Styling: semantic identifier → theme band style. The single styling channel.
|
|
39
54
|
const { band } = container.theme;
|
|
40
55
|
const style = (semantic !== undefined ? band[semantic] : undefined) ?? band.default;
|
|
@@ -118,7 +133,7 @@ export function BandChart({ series, lower, upper, as: semantic, axis, curve, dec
|
|
|
118
133
|
},
|
|
119
134
|
];
|
|
120
135
|
},
|
|
121
|
-
draw: (ctx, xScale, yScale) => drawBand(ctx, bs, xScale, yScale, style, curveFactory, decimate),
|
|
136
|
+
draw: (ctx, xScale, yScale) => drawBand(ctx, bs, xScale, yScale, style, curveFactory, sessionBreakInstants, decimate),
|
|
122
137
|
},
|
|
123
138
|
axisId: axis,
|
|
124
139
|
index,
|
|
@@ -129,6 +144,7 @@ export function BandChart({ series, lower, upper, as: semantic, axis, curve, dec
|
|
|
129
144
|
upper,
|
|
130
145
|
style,
|
|
131
146
|
curveFactory,
|
|
147
|
+
sessionBreakInstants,
|
|
132
148
|
decimate,
|
|
133
149
|
axis,
|
|
134
150
|
index,
|
package/dist/BoxPlot.js
CHANGED
|
@@ -139,9 +139,11 @@ export function BoxPlot({ series, lower, q1, median, q3, upper, as: semantic, ax
|
|
|
139
139
|
// The readout reads the box **under the cursor** (boxIndexAtTime — span
|
|
140
140
|
// containment, not nearest-by-begin which flips past a wide box's
|
|
141
141
|
// midpoint), anchored at the box **centre** `(x + xEnd) / 2`. Outside
|
|
142
|
-
// every box → no readout.
|
|
143
|
-
//
|
|
144
|
-
//
|
|
142
|
+
// every box → no readout. Feeds the off-chart readout and the
|
|
143
|
+
// crosshair (its x-snap lands mid-box, its y-snap on the nearest
|
|
144
|
+
// quantile); the in-chart flag is `cursorFlag`. `push` skips a
|
|
145
|
+
// non-finite quantile, so an absent (range-only) q1/q3/median simply
|
|
146
|
+
// doesn't read out.
|
|
145
147
|
if (bx.length === 0)
|
|
146
148
|
return [];
|
|
147
149
|
const i = boxIndexAtTime(bx, x);
|
package/dist/Candlestick.d.ts
CHANGED
|
@@ -111,9 +111,9 @@ export interface CandlestickProps<S extends SeriesSchema> {
|
|
|
111
111
|
* supersedes `BoxPlot shape='solid'` for OHLC (which needed a quantile remap, a
|
|
112
112
|
* body precompute, two overlaid layers for green/red, and a column-name tracker).
|
|
113
113
|
*
|
|
114
|
-
* **Cursor.**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
114
|
+
* **Cursor.** A candle **participates in the crosshair snap** (as a box plot
|
|
115
|
+
* does), so the reticle lands on candles; unlike a box plot it has no
|
|
116
|
+
* consolidated `cursorFlag`, so the flag cursor shows a chip per value. The readout keys on `as` and shows `close` by default; pass
|
|
117
117
|
* `showOHLC` for the full four-pill quote.
|
|
118
118
|
*
|
|
119
119
|
* ```tsx
|
package/dist/Candlestick.js
CHANGED
|
@@ -37,9 +37,9 @@ import { spansForLayer } from './span.js';
|
|
|
37
37
|
* supersedes `BoxPlot shape='solid'` for OHLC (which needed a quantile remap, a
|
|
38
38
|
* body precompute, two overlaid layers for green/red, and a column-name tracker).
|
|
39
39
|
*
|
|
40
|
-
* **Cursor.**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* **Cursor.** A candle **participates in the crosshair snap** (as a box plot
|
|
41
|
+
* does), so the reticle lands on candles; unlike a box plot it has no
|
|
42
|
+
* consolidated `cursorFlag`, so the flag cursor shows a chip per value. The readout keys on `as` and shows `close` by default; pass
|
|
43
43
|
* `showOHLC` for the full four-pill quote.
|
|
44
44
|
*
|
|
45
45
|
* ```tsx
|
|
@@ -94,8 +94,8 @@ export function Candlestick({ series, open = 'open', high = 'high', low = 'low',
|
|
|
94
94
|
// The readout reads the candle **under the cursor** (containment span,
|
|
95
95
|
// not nearest-by-begin), anchored at the slot centre. Outside every
|
|
96
96
|
// candle → no readout. No `cursorFlag`: the samples flow through the
|
|
97
|
-
// normal per-series tracker path
|
|
98
|
-
//
|
|
97
|
+
// normal per-series tracker path (BoxPlot's cursorFlag takes its
|
|
98
|
+
// values out of the per-series dots and chips).
|
|
99
99
|
if (ohlc.length === 0)
|
|
100
100
|
return [];
|
|
101
101
|
const i = ohlcIndexAtTime(ohlc, time);
|
package/dist/ChartContainer.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import { type DiscontinuityProvider, type TradingCalendarLike } from './tradingTimeScale.js';
|
|
3
|
-
import { Sequence, BoundedSequence } from 'pond-ts';
|
|
4
3
|
import type { TimeRange } from 'pond-ts';
|
|
5
|
-
import { type AnnotationKind, type CreateSpec, type
|
|
6
|
-
import { type AxisFormat
|
|
4
|
+
import { type AnnotationKind, type CreateSpec, type TrackerInfo, type DrawStatsFrame } from './context.js';
|
|
5
|
+
import { type AxisFormat } from './format.js';
|
|
7
6
|
import { type ChartTheme } from './theme.js';
|
|
8
7
|
export interface ChartContainerProps {
|
|
9
8
|
/**
|
|
@@ -210,7 +209,7 @@ export interface ChartContainerProps {
|
|
|
210
209
|
* (`TimeZone`) places these ticks and cuts `Sequence.calendar` buckets, so
|
|
211
210
|
* `Sequence.calendar('day', { timeZone })` and `<ChartContainer timeZone>`
|
|
212
211
|
* given the same zone put a bucket edge and its tick on one instant.
|
|
213
|
-
* Function formatters (`timeFormat`, `
|
|
212
|
+
* Function formatters (`timeFormat`, a cursor's `format`) still receive epoch ms;
|
|
214
213
|
* read the resolved zone from the chart context. An unknown id throws
|
|
215
214
|
* `RangeError`. Only affects a **time** axis.
|
|
216
215
|
*/
|
|
@@ -387,93 +386,10 @@ export interface ChartContainerProps {
|
|
|
387
386
|
*
|
|
388
387
|
* **Omit or pass `null`** (equivalent) for no controlled position — a hovered
|
|
389
388
|
* chart still tracks its pointer, a non-hovered one shows nothing. To force a
|
|
390
|
-
* chart to *never* show a cursor,
|
|
391
|
-
* See {@link onTrackerChanged}.
|
|
389
|
+
* chart to *never* show a cursor, mount no cursor component, rather than
|
|
390
|
+
* clearing `trackerPosition`. See {@link onTrackerChanged}.
|
|
392
391
|
*/
|
|
393
392
|
trackerPosition?: number | null;
|
|
394
|
-
/**
|
|
395
|
-
* In-chart cursor presentation — the default for all rows (a row may override
|
|
396
|
-
* via `<ChartRow cursor>`). **Default `'line'`** — the synced vertical line,
|
|
397
|
-
* with values surfaced *outside* the chart via {@link onTrackerChanged}.
|
|
398
|
-
* `'point'` / `'inline'` / `'flag'` add per-series marks; `'none'` hides it.
|
|
399
|
-
* `'region'` shades the bucket under the pointer (needs {@link cursorSequence}).
|
|
400
|
-
* See {@link CursorMode}.
|
|
401
|
-
*
|
|
402
|
-
* @deprecated Mount a **cursor component** instead — `<LineCursor>` /
|
|
403
|
-
* `<PointCursor>` / `<InlineCursor>` / `<FlagCursor>` / `<CrosshairCursor>` /
|
|
404
|
-
* `<RangeCursor>` as a child of the container (or inside a `<ChartRow>` for
|
|
405
|
-
* the per-row override); mount nothing for `'none'`. This prop keeps working
|
|
406
|
-
* for one more minor by synthesizing the equivalent preset internally; a
|
|
407
|
-
* mounted cursor component overrides it. See `docs/rfcs/interaction.md` §9.
|
|
408
|
-
*/
|
|
409
|
-
cursor?: CursorMode;
|
|
410
|
-
/**
|
|
411
|
-
* The bucketing for `cursor="region"` — the interval highlighted under the
|
|
412
|
-
* pointer. A pond {@link Sequence} (duration or calendar-aware —
|
|
413
|
-
* `Sequence.every('1d')`, `Sequence.calendar('month')`) is realized over the
|
|
414
|
-
* current view; a {@link BoundedSequence} (e.g. a `TradingCalendar`'s
|
|
415
|
-
* `sessionSequence()` / `barSequence()`) is used as-is, so the band can track
|
|
416
|
-
* whole **sessions**. Either way the band maps through `xScale`, so on a
|
|
417
|
-
* trading-time axis the closed part of the bucket collapses. Ignored unless
|
|
418
|
-
* `cursor="region"`.
|
|
419
|
-
*
|
|
420
|
-
* **Time axis only.** A bucket is a *time* interval, so the region cursor is
|
|
421
|
-
* gated to a **time** x-axis — on a **value** axis (a horizontal histogram, a
|
|
422
|
-
* value-keyed chart) it's a no-op (highlighting a value *band* on a horizontal
|
|
423
|
-
* histogram would be a different, y-oriented cursor).
|
|
424
|
-
*
|
|
425
|
-
* **Pass a stable reference.** The buckets are memoized on this value + the
|
|
426
|
-
* view range; a `Sequence`/`BoundedSequence` rebuilt inline every render
|
|
427
|
-
* re-realizes the buckets on each pointer move (harmless for a coarse
|
|
428
|
-
* day/session sequence, wasteful for a fine one over a wide view) — hoist it or
|
|
429
|
-
* `useMemo` it.
|
|
430
|
-
*
|
|
431
|
-
* @deprecated Use `<RangeCursor sequence={…}>` — the prop moved onto the
|
|
432
|
-
* component that uses it, where it is no longer mode-conditional. Works for
|
|
433
|
-
* one more minor; a mounted `<RangeCursor>`'s sequence wins over this.
|
|
434
|
-
*/
|
|
435
|
-
cursorSequence?: Sequence | BoundedSequence;
|
|
436
|
-
/**
|
|
437
|
-
* Makes the `region` cursor **draggable**: drag across the plot and the band
|
|
438
|
-
* extends **bucket by bucket** (snapping to `cursorSequence` points); on
|
|
439
|
-
* release this fires **once** with the selected `[lo, hi]` span, and the cursor
|
|
440
|
-
* reverts to the single-bucket highlight (it does not keep the range). Typical
|
|
441
|
-
* use — zoom the view to the returned span (the container doesn't zoom itself;
|
|
442
|
-
* that's the consumer's call), or map it onto a data subscription's range params.
|
|
443
|
-
*
|
|
444
|
-
* The span is a **neutral numeric pair in axis units** — epoch ms on a **time**
|
|
445
|
-
* axis, the axis value (strike, distance, …) on a **value** axis — mirroring the
|
|
446
|
-
* polymorphic `range` input. A time consumer that wants a `TimeRange` builds one
|
|
447
|
-
* from the pair.
|
|
448
|
-
*
|
|
449
|
-
* With **no `cursorSequence`** the region cursor is the degenerate case — it
|
|
450
|
-
* renders as a **line** on hover and the drag is **freeform** (raw `[lo, hi]`, no
|
|
451
|
-
* bucket snapping); the same callback fires on release. Bucket snapping needs a
|
|
452
|
-
* `cursorSequence`, which is **time-axis only** (a time interval over a value
|
|
453
|
-
* domain is meaningless), so a **value** axis is always freeform. No-op unless
|
|
454
|
-
* `cursor="region"` on a **time** or **value** x-axis (a **category** axis is
|
|
455
|
-
* excluded — an ordinal-slot select is a different gesture).
|
|
456
|
-
*
|
|
457
|
-
* @deprecated Use `<RangeCursor onDragRelease>` — the drag moved onto the
|
|
458
|
-
* component, and the payload becomes `{ x: [lo, hi] }` (a {@link RangeSpan},
|
|
459
|
-
* forward-compatible with the 2-D drag's optional `y`) instead of the bare
|
|
460
|
-
* pair. Works for one more minor; a mounted `<RangeCursor onDragRelease>`
|
|
461
|
-
* takes over the gesture.
|
|
462
|
-
*/
|
|
463
|
-
onRegionSelect?: (range: readonly [number, number]) => void;
|
|
464
|
-
/**
|
|
465
|
-
* Which modifier a region-drag needs — set `'shift'` when you also enable
|
|
466
|
-
* **pan** (`panZoom="pan"` or `"panZoom"`) and want **plain drag to pan,
|
|
467
|
-
* shift-drag to select**. It's only enforced while pan is enabled (with pan
|
|
468
|
-
* off there's no gesture conflict, so shift is optional — either drag
|
|
469
|
-
* selects). **Omitted** ⇒ a region-drag
|
|
470
|
-
* **preempts** pan (drag always selects; document that precedence for users).
|
|
471
|
-
* Wheel-zoom is unaffected in every case.
|
|
472
|
-
*
|
|
473
|
-
* @deprecated Use `<RangeCursor dragModifier>` — the prop moved onto the
|
|
474
|
-
* component alongside `onDragRelease`. Works for one more minor.
|
|
475
|
-
*/
|
|
476
|
-
regionSelectModifier?: 'shift';
|
|
477
393
|
/**
|
|
478
394
|
* Fires on pointer move with the hovered time + every series' value there (so
|
|
479
395
|
* you can render a readout outside the chart), and `null` on leave.
|
|
@@ -561,30 +477,6 @@ export interface ChartContainerProps {
|
|
|
561
477
|
onTimeRangeChange?: (range: [number, number]) => void;
|
|
562
478
|
/** Zoom-in floor — the minimum visible duration in ms. Default `1`. */
|
|
563
479
|
minDuration?: number;
|
|
564
|
-
/**
|
|
565
|
-
* Show the cursor's time atop the in-chart readout (when a row's `cursor` draws
|
|
566
|
-
* one). **Default `false`.** Formatted by {@link timeFormat} to match the time
|
|
567
|
-
* axis.
|
|
568
|
-
*
|
|
569
|
-
* @deprecated Use `showTime` on the mounted cursor component
|
|
570
|
-
* (`<LineCursor showTime>` / `<FlagCursor showTime>` / …). Works for one
|
|
571
|
-
* more minor via the shim.
|
|
572
|
-
*/
|
|
573
|
-
cursorTime?: boolean;
|
|
574
|
-
/**
|
|
575
|
-
* `cursor="crosshair"` reticle **y** snapping. **Default `true`** — the
|
|
576
|
-
* crosshair centres on the nearest **data point** (the horizontal line snaps to
|
|
577
|
-
* that sample's value). `false` — the horizontal line + centre follow the
|
|
578
|
-
* pointer **y** freely, the value read as `yScale.invert(pointerY)`. Either way
|
|
579
|
-
* the vertical line snaps its **x** to the data grid (so the time readout is
|
|
580
|
-
* clean), and both draw a full-height dashed vertical + full-width dashed
|
|
581
|
-
* horizontal line.
|
|
582
|
-
*
|
|
583
|
-
* @deprecated Use `<CrosshairCursor snap={…}>` — the prop moved onto the
|
|
584
|
-
* component, where it is no longer mode-conditional. Works for one more
|
|
585
|
-
* minor via the shim.
|
|
586
|
-
*/
|
|
587
|
-
crosshairSnap?: boolean;
|
|
588
480
|
/**
|
|
589
481
|
* Enter **annotation-edit mode**: suppresses the data cursor and makes editable
|
|
590
482
|
* annotations (those given an `onChange`) interactive — hovering one reveals its
|
|
@@ -634,43 +526,10 @@ export interface ChartContainerProps {
|
|
|
634
526
|
* **owns the labels**, so it opts the axis out of the `dateStyle` ladder
|
|
635
527
|
* (flat / stacked) by design. **Omitted ⇒ the flat/stacked date style.** To
|
|
636
528
|
* shape only the cursor readout while keeping a date style, use
|
|
637
|
-
*
|
|
638
|
-
* when `
|
|
529
|
+
* a mounted cursor's `format` (e.g. `<CrosshairCursor format>`) instead. (For
|
|
530
|
+
* back-compat this also shapes the readout when no cursor `format` is set.)
|
|
639
531
|
*/
|
|
640
532
|
timeFormat?: AxisFormat;
|
|
641
|
-
/**
|
|
642
|
-
* The **cursor / marker readout** format — the crosshair x pill, marker
|
|
643
|
-
* axis indicators, and annotation auto-labels — **independent of the tick
|
|
644
|
-
* labels** on both axis kinds: it does **not** disqualify the `dateStyle`
|
|
645
|
-
* ladder (time), and it never moves the tick labels (value). It beats an
|
|
646
|
-
* explicit `<XAxis format>` for the **readout only** — pill precedence is
|
|
647
|
-
* `cursorFormat → axis format → container` — so terse ticks can pair with a
|
|
648
|
-
* precise readout (`+2.0σ` labels, `+1.83σ` pill).
|
|
649
|
-
*
|
|
650
|
-
* **Omitted ⇒ the axis's own formatter.** On a time axis that default is
|
|
651
|
-
* grain-aware: the readout formats at the axis's granularity, so a
|
|
652
|
-
* day-or-coarser axis reads a **date** (never a time-of-day) and a sub-day
|
|
653
|
-
* axis reads date + clock — a daily bar at a foreign-tz midnight no longer
|
|
654
|
-
* renders as `02 AM`. On a value axis it is the tick formatter
|
|
655
|
-
* ({@link timeFormat}-shaped, else the d3 default).
|
|
656
|
-
*
|
|
657
|
-
* A d3 specifier **string** formats uniformly (time specifier on a time
|
|
658
|
-
* axis, number specifier on a value axis); a **function**
|
|
659
|
-
* `(value, { grain, defaultText }) => string` receives the axis's resolved
|
|
660
|
-
* coarse {@link TimeGrain} (`undefined` on a value axis) and the default
|
|
661
|
-
* readout text, so it can branch on the zoom level and pass `defaultText`
|
|
662
|
-
* through for grains it doesn't override (no re-deriving the grain from the
|
|
663
|
-
* range). See {@link CursorFormat}. This is the independent readout channel;
|
|
664
|
-
* {@link timeFormat} owns the labels. (A category axis reads names, and a
|
|
665
|
-
* `transform`ed axis's pill speaks its derived unit — neither consults
|
|
666
|
-
* `cursorFormat`.)
|
|
667
|
-
*
|
|
668
|
-
* @deprecated Use `format` on the mounted cursor (`<CrosshairCursor
|
|
669
|
-
* format={…}>`) — it feeds the same shared readout channel (marker
|
|
670
|
-
* indicators and annotation auto-labels included). Works for one more
|
|
671
|
-
* minor; a mounted cursor's `format` wins over this.
|
|
672
|
-
*/
|
|
673
|
-
cursorFormat?: CursorFormat;
|
|
674
533
|
/**
|
|
675
534
|
* Label the x axis as **offsets from a zero point** instead of absolute
|
|
676
535
|
* values — the *duration* (elapsed-time) axis. A time axis reads
|
|
@@ -690,7 +549,7 @@ export interface ChartContainerProps {
|
|
|
690
549
|
* and so does the cursor pill (one grain finer, as ever: `00:05:12`).
|
|
691
550
|
*
|
|
692
551
|
* This is a **labelling** mode, not a data transform: `range`, an annotation's
|
|
693
|
-
* `at`,
|
|
552
|
+
* `at`, a `<RangeCursor onDragRelease>` span, `trackerPosition` are all still absolute
|
|
694
553
|
* axis units. Ignored on a category axis. An explicit `timeFormat` /
|
|
695
554
|
* `<XAxis format>` still wins — on a time axis a d3 *time* specifier can only
|
|
696
555
|
* describe an instant, so it labels the underlying wall clock (the lever for
|