Line
Ordered trends with keyed observations inside the path and honest gaps by default.
import { line } from 'visdelta/line';line() shows an ordered trend. .key() identifies observations inside the
SVG path, not only as separate point elements, so a single observation can enter
or leave a line.
import { line } from 'visdelta/line';
import { transition } from 'visdelta/transition';
import 'visdelta/style.css';
const prices = [
{ date: '2026-01-05', ticker: 'NOVA', close: 41 },
{ date: '2026-01-12', ticker: 'NOVA', close: 44 },
{ date: '2026-01-19', ticker: 'NOVA', close: 43 },
{ date: '2026-01-26', ticker: 'NOVA', close: 48 },
{ date: '2026-02-02', ticker: 'NOVA', close: 52 },
{ date: '2026-02-09', ticker: 'NOVA', close: 50 },
{ date: '2026-01-05', ticker: 'ORBIT', close: 33 },
{ date: '2026-01-12', ticker: 'ORBIT', close: 31 },
{ date: '2026-01-19', ticker: 'ORBIT', close: 35 },
{ date: '2026-01-26', ticker: 'ORBIT', close: 34 },
{ date: '2026-02-02', ticker: 'ORBIT', close: 30 },
{ date: '2026-02-09', ticker: 'ORBIT', close: 36 },
];
const detailed = line(prices)
.x('date', { type: 'temporal', label: 'Week' })
.y('close', { label: 'Close (USD)' })
.key(['date', 'ticker'])
.breakdown('ticker')
.color('ticker');
// One mean line splits into one line per ticker.
const from = detailed.rollup({ op: 'mean' });
const to = detailed;
const change = await transition(from, to, { target: '#chart' });
change.play({ duration: 800 }); // or change.progress(0.5)
Methods
| Method | Meaning |
|---|---|
.curve(d3CurveName) | Use any exact D3 line-curve export |
.connect('adjacent' | 'across') | Keep honest gaps, or connect across them |
.strokeWidth(number) | Set the line width |
.pointSize(number) | Set the point radius |
.flip(options?) | Swap the position mappings in an explicit order |
.breakdown(field, options?) | Split one line into series |
.rollup(options?) | Combine series into one line |
Curve names are exact D3 exports such as curveLinear, curveStep and
curveMonotoneX. Line also accepts curveBundle. The full list is exported as
D3_CURVE_NAMES.
const prices = line(rows)
.x('date', { type: 'temporal' })
.y('close')
.key(['date', 'ticker'])
.breakdown('ticker')
.color('ticker');
const average = prices.rollup({ op: 'mean' });Transition behaviour
- Adding an observation extends the line to it before its point appears.
- Removing or filtering runs the same frames backward: the point leaves before the segment retracts.
- Gaps stay honest. With the default
connect('adjacent'), filtered observations leave a visible gap.connect('across')joins across them. - Split and merge zip series out of, and back into, the summary line.
Limits
The declaration planner treats raw y remapping as an Encoding operation and a supported summary (source field, reducer and output alias) as one Grain operation. Raw-to-summary pairs keep Line's native route when eligible. Complex pipelines remain outside the planner and use the ordinary transition.
Try it
Edit an average line that unzips into AAPL and GOOG in the playground.