Packages
Sparklines
The 4.8 KB build for tables and cards: line, area, column and win-loss.
The 5.4 KB Build
@ortex-charts/lite is a separate package with one job: a tiny canvas chart for a table
cell or a card. It is 4.8 KB gzipped, depends only on @ortex-charts/math, and has no
axes, no crosshair, no legend and no interaction. A table with 300 sparklines schedules one
animation frame, not 300.
npm install @ortex-charts/lite
import { createSparkline } from "@ortex-charts/lite";
const spark = createSparkline(cell, { kind: "area", colorByTrend: true, width: 120, height: 28 });
spark.setData(closes);@ortex-charts/liteFour Kinds
| Kind | Draws | Used for |
|---|---|---|
line |
A polyline, optionally curved, with an endpoint dot. | Price and value history. |
area |
The same line with a fill beneath it. | The same, with more weight in a dense table. |
column |
One column per value, colored by sign around baseline. |
Returns, flows, changes. |
winloss |
Equal-height marks up or down by sign. | Win and loss streaks, hit rates. |
createSparkline(el, { kind: "line" });
createSparkline(el, { kind: "column", baseline: 0 });
createSparkline(el, { kind: "winloss", baseline: 0 });
Data
spark.setData([12.4, 12.9, 12.1, 13.4]); // numbers
spark.setData([{ value: 12.4 }, { value: 12.9 }]); // rows
spark.setData([[t1, 12.4], [t2, 12.9]]); // [time, value] pairs
Time is accepted but not used for spacing: points are evenly spaced. A sparkline is a shape, not a chart, and a gap in the dates does not become a gap in the line.
spark.push(13.1); // append one value
spark.push(13.1, 60); // append, keeping at most 60 points
push is the live path. It is cheap enough to call on every tick of a streaming table.
Options
| Option | Default | What it does |
|---|---|---|
kind |
"line" |
One of the four above. |
width, height |
container size, else 100 by 28 | Canvas size in CSS pixels. |
color |
"#4C8DFF" |
Line or column color. |
positiveColor |
"#22C08A" |
Used by colorByTrend and by sign coloring. |
negativeColor |
"#EF4E5A" |
The same, downward. |
colorByTrend |
false |
Color the whole sparkline by whether the last value is above the first. |
lineWidth |
1.5 |
Stroke width. |
curve |
"linear" |
linear, step, monotone or smooth. |
fillOpacity |
0.18 |
Area fill opacity. |
endpoint |
true |
Dot at the last point. |
endpointRadius |
2 |
Its radius. |
baseline |
null |
Draw a faint line at this value and color columns by sign around it. |
baselineColor |
a faint gray | Color of that line. |
min, max |
data extent | Fixed value range, for comparability across rows. |
padding |
2 |
Inset in CSS pixels. |
extremes |
false |
Highlight the minimum and maximum points. |
background |
"transparent" |
Canvas background. |
SPARKLINE_DEFAULTS is exported if you want to derive from the defaults.
The two options that matter most in a table are colorByTrend and min/max.
colorByTrend is what makes a column of sparklines readable at a glance without a legend.
Fixing min and max makes rows comparable to each other; leaving them unset makes each
row use its full height, which reads better per row and worse down the column. Choose
deliberately.
The Handle
const spark = createSparkline(el, options);
spark.canvas; // the <canvas> element, appended to the container
spark.setData(values);
spark.push(value, maxPoints?);
spark.applyOptions({ kind: "column", color: "#F5A524" });
spark.resize(160, 32);
spark.invalidate(); // schedule a redraw
spark.flush(); // draw now, synchronously
spark.remove(); // detach and stop
Every mutator returns this, so calls chain. flush() is the one to call before taking a
screenshot or asserting in a test, because drawing is otherwise deferred to the next frame.
The Shared Render Loop
Every sparkline on the page schedules its redraw on one RenderScheduler, exported as
renderScheduler. A table that updates 300 cells in a loop produces one animation frame
with 300 draws, not 300 frames. This is the reason the package exists separately from
@ortex-charts/core, and it is why the cost of a sparkline table is proportional to the
data rather than to the number of cells.
You do not have to do anything to get this. It applies automatically.
In a Table
import { createSparkline, type Sparkline } from "@ortex-charts/lite";
const sparks = new Map<string, Sparkline>();
for (const row of rows) {
const cell = document.querySelector<HTMLElement>(`#spark-${row.id}`)!;
const spark = createSparkline(cell, {
kind: "area",
colorByTrend: true,
width: 120,
height: 26,
endpoint: true,
});
spark.setData(row.closes);
sparks.set(row.id, spark);
}
// Live: one push per row, one frame for all of them.
feed.subscribe((tick) => sparks.get(tick.id)?.push(tick.price, 120));
// Teardown, when the table unmounts.
for (const s of sparks.values()) s.remove();
Beside a Line of Text
A sparkline sized to the type next to it is the densest useful form, and it needs no chrome at all.
createSparkline(span, {
kind: "line",
width: 56,
height: 14,
lineWidth: 1,
endpoint: false,
padding: 1,
colorByTrend: true,
});
Keep the container display: inline-block with line-height: 0 so the canvas sits on the
text baseline instead of adding a descender's worth of space.
@ortex-charts/liteIn React
import { Sparkline } from "@ortex-charts/react";
<Sparkline data={closes} width={120} height={28} options={{ kind: "area", colorByTrend: true }} />
The component creates the sparkline on mount, applies data and option changes in place, and
removes it on unmount. The instance is available through ref when you want push. See
React.
When to Use the Full Chart Instead
@ortex-charts/lite is deliberately small, and the things it does not do are the reason it
is small.
- No axes, no ticks, no labels. If you need a scale, use
@ortex-charts/financialor@ortex-charts/viz. - No crosshair, no tooltip, no hit testing. Hovering does nothing. A tooltip on a
sparkline is a
titleattribute or your own overlay on the container. - No time axis. Points are evenly spaced regardless of their timestamps.
- No theme object. Colors are options on the sparkline, not tokens, because pulling in the theme would pull in the engine.
- No multiple series. One array of numbers per sparkline.
The crossover point in practice is a tooltip. As soon as a small chart needs to tell the
user what a point is worth, it wants
createFinancialChart with most of the chrome switched off, which is
about 56 KB gzipped instead of 4.8 KB.