A Chartist plugin listens to the phases of a chart and changes its scene: it adds nodes, replaces them or drops them. The terminal draws that same scene, so a plugin needs no terminal version. Pass it in plugins, as you would on an SVG chart.
A target line
This plugin draws a labeled line at a target value, keeps a circle on each value that reaches it, and drops the other points. It’s an ordinary 2.x plugin, written with nothing but chartist:
import { node, type ChartPlugin, type SceneNode } from 'chartist';
/**
* A labeled line at a target value, and a circle on each value that
* reaches it. The other points go.
*/
export const targetLine = (target: number, label = 'target'): ChartPlugin => ({
name: 'target-line',
install(chart) {
let marker: SceneNode | undefined;
chart.on('compose', current => {
// A grid line of the Y axis knows its axis, and so where the target is.
if (
current.role === 'grid' &&
current.ctx.axis.dimension === 'y' &&
current.ctx.index === 0
) {
const { axis, index, x1, x2, y1 } = current.ctx;
const y = y1 - (axis.project(target) - axis.project(axis.ticks[index]));
marker = node('g', {}, 'ct-target')
.append(node('line', { x1, x2, y1: y, y2: y }))
.append(node('text', { x: x1, y: y - 6 }).text(label));
return;
}
if (current.role === 'point') {
const { x, y, value } = current.ctx;
const reached =
value && typeof value === 'object' && 'y' in value
? (value.y ?? 0) >= target
: false;
return reached
? node('circle', { cx: x, cy: y, r: 6 }, 'ct-hit', {
role: current.role,
ctx: current.ctx,
key: current.key
})
: null;
}
});
// Drawn last, on top of the series.
chart.on('scene', ({ scene }) =>
marker ? { scene: scene.append(marker) } : undefined
);
}
});How it works, step by step:
- A grid line of the Y axis carries its axis in
ctx.axis.axis.project()turns the target into px, measured from the same tick as the grid line. - The
scenelistener appends the line and its label to the root, so they’re drawn on top of the series. - For points, the listener returns a
circlewith the point’srole,ctxandkey, ornullto drop it. The circles stay in their series’ group, so they take its color.
On an SVG chart, the same plugin goes into the same option:
import { lineChart } from 'chartist';
import { targetLine } from './target-line';
lineChart('#chart', data, { low: 0, plugins: [targetLine(1000)] });
Events and plugins covers the phases, the scene nodes and writing a plugin.
What the terminal draws
Nodes with one of Chartist’s roles (line, point, bar, slice and the others) are drawn as the terminal draws that role. Every other node is drawn by its element:
| Element | Drawn as |
|---|---|
line |
a braille line between its two ends |
path |
its outline as a braille line, curves flattened |
circle |
a point at its center |
text, foreignObject |
a label, one cell per character |
| anything else | nothing, but its children are drawn |
That goes for nodes a plugin replaced too. The circles above keep the role point, but they’re circles now, so the terminal draws them as circles.
A node in a series’ group, or with a ct-series-x class, takes that series’ color. Other lines and points use the text color, and text the label color. Sizes and styles (a circle’s r, stroke-width, dashes) and the plugin’s own classes don’t show: a cell has a character and a color, and in HTML its classes are the kind of mark and the series.
Plugins that need a page
A terminal chart is laid out and drawn, never mounted. Listeners of the render and mount phases don’t run, and calling update() on the chart throws. So plugins that work with the page, such as tooltips, hover effects and zoom, have nothing to do here. Plugins that change the scene in compose or scene work.
Next: Chartist’s options in the terminal in Customizing charts, or every function on the API page.