# Sparklines

> The 3.3 KB build for tables and cards: line, area, column and win-loss.

Section: Packages. Source: https://ortexcharts.com/docs/sparklines

## 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 3.3 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.

```bash
npm install @ortex-charts/lite
```

```ts
import { createSparkline } from "@ortex-charts/lite";

const spark = createSparkline(cell, { kind: "area", colorByTrend: true, width: 120, height: 28 });
spark.setData(closes);
```

_Live example: [sparkline-table](https://ortexcharts.com/examples/sparkline-table)_

## Four 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. |

```ts
createSparkline(el, { kind: "line" });
createSparkline(el, { kind: "column", baseline: 0 });
createSparkline(el, { kind: "winloss", baseline: 0 });
```

## Data

```ts
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.

```ts
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

```ts
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

```ts
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.

```ts
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.

_Live example: [spark-cells](https://ortexcharts.com/examples/spark-cells)_

## In React

```tsx
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](https://ortexcharts.com/docs/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/financial` or
  `@ortex-charts/viz`.
- **No crosshair, no tooltip, no hit testing.** Hovering does nothing. A tooltip on a
  sparkline is a `title` attribute 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`](https://ortexcharts.com/docs/quickstart) with most of the chrome switched off, which is
about 56 KB gzipped instead of 3.3 KB.
