SparkChart
A smooth canvas trend chart with optional axes, active crosshair and accessible hover values.
Usage
SparkChart + ChartScrubber
A scrubbable trend snapshot
Smooth paired trends, axes and a value readout under the pointer.
Best Practices
- Give the stage a definite height, otherwise a zero-height container cannot paint.
- Use
aria-labelandSparkSeries.label; hover values then remain available outside the visual tooltip. - Use the monotone default with evenly spaced, reasonably dense samples. Sparse samples are still sparse data; smoothing should not invent them.
- Bind one
activeIndextoTxChartScrubberandTxSparkChartwhen both are present. - Both map the pointer through the plot box, not the stage, so the crosshair lands on the sample it reports. The chart publishes its own gutters as
--tx-bui-plot-left/--tx-bui-plot-righton its root; the scrubber reads them off the element it wraps, so there is nothing to keep in sync by hand. - The tooltip is centred on the cursor and only pulled inward when it would overhang the stage. Keep it narrower than the stage or it stops travelling.
API Reference
SparkChart Props
| Name | Type | Default | Description |
|---|---|---|---|
series | SparkSeries[] | — | Series list, { id, data, color?, label? }. |
theme | 'light' | 'dark' | 'auto' | 'auto' | auto follows data-theme or .dark. |
grid | boolean | false | Draws horizontal hairline gridlines. |
gridLines | number | 4 | Number of gridlines. |
lineWidth | number | 2.25 | Stroke width in CSS pixels. |
curve | LineCurve | 'monotone' | linear, monotone, natural, or step. |
xAxis / yAxis | boolean | false | Draw compact x/y baselines and labels. |
xTicks / yTicks | number | 3 / 4 | Number of x/y labels. |
xTickFormat / yTickFormat | (value: number) => string | — | Override x/y label formatting. |
padding | Partial<SparkChartPadding> | { top: 24, right: 0, bottom: 22, left: 0 } | Inner inset; axes reserve their own minimum edges. |
domain | [number, number] | — | Fixed value range; omit to fit the data. |
activeIndex | number | null | — | Controlled highlighted sample. |
interactive | boolean | true | Enables pointer and keyboard hover state. |
baseline | boolean | true | Dashed rule at each series' own starting value. Without a reference the eye can see that a line wobbles but not whether it ended up above or below where it began. Per series rather than one shared zero line, because two series on one spark chart rarely share a scale. |
endpoint | boolean | true | Filled dot on each series' last sample. The line's end is the current value — the one number the reader is after — and a stroke alone gives it no more weight than any midpoint. |
animation | boolean | true | ECharts-parity 1000ms enter reveal and 500ms updates. |
ariaLabel | string | — | Accessible name for the canvas. |
SparkPoint is { time: number, value: number }; time positions a sample and need not be an epoch. SparkSeries.label is used in an accessible hover announcement when supplied.
SparkChart Events
| Event | Payload | Description |
|---|---|---|
update:activeIndex | (index: number | null) | Controlled hover write-back. |
hover | (index: number) | A new active sample was reached. |
leave | — | The pointer left or Escape cleared the active sample. |
ChartScrubber Props
| Name | Type | Default | Description |
|---|---|---|---|
pointCount | number | — | How many samples the pointer maps onto. |
activeIndex | number | null | — | Controlled index. Omit to let the component own it. |
rows | ChartTooltipRow[] | — | Tooltip rows, { label, value, color? }. |
timeLabel | string | — | Caption line above the rows. |
tooltip | boolean | true | Turn off for a bare cursor line. |
anchorMargin | number | 8 | Gap kept between the tooltip and the stage edges, in px. |
disabled | boolean | false | Ignores the pointer. |
ChartScrubber Events
| Event | Payload | Description |
|---|---|---|
scrub | (index: number) | The pointer reached a new sample. |
leave | — | Pointer left, lifted, or was cancelled. |
update:activeIndex | (index: number | null) | Controlled write-back. |
Sizing and Theme
The chart fills its container and measures that container rather than taking a width or height prop. Give the wrapper a definite height. A ResizeObserver repaints it on resize; the bitmap is scaled by devicePixelRatio (capped at 2) while draw maths stays in CSS pixels.
theme defaults to 'auto' and follows data-theme or .dark on <html> and <body>. Canvas cannot inherit CSS variables, so a theme change repaints with the current token colours.
Curves, Axes, and Hover
The default curve="monotone" uses the same d3 curve factory as the full @talex-touch/tuffex/charts line series: it avoids the angular polyline without overshooting local extrema. Choose linear, natural, or step only when that encoding is intentional.
xAxis and yAxis draw compact baselines and ticks inside the canvas. Their padding is reserved automatically; use xTickFormat and yTickFormat when raw time or value numbers are not useful to readers.
interactive gives the standalone chart a pointer/keyboard crosshair: arrows, Home, End and Escape move or clear the active sample. Controlled activeIndex lets a surrounding TxChartScrubber own the tooltip while the canvas still draws the highlighted dots. The chart and scrubber both announce active values through a polite live region.
Overview
- Every series shares one value domain; x is derived from
time, or even index spacing when timestamps collapse. A single sample is centred and painted as a round-cap dot. - The active crosshair and dots use the controlled index when present. An outer scrubber can therefore own the DOM tooltip without losing the canvas affordance.
- Empty data, a zero-sized container, or no 2D context paint nothing and throw nothing.
- Enter motion is 1000ms
cubicInOut; data updates use 500mscubicInOut; both skip above 2000 points and underprefers-reduced-motion: reduce.
Technologies
- Component source:
packages/tuffex/packages/components/src/spark-chart/src/TxSparkChart.vue,TxChartScrubber.vue. - Projection and painting:
packages/tuffex/packages/components/src/spark-chart/src/geometry.ts,draw.ts. - Types:
packages/tuffex/packages/components/src/spark-chart/src/types.ts. - Tested coverage:
packages/tuffex/packages/components/src/spark-chart/__tests__/spark-chart.test.ts(33 cases) covers domains, projection, monotone canvas strokes, x/y axes and edge-label anchoring, hover dots, keyboard state, scrubber control and accessibility. - Adapted from Beautiful UI (https://www.beautifului.dev), © 2026 Shane Levine, MIT.
- The chart is intentionally canvas-first: the draw-call surface is testable even where jsdom has no 2D context.
- The full chart family now lives at
@talex-touch/tuffex/charts; SparkChart stays a compact card primitive at the root TuffEx entry. - No area fill is offered: the user request is a legible trend readout, not an uncertain extrapolation between sparse points.