The top of the chart layout (react-timeseries-charts-style). Owns the shared
x geometry: it collects each row's per-slot gutter widths, reserves each
slot's max across rows (so the innermost axis aligns column-by-column and
every row's plot left-aligns), and from the slot sums derives plotWidth and
the shared time xScale. It renders its rows (separated by rowGap) then one
TimeAxis at the bottom, aligned under the plots. Y axes are per-row
(<YAxis>).
Props
Total width in CSS pixels (plot + axis gutters).
calendarTradingCalendarLikeThe high-level sugar for discontinuities: a trading calendar the
container derives the provider from itself (calendar.discontinuities({ spacing })), so you don't wire the low-level prop. A @pond-ts/financial
TradingCalendar satisfies the structural TradingCalendarLike shape
(charts never imports that package). Combine with spacing. For the
full option matrix (a bar period, a scoped range) use the low-level
discontinuities prop instead. Only affects a time axis.
The provider is memoized on (calendar, spacing), so pass a stable
calendar reference (build it once, not inline in JSX).
childrenReactNodecreatingAnnotationKindAnnotationKindtype@pond-ts/charts'region' | 'marker' | 'baseline'The kind of an annotation, and of a creation tool.
| nullThe armed annotation creation tool (the consumer's toolbar sets it), or
null/omitted for idle. When set, the plot captures a create gesture — a
preview tracks the pointer, and on release onCreate fires. The consumer
then adds the mark, disarms (back to null), and selects it (spring-loaded);
keep it set to place several. Requires editAnnotations.
crosshairSnapbooleancursor="crosshair" reticle y snapping. Default true — the
crosshair centres on the nearest data point (the horizontal line snaps to
that sample's value). false — the horizontal line + centre follow the
pointer y freely, the value read as yScale.invert(pointerY). Either way
the vertical line snaps its x to the data grid (so the time readout is
clean), and both draw a full-height dashed vertical + full-width dashed
horizontal line.
cursorCursorModeCursorModetype@pond-ts/charts'none' | 'line' | 'point' | 'inline' | 'flag' | 'crosshair' | 'region'The in-chart cursor presentation for a row (the synced vertical line is shared
across rows). Exclusive modes — pick one:
In-chart cursor presentation — the default for all rows (a row may override
via <ChartRow cursor>). Default 'line' — the synced vertical line,
with values surfaced outside the chart via onTrackerChanged.
'point' / 'inline' / 'flag' add per-series marks; 'none' hides it.
'region' shades the bucket under the pointer (needs cursorSequence).
See CursorMode.
cursorFormatCursorFormatCursorFormattype@pond-ts/chartsstring | (epochMs: number, ctx: { defaultText: string; grain: TimeGrain }) => stringHow to format the cursor / marker readout on a time axis
(ChartContainerProps.cursorFormat). Either:
The cursor / marker readout format — the crosshair time pill, marker
axis indicators, and annotation auto-labels — independent of the tick
labels, so it does not disqualify the dateStyle ladder.
Omitted ⇒ a grain-aware default: the readout formats at the axis's own
granularity, so a day-or-coarser axis reads a date (never a
time-of-day) and a sub-day axis reads date + clock — a daily bar at a
foreign-tz midnight no longer renders as 02 AM.
A d3 time-specifier string formats uniformly at every zoom; a
function (epochMs, { grain, defaultText }) => string receives the
axis's resolved coarse TimeGrain and the grain-aware default text,
so it can branch on the zoom level and pass defaultText through for
grains it doesn't override (no re-deriving the grain from the range). See
CursorFormat. This is the independent readout channel;
timeFormat owns the labels.
cursorSequenceSequenceSequenceclasspond-tsAn unbounded fixed-step grid definition used for alignment or aggregation.
| BoundedSequenceBoundedSequenceclasspond-tsA finite ordered list of Interval buckets.
The bucketing for cursor="region" — the interval highlighted under the
pointer. A pond Sequence (duration or calendar-aware —
Sequence.every('1d'), Sequence.calendar('month')) is realized over the
current view; a BoundedSequence (e.g. a TradingCalendar's
sessionSequence() / barSequence()) is used as-is, so the band can track
whole sessions. Either way the band maps through xScale, so on a
trading-time axis the closed part of the bucket collapses. Ignored unless
cursor="region".
Time axis only. A bucket is a time interval, so the region cursor is gated to a time x-axis — on a value axis (a horizontal histogram, a value-keyed chart) it's a no-op (highlighting a value band on a horizontal histogram would be a different, y-oriented cursor).
Pass a stable reference. The buckets are memoized on this value + the
view range; a Sequence/BoundedSequence rebuilt inline every render
re-realizes the buckets on each pointer move (harmless for a coarse
day/session sequence, wasteful for a fine one over a wide view) — hoist it or
useMemo it.
cursorTimebooleanShow the cursor's time atop the in-chart readout (when a row's cursor draws
one). Default false. Formatted by timeFormat to match the time
axis.
discontinuitiesDiscontinuityProviderDiscontinuityProviderinterface@pond-ts/charts{ boundaries?: unknown; clampDown: unknown; clampUp: unknown; copy: unknown; distance: unknown; offset: unknown }The structural discontinuity-provider surface scaleTradingTime consumes to
collapse closed-market time. Charts declares this shape itself and never
imports @pond-ts/financial — a TradingCalendar.discontinuities() provider
satisfies it structurally, so the packages stay decoupled (trading-calendar
RFC §6.1). Domain values are epoch-milliseconds.
A trading-calendar discontinuity provider — closed-market time
(weekends, holidays, overnight, lunch breaks) collapsed. Supply it to turn
the shared x axis into a trading-time axis: gaps disappear and time
stays proportional within each session. A @pond-ts/financial
TradingCalendar.discontinuities() satisfies this structurally (charts
never imports that package). The low-level primitive: pass
calendar.discontinuities() (or a { spacing, period } variant) directly.
Only affects a time axis (ignored on a value axis). Takes precedence
over calendar if both are given.
Pass a stable reference. The scale (and container frame) rebuild when
this prop's identity changes, so memoize it — const disc = useMemo(() => calendar.discontinuities(), [calendar]) — rather than calling
.discontinuities() inline in JSX, which would rebuild every render.
Accepts an explicit undefined (a cond ? provider : undefined toggle
under exactOptionalPropertyTypes), same as omitting it.
editAnnotationsbooleanEnter annotation-edit mode: suppresses the data cursor and makes editable
annotations (those given an onChange) interactive — hovering one reveals its
handles + highlights it, and dragging edits it. Default false. Pairs
with each annotation's onChange (where the edit goes); this is the mode that
turns the affordances on and gets the cursor out of the way.
gridbooleanDraw the reference gridlines behind the data. On a calendar (time) axis
the verticals are the full grain populations — every day / month /
aligned clock instant in view, each grain fading by its calendar density
— not just the labelled ticks (the labels decorate the grid; they don't
define it). Default true. Set false for a clean backdrop —
session dividers (below) are independent and still draw when enabled.
hoveredSelectInfoSelectInfointerface@pond-ts/charts{ color: string; id: string; key: number; label: string; mark?: string; value: number }One selection — what RowLayer.hitTest returns and onSelect reports.
Selection identity is the series id, not the sample: key/value are
click provenance (the nearest sample under the pointer, informational);
equality, dedup, and the controlled echo all key on id. Because id is a
stable series identity — distinct from the as theme role,…
| nullControlled hover-highlight — the transiently lit mark (echo the onHover arg
back), or null. Omitted ⇒ uncontrolled (the pointer over a selectable
layer manages it internally). The hover analog of selected: pass it to
pin a lit mark from outside the chart (e.g. hovering a legend / list row
lights the matching BarChart bar). Only layers with a hover-highlight
(currently BarChart) render it; keyed by the same SelectInfo identity
as selection.
minDurationnumberZoom-in floor — the minimum visible duration in ms. Default 1.
onCreate(spec: CreateSpecCreateSpectype@pond-ts/charts{ at: number; kind: 'marker' } | { axis: string; kind: 'baseline'; value: number } | { from: number; kind: 'region'; to: number }What a completed create gesture reports to ContainerFrame.onCreate —
the new mark's kind + position in axis units (+ the y-axis id for a baseline).
(Which row a mark lands on is the consumer's call for now; multi-row routing is
a follow-up.)
) => voidFired when a create gesture completes (on release). See CreateSpec.
onEditAnnotation(id: string) => voidFired when a mark is double-clicked — the request to edit just that one
(set its editing prop in response). Single click selects (inspect); double
click edits. Works in any mode.
onHover(hit: SelectInfoSelectInfointerface@pond-ts/charts{ color: string; id: string; key: number; label: string; mark?: string; value: number }One selection — what RowLayer.hitTest returns and onSelect reports.
Selection identity is the series id, not the sample: key/value are
click provenance (the nearest sample under the pointer, informational);
equality, dedup, and the controlled echo all key on id. Because id is a
stable series identity — distinct from the as theme role,…
| null) => voidFires when the pointer enters a selectable layer's mark (the hit mark) or
leaves every mark (null) — the hover analog of onSelect. Notification
only (works controlled or uncontrolled), and deduped: it fires on a mark
transition, not on every pointer move. Wire it to mirror hover out-of-band
(e.g. a list row ↔ the bar), pairing with hovered to sync both ways.
(The annotation counterpart is onHoverAnnotation.)
Dedup key: by the mark's key + label only (not value/color). So on
a live chart where a bar's value changes while the cursor stays on it, this
won't re-fire — read the current value from your series, not the last
onHover payload. (Matches the internal hover-highlight, which repaints on
key transitions.)
onHoverAnnotation(id: string | null) => voidFired when the pointer enters an annotation (its id) or leaves it (null).
Mirror it to a controlled hovered prop on each mark to sync hover both ways
(e.g. a legend row ↔ the mark). Fires in any mode.
onRegionSelect(range: readonly [number, number]) => voidMakes the region cursor draggable: drag across the plot and the band
extends bucket by bucket (snapping to cursorSequence points); on
release this fires once with the selected [lo, hi] span, and the cursor
reverts to the single-bucket highlight (it does not keep the range). Typical
use — zoom the view to the returned span (the container doesn't zoom itself;
that's the consumer's call), or map it onto a data subscription's range params.
The span is a neutral numeric pair in axis units — epoch ms on a time
axis, the axis value (strike, distance, …) on a value axis — mirroring the
polymorphic range input. A time consumer that wants a TimeRange builds one
from the pair.
With no cursorSequence the region cursor is the degenerate case — it
renders as a line on hover and the drag is freeform (raw [lo, hi], no
bucket snapping); the same callback fires on release. Bucket snapping needs a
cursorSequence, which is time-axis only (a time interval over a value
domain is meaningless), so a value axis is always freeform. No-op unless
cursor="region" on a time or value x-axis (a category axis is
excluded — an ordinal-slot select is a different gesture).
onSelect(hit: SelectInfoSelectInfointerface@pond-ts/charts{ color: string; id: string; key: number; label: string; mark?: string; value: number }One selection — what RowLayer.hitTest returns and onSelect reports.
Selection identity is the series id, not the sample: key/value are
click provenance (the nearest sample under the pointer, informational);
equality, dedup, and the controlled echo all key on id. Because id is a
stable series identity — distinct from the as theme role,…
| null) => voidFires when a selectable layer's mark is clicked, with the hit mark, or null
when a click misses every mark (or hits a layer with no id — display-only,
so it reads as empty space). Notification only — works in both controlled and
uncontrolled mode. If this or selected is set but no layer has an id, a
dev-warning notes that nothing is selectable.
onSelectAnnotation(id: string | null) => voidFired when an annotation is clicked (its id), the plot is clicked empty
(null), or a region is double-clicked (the shortcut into edit). The consumer
holds the selected id and sets each mark's selected={id === sel}.
onTimeRangeChange(range: [number, number]) => voidControlled view range — fires on pan/zoom with the new [start, end]. Wire
it back to range for a controlled chart; omit for uncontrolled (the
container holds the view internally). Uncontrolled + panZoom seeds the
internal view from range whenever it isn't actively holding one — so
toggling panZoom on, or a controlled→uncontrolled switch, starts from the
current range, not the mount-time one. Once uncontrolled, later range
changes are ignored so they can't fight the user's pan. To drive the range
externally — or to follow a live sliding window — use controlled mode (this
callback).
onTrackerChanged(info: TrackerInfoTrackerInfointerface@pond-ts/charts{ time: number; values: readonly TrackerSample[] }The hover snapshot handed to onTrackerChanged — the cursor time + every
series' value there, so a consumer can render the readout outside the chart.
| null) => voidFires on pointer move with the hovered time + every series' value there (so
you can render a readout outside the chart), and null on leave.
panZoombooleanEnable pan/zoom: drag the plot to pan the time range, wheel to zoom around the cursor. Default off — so it doesn't capture drag/scroll unless asked.
rangeTimeRangeTimeRangeclasspond-tsA time interval event key with inclusive start and end boundaries. Example: new TimeRange({ start, end }).
| readonly [number, number]The shared x domain [begin, end] — a tuple, or a TimeRange
(series.timeRange()). Units follow the data: epoch-ms for a time axis,
the value units (distance, …) for a value axis. Omit to auto-fit to the
rows' extents. The axis kind is never taken from here — it's inferred from
the data — so a tuple stays a time domain on a time chart.
regionSelectModifier'shift'Which modifier a region-drag needs — set 'shift' when you also enable
panZoom and want plain drag to pan, shift-drag to select. It's only
enforced while panZoom is on (with pan off there's no gesture conflict, so
shift is optional — either drag selects). Omitted ⇒ a region-drag
preempts pan (drag always selects; document that precedence for users).
Wheel-zoom is unaffected in every case.
rowGapnumberVertical space between rows in CSS pixels (not under the axis). Default 0.
selectedSelectInfoSelectInfointerface@pond-ts/charts{ color: string; id: string; key: number; label: string; mark?: string; value: number }One selection — what RowLayer.hitTest returns and onSelect reports.
Selection identity is the series id, not the sample: key/value are
click provenance (the nearest sample under the pointer, informational);
equality, dedup, and the controlled echo all key on id. Because id is a
stable series identity — distinct from the as theme role,…
| nullControlled selection — the selected mark (echo the onSelect arg back), or
null. Omitted ⇒ uncontrolled (a click on a selectable layer manages it
internally; pass null to force nothing selected). A layer is selectable
only when it carries an id (the stable series identity) — BarChart /
ScatterChart highlight the mark matching the selection's id (the series)
and its key (the sample), so two series sharing a timestamp don't both
light up, and the selection survives a data update (it keys on the stable
id, not the sample key). A layer with no id renders + reads out but
can't be selected.
sessionDividers'none' | 'labeled' | 'all'Where to draw session dividers — the solid verticals at a trading
calendar's collapse seams: boundaries that removed (closed-market)
time actually precedes, not every session roll (only with a
discontinuities / calendar provider). On a real exchange calendar
every session open follows an overnight gap, so seams = session opens; a
calendar of contiguous full-day sessions has seams only where days were
excised (the weekend). Default 'none' — the hierarchical grid
already marks the calendar structure at every zoom, so dividers are
opt-in emphasis: 'all' draws one at every seam in view (the
TradingView session-separator look, crowding lines fading out),
'labeled' only at seams the axis also labels. Dividers are independent
of grid — 'all' + grid={false} is the
separators-on-a-clean-plot look.
showAxisbooleanAuto-render the shared x axis under the rows. Default true. Set
false for a bare plot (a sparkline), or when you place your own <XAxis>
child (e.g. with a label, custom ticks, or on side="top"). Named
showAxis (not axis) to avoid clashing with a layer's axis prop, which
picks which <YAxis> it scales against — a different axis entirely.
snapbooleanSnap mode (the toolbar's "Snap"). Default true. When on, a dragged
mark snaps to other marks' guidelines (their x-positions, within a few
px) so spans align; off = free placement. (Snapping to the nearest data
sample is not implemented — guideline alignment only.)
spacing'proportional' | 'uniform'The trading axis metric, when a calendar is supplied
(trading-calendar RFC Q7). 'proportional' (default) keeps time
proportional within and across sessions — a half-day is half as wide.
'uniform' gives every session equal width (the TradingView ordinal look).
Ignored without calendar (a low-level discontinuities provider already
carries its own metric).
themeChartThemeChartThemeinterface@pond-ts/charts{ annotation?: { color: string; depth: readonly [number, number, number]; fillOpacity: number }; area: { default: AreaStyle }; axis: { band?: { divider?: string; fill: string; label?: string }; grid: string; gridDash: readonly number[]; lab…Visual styling for a chart, threaded through ChartContainer via
context. Canvas has no CSS cascade into drawn pixels, so this typed object is
the single styling channel for the drawn layers; DOM chrome (axis labels)
derives from it too.
Visual theme for all rows; defaults to defaultTheme.
timeFormatAxisFormatAxisFormattype@pond-ts/chartsstring | (value: number) => stringHow to format an axis's values — a d3 [format specifier]
(https://github.com/d3/d3-format#locale_format) string, or a custom
(value) => string function. Omit for the scale's d3 default.
Time-axis label formatting — a d3 time specifier string (e.g. '%H:%M')
or a (epochMs) => string function (AxisFormat). A custom format
owns the labels, so it opts the axis out of the dateStyle ladder
(flat / stacked) by design. Omitted ⇒ the flat/stacked date style. To
shape only the cursor readout while keeping a date style, use
cursorFormat instead. (For back-compat this also shapes the readout
when cursorFormat is absent.)
trackerPositionnumber | nullControlled tracker position (epoch ms) — pins the synced crosshair across
rows. Omit for uncontrolled (the chart tracks the pointer itself); pass
null to force it hidden. See onTrackerChanged.