# Trend lines, moving averages and year-over-year comparison

> series.trend adds a linear trend or moving average; compare overlays the previous period as a dashed series with change and change % in the tooltip.

Source: https://82chart.com/en/docs/trend-compare/

A trend line shows the overall direction through values that jump around. A linear trend is the straight line closest to all values (least squares); a moving average joins the mean of the last few periods and smooths out short swings. A year-over-year comparison overlays the same months of last year so the change is visible.

In 82chart 0.5 both are one option. `trend` on a series draws a thin dashed line in its color; `compare` on the chart overlays the previous period as a muted dashed series and adds **change** and **change %** to the tooltip.

## Trend lines and moving averages

```js
createChart('#chart', {
  type: 'line',
  title: 'Daily visitors in September',
  data: {
    labels: Array.from({ length: 30 }, (_, i) => '2026-09-' + String(i + 1).padStart(2, '0')),
    series: [
      {
        name: 'Visitors',
        data: Array.from({ length: 30 }, (_, i) => Math.round(1200 + i * 18 + Math.sin(i * 0.9) * 160)),
        trend: 'linear',
      },
      {
        name: 'Members',
        data: Array.from({ length: 30 }, (_, i) => Math.round(520 + i * 6 + ((i + 2) % 7 < 2 ? -140 : 0) + Math.cos(i) * 40)),
        trend: { type: 'moving', period: 7 },
      },
    ],
  },
});
```

- Trend lines get their own legend entries, such as "Visitors trend" and "Members 7-period moving average" (rename with `trend.name`), switch on and off separately and show in the tooltip.
- Linear is a least-squares line through the points that have a value, from the first to the last of them. Moving is the trailing mean of `period` values (default 7); a gap (`null`) restarts it.
- Line, area and bar series on a shared x. Not for scatter plots, pyramids, waterfalls or horizontal bars.
- Trend lines are not data, so CSV, xlsx and the table leave them out.

## Year over year from the data (shift)

Pass 24 months with `previous: 'shift'`: the first 12 are the base and the latest 12 are drawn. Hover a bar for last year's value, the change and the change %. With `deltaColors: 'korea'` changes read ▲ red and ▼ blue.

```js
createChart('#chart', {
  type: 'bar',
  title: 'Monthly sales vs the same month last year',
  prefix: '₩',
  deltaColors: 'korea',
  // 24 months in: the first 12 are the base, the latest 12 are drawn
  compare: { previous: 'shift', period: 12, label: 'Last year' },
  data: {
    labels: Array.from({ length: 24 }, (_, i) => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][i % 12] + (i < 12 ? ' 25' : ' 26')),
    series: [{
      name: 'Sales',
      data: Array.from({ length: 24 }, (_, i) => Math.round((180 + i * 4 + Math.sin(i / 1.9) * 22) * 1e6)),
    }],
  },
});
```

- The spacing of `'shift'` (`period`) comes from date x values: 12 for months, 4 quarters, 7 days (the same weekday), 24 hours, 1 otherwise. With name labels as above, set `period: 12`; weekly data takes `period: 52`.
- The previous period is data: CSV, xlsx and the table get a column for it.

## Previous period as separate data

When last year's values come from elsewhere, give `previous` a `ChartData`. Series match by order and values by position (value j of the first series is the previous value at this chart's x j).

```js
createChart('#chart', {
  type: 'line',
  title: 'Sign-ups per quarter, year over year',
  compare: {
    label: 'Last year',
    previous: { series: [{ data: [4100, 4520, 4380, 5010] }] },
  },
  data: {
    labels: ['1Q', '2Q', '3Q', '4Q'].map((q) => q + ' 2026'),
    series: [{ name: 'Sign-ups', data: [4620, 4810, 5240, 5580] }],
  },
});
```

## Options

| Option | What it does |
| --- | --- |
| `series[i].trend` | `'linear'`, `'moving'` or `{ type: 'linear' \| 'moving', period?: 7, name? }` |
| `compare.previous` | A `ChartData` (series by order, values by position) or `'shift'` |
| `compare.label` | Name of the previous period (default 'Previous'), as in 'Sales (Last year)' |
| `compare.period` | `'shift'` spacing (default: from the x spacing) |
| `deltaColors` | `'korea'`: changes as ▲ red and ▼ blue |
| `locale.trend`, `movingAverage`, `previous`, `compareChange`, `compareRate` | Wording |

## Frequently asked questions

### Does year-over-year need a second axis?

No. The previous period is drawn on the same axis in the same unit, so there is no dual axis to misread; change and change % are numbers in the tooltip.

### Can the legend switch a trend line off?

Yes. A trend line has its own legend entry and toggles separately; hiding the series hides its trend too.

### Do trend lines and last year go into the Excel export?

The previous period is data and gets a column in CSV and xlsx; trend lines are computed guides and are left out.
