TimeseriesChart
Time-series lines and stacked bars: clustered markers, threshold lines, range brushing, full tooltips.
Usage
data is an array of series; each series' data holds time-ordered [timestamp_ms, value] tuples. color is optional — series fall onto the categorical palette by position, and positions are stable, so hiding one series never recolors the rest. Hovering opens the tooltip: rows sort by value descending, duplicate names dedupe, and values resolve by binary-searching the nearest sample.
Two-series lines
Lines + axis formatting
xAxisTickFormat / tooltipValueFormat customize tick and value text.
Integer ticks + tooltip footer
yAxisMinInterval drops ticks closer together than the interval, which suits discrete counts; tooltipFooter appends one line of text below the tooltip rows.
Integer ticks + tooltip footer
yAxisMinInterval 1 keeps integer ticks only; tooltipFooter adds a footer row.
API Reference
TimeseriesChart Props
| Prop | Type | Default | Description |
|---|---|---|---|
data | TimeseriesData[] | — | { name, data: [ts, value][], color? }; missing color falls onto the categorical palette by position. |
type | 'line' | 'bar' | 'line' | Bars stack automatically. |
markers | TimeseriesMarker[] | — | { timestamp, label?, description?, color?, lineStyle? }. |
thresholds | TimeseriesThreshold[] | — | { value, label?, color }; the y domain extends to cover them. |
xAxisName / yAxisName | string | — | Axis names. |
xAxisTickCount / yAxisTickCount | number | 5 | Suggested tick counts. |
xAxisTickFormat / yAxisTickFormat | (v: number) => string | — | Tick formatters. |
yAxisMinInterval | number | — | Minimum interval between y-axis ticks (ECharts yAxis.minInterval): closer ticks drop, the lowest and highest always stay, and integer ticks stop printing as 1.0 when set to 1. |
tooltipValueFormat | (v: number) => string | raw value | Tooltip value formatter. |
tooltipMode | 'all' | 'single' | 'all' | single shows only the series closest to the cursor's y value. |
tooltipMaxItems | number | 10 | Overflow folds into "+N more". |
tooltipFollowCursor | 'both' | 'x' | 'both' | x pins the vertical position to avoid jitter. |
tooltipFooter | string | — | Extra line of text appended below the tooltip rows. |
tooltipBoundary | TimeseriesTooltipBoundary | 'clipping-ancestors' | Tooltip collision boundary; by default it walks clipping ancestors (offsetParents whose overflow is not visible) and intersects them with the viewport before flipping. The TimeseriesTooltipBoundary type is exported from the @talex-touch/tuffex/charts entry. |
incomplete | { before?, after? } | — | Incomplete periods (line type only). |
gradient | boolean | false | Gradient fill under lines. |
loading | boolean | false | Skeleton state. |
highlightedSeries | string | null | — | Emphasized series; the rest dim to 10% opacity. |
height | number | 350 | Pixel height. |
width | number | measured | Explicit width (SSR/tests). |
ariaDescription | string | — | Accessible description (svg role="img"). |
clusterLabel | (n: number) => string | n => `${n} changes` | Cluster label wording. |
timestampFormat | (ts: number) => string | compact locale | Tooltip timestamp format. |
TimeseriesChart Events
| Event | Payload | Description |
|---|---|---|
time-range-change | (from: number, to: number) | Brush finished. Attaching it enables brushing. |
update:hiddenSeries | (names: string[]) | v-model:hidden-series write-back. |
Markers & Thresholds
markers draw vertical dashed lines on the time axis; markers that crowd together cluster into one line based on the visible span, the label becomes "N changes" (clusterLabel overrides the wording), and hovering the line lists each marker's label and description. thresholds draw horizontal lines on the value axis, and the y domain extends automatically to cover them.
Deploy markers + SLO line
Markers + Thresholds
The last two markers sit close together and cluster.
Gradient & Incomplete Data
gradient adds a vertical fill under each line (series color at 40% → transparent). incomplete declares data outside [before, after] as incomplete: edge segments render dashed and overlap the solid segment by one sample so the line stays connected.
Gradient + dashed edges
Gradient + Incomplete
The first and last three hours are incomplete periods.
Stacked Bars
With type="bar" every series stacks automatically (kumo's stack: 'total'), and the y domain covers each timestamp's stacked total.
Daily stacks
Stacked bars
Three series share one bar per day.
Time Range Selection
Attaching a time-range-change listener enables horizontal brushing: drag on the plot to draw a selection; releasing emits (from, to) in milliseconds and clears the selection. Drags under 3px count as clicks and do nothing. The selection rectangle fills with rgba(120, 140, 180, 0.3) and strokes 1px rgba(120, 140, 180, 0.8). While dragging, the plot outside the selection dims too: one luminance <mask> spanning the plot (a white plot rect plus two #4D4D4D strips) presses everything outside the selection to 30%, so each series stays mounted exactly once — equivalent to ECharts outOfBrush.colorAlpha: 0.3.
Drag to select
Brush selection
The readout below shows the selected range.
Legend Interplay
v-model:hidden-series two-way binds the hidden series names: hidden series neither render nor appear in tooltips. highlighted-series emphasizes one series and dims the rest to 10% opacity (ECharts blur's fromState.opacity * 0.1). Combine both with TxChartLegendItem for a clickable, hover-highlighting legend.
Click to hide + hover to highlight
Legend interplay
Click legend items to toggle; hover to highlight.
Loading Skeleton
loading swaps the chart for a harmonic-wave skeleton; the line and bar variants share one silhouette, and the shimmer respects prefers-reduced-motion.
Skeleton loop
Loading skeleton
Loading toggles on a loop, alternating the line and bar variants.
Animation & Interaction
The chart reuses ECharts' default timings (kumo pins echarts ^6.0.0):
- First render: lines/areas reveal left to right through a clip, 1000ms
easings.linear; bars grow out of the base axis (y lerps frombaseYto the target, height 0 → target) and scatter symbols scale 0 → radius while fading in, all 1000ms cubicInOut. - Data updates: geometry morphs over 500ms cubicInOut.
- State switches (emphasis / blur): 300ms cubicOut.
animationThreshold2000: a series with more points than that renders its final geometry with no animation.- Tooltip: closing waits 100ms, then fades out over 200ms and removes the DOM, so brief pointer excursions do not flicker; the position travels via
transform: translate3d()and lets the browser interpolate the 400ms move (cubic-bezier(0.23, 1, 0.32, 1)); pointer tracking is throttled to 50ms, taking one leading and one trailing sample. - The plot outside the brush selection dims while dragging and restores on release — see the single
<mask>above. - Hovering the plot dims every series except the one nearest the cursor's value at that timestamp to 10% opacity; this is a documented approximation of ECharts
emphasis.focus: 'series', which only emphasizes over an actual item. - Under
prefers-reduced-motion: reduceevery tween lands on its final frame immediately, and all CSS transitions sit inside@media (prefers-reduced-motion: no-preference).
The @talex-touch/tuffex/charts entry also exports the animation primitives, so bespoke charts can reuse the same timings: easings (linear | cubicIn | cubicOut | cubicInOut), cubicBezier(x1, y1, x2, y2), tween({ duration, easing, delay, onUpdate, onComplete }), useEnterProgress(options), useTweenedNumbers(source, options), prefersReducedMotion(), plus the constants ENTER_DURATION 1000, UPDATE_DURATION 500, STATE_DURATION 300 and ANIMATION_THRESHOLD 2000. The tooltip timing constants (TOOLTIP_FADE_DURATION 200, TOOLTIP_MOVE_DURATION 400, TOOLTIP_HIDE_DELAY 100, TOOLTIP_TRACK_THROTTLE 50, tooltipMoveEasing) live in the charts entry's core/animate.
Differences from kumo
enableLegendSelection+ imperative echarts actions → declarativev-model:hidden-series; highlighting viahighlighted-series.tooltipBoundaryperforms the real clipping-ancestors collision walk: it intersects clipping ancestors (offsetParents whoseoverflowis notvisible) with the viewport, flips on overflow, and defaults to'clipping-ancestors'.- The brush no longer just draws the rectangle during a drag: one luminance
<mask>presses everything outside the selection to 30% while each series stays mounted exactly once. - Geometry animation matches ECharts: the pie grows angularly via
animationType: 'expansion'and highlights displace a slice byscaleSize5px; sankey and maps have no geometry animation (SankeyViewhas noinitProps/updateProps, maps setanimationDurationUpdate: 0) — parity, not a gap. - Series-level hover emphasis is an approximation: ECharts blurs the other series only over an actual item, while this picks the nearest series at the cursor's timestamp.
- Keep each series under ~5k points: SVG rendering degrades in the tens of thousands.