---
product: "AG Charts"
title: "Animation"
description: "Switch between the different series types below to see their initial load animations. Toggling items in the legend will also animate the series in and out."
enterprise: true
framework: vue
version: "14.2.0"
related:
    - title: "Accessibility"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/accessibility/"
    - title: "Localisation"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/localisation/"
    - title: "Series Highlighting"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/series-highlighting/"
    - title: "Tooltips"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/tooltips/"
    - title: "Touch"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/touch/"
    - title: "Context Menu"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/context-menu/"
    - title: "Crosshairs & Band Highlight"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/axes-crosshairs/"
    - title: "Data Selection"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/selection/"
    - title: "Flash On Update"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/flash-on-update/"
    - title: "Navigator"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/navigator/"
    - title: "Range Controls"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/range-controls/"
    - title: "Scrollbar"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/scrollbar/"
    - title: "Synchronization"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/sync/"
    - title: "Zoom"
      url: "https://www.ag-grid.com/charts/archive/14.2.0/vue/zoom/"
llms: "https://www.ag-grid.com/charts/archive/14.2.0/llms.txt"
---

# Animation

## Initial Load

Switch between the different series types below to see their initial load animations. Toggling items in the legend will also animate the series in and out.

#### Initial Load

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import {
  AnimationModule,
  AreaSeriesModule,
  BarSeriesModule,
  CategoryAxisModule,
  ContextMenuModule,
  CrosshairModule,
  DonutSeriesModule,
  LegendModule,
  LineSeriesModule,
  ModuleRegistry,
  NumberAxisModule,
  PieSeriesModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";

const numFormatter = new Intl.NumberFormat("en-US");

const tooltip = {
  renderer: ({ datum, yKey, yName }) => {
    return {
      data: [{ label: yName, value: numFormatter.format(Number(datum[yKey])) }],
    };
  },
};

const barOptions = {
  series: [
    {
      type: "bar",
      xKey: "station",
      yKey: "early",
      stacked: true,
      yName: "Early",
      tooltip,
    },
    {
      type: "bar",
      xKey: "station",
      yKey: "morningPeak",
      yName: "Morning peak",
      stacked: true,
      tooltip,
    },
    {
      type: "bar",
      xKey: "station",
      yKey: "interPeak",
      yName: "Between peak",
      stacked: true,
      tooltip,
    },
    {
      type: "bar",
      xKey: "station",
      yKey: "afternoonPeak",
      yName: "Afternoon peak",
      stacked: true,
      tooltip,
    },
    {
      type: "bar",
      xKey: "station",
      yKey: "evening",
      yName: "Evening",
      stacked: true,
      tooltip,
    },
  ],
  axes: {
    x: {
      type: "category",
      label: {
        wrapping: "on-space",
        autoRotate: false,
      },
    },
    y: {
      type: "number",
      label: {
        formatter: (params) => {
          return params.value / 1000 + "k";
        },
      },
    },
  },
};

const lineOptions = {
  series: [
    {
      type: "line",
      xKey: "station",
      yKey: "early",
      yName: "Early",
      tooltip,
    },
    {
      type: "line",
      xKey: "station",
      yKey: "morningPeak",
      yName: "Morning peak",
      tooltip,
    },
    {
      type: "line",
      xKey: "station",
      yKey: "interPeak",
      yName: "Between peak",
      tooltip,
    },
    {
      type: "line",
      xKey: "station",
      yKey: "afternoonPeak",
      yName: "Afternoon peak",
      tooltip,
    },
    {
      type: "line",
      xKey: "station",
      yKey: "evening",
      yName: "Evening",
      tooltip,
    },
  ],
  axes: {
    x: {
      type: "category",
      label: {
        wrapping: "on-space",
        autoRotate: false,
      },
    },
    y: {
      type: "number",
      label: {
        formatter: (params) => {
          return params.value / 1000 + "k";
        },
      },
    },
  },
};

const areaOptions = {
  series: [
    {
      type: "area",
      xKey: "station",
      yKey: "early",
      stacked: true,
      yName: "Early",
      tooltip,
    },
    {
      type: "area",
      xKey: "station",
      yKey: "morningPeak",
      yName: "Morning peak",
      stacked: true,
      tooltip,
    },
    {
      type: "area",
      xKey: "station",
      yKey: "interPeak",
      yName: "Between peak",
      stacked: true,
      tooltip,
    },
    {
      type: "area",
      xKey: "station",
      yKey: "afternoonPeak",
      yName: "Afternoon peak",
      stacked: true,
      tooltip,
    },
    {
      type: "area",
      xKey: "station",
      yKey: "evening",
      yName: "Evening",
      stacked: true,
      tooltip,
    },
  ],
  axes: {
    x: {
      type: "category",
      label: {
        wrapping: "on-space",
        autoRotate: false,
      },
    },
    y: {
      type: "number",
      label: {
        formatter: (params) => {
          return params.value / 1000 + "k";
        },
      },
    },
  },
};

const donutOptions = {
  series: [
    {
      type: "pie",
      title: {
        text: "Morning Peak",
      },
      calloutLabelKey: "station",
      legendItemKey: "station",
      angleKey: "morningPeak",
      outerRadiusRatio: 0.6,
    },
    {
      type: "donut",
      title: {
        text: "Afternoon Peak",
      },
      calloutLabelKey: "station",
      legendItemKey: "station",
      angleKey: "afternoonPeak",
      showInLegend: false,
    },
  ],
};

ModuleRegistry.registerModules([
  AnimationModule,
  AreaSeriesModule,
  BarSeriesModule,
  CategoryAxisModule,
  CrosshairModule,
  DonutSeriesModule,
  LegendModule,
  LineSeriesModule,
  NumberAxisModule,
  PieSeriesModule,
  ContextMenuModule,
]);

const ChartExample = defineComponent({
  template: `
    <div class="example-controls">
      <div class="controls-row">
        <div class="button-group" role="group" aria-label="Series Type">
          <input type="radio" id="series-bar" name="series-type" value="bar" checked="" v-on:change="seriesTypeChange($event)">
            <label for="series-bar">Bar</label>
            <input type="radio" id="series-line" name="series-type" value="line" v-on:change="seriesTypeChange($event)">
              <label for="series-line">Line</label>
              <input type="radio" id="series-area" name="series-type" value="area" v-on:change="seriesTypeChange($event)">
                <label for="series-area">Area</label>
                <input type="radio" id="series-donut" name="series-type" value="donut" v-on:change="seriesTypeChange($event)">
                  <label for="series-donut">Pie &amp; Donut</label>
                </div>
              </div>
            </div>
            <ag-charts
              :options="options"
            />
  `,
  components: {
    "ag-charts": AgCharts,
  },
  setup(props) {
    const options = ref<
      AgCartesianChartOptions<DataType> | AgPolarChartOptions<DataType>
    >({
      data: getData(),
      animation: {
        enabled: true,
      },
      ...barOptions,
    });

    const seriesTypeChange = (event) => {
      const optionsCopy = clone(options.value);

      const value = event.target.value;
      const seriesOptions = {
        bar: barOptions,
        line: lineOptions,
        area: areaOptions,
        donut: donutOptions,
      }[value];
      optionsCopy.series = seriesOptions.series;
      optionsCopy.axes = seriesOptions.axes;

      options.value = optionsCopy;
    };

    return {
      options,
      seriesTypeChange,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: Initial Load](https://www.ag-grid.com/charts/archive/14.2.0/vue3/animation/examples/initial-load/)

## Data Updates

A data update animation is split into three sequential phases — remove, update then add, which can be observed for different series types in this example:

#### Line Series Data Updates

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import {
  AnimationModule,
  AreaSeriesModule,
  BarSeriesModule,
  CategoryAxisModule,
  ContextMenuModule,
  CrosshairModule,
  DonutSeriesModule,
  LegendModule,
  LineSeriesModule,
  ModuleRegistry,
  NumberAxisModule,
  PieSeriesModule,
} from "ag-charts-enterprise";
import { getData, random } from "./data";
import clone from "clone";

let start = [120, 150, 130, 140, 80];

let variance = 20;

let offset = 0;

let length = 8;

let seed = 1234;

const barOptions = {
  series: [
    {
      type: "bar",
      xKey: "year",
      yKey: "one",
      yName: "One",
      stacked: true,
    },
    {
      type: "bar",
      xKey: "year",
      yKey: "two",
      yName: "Two",
      stacked: true,
    },
    {
      type: "bar",
      xKey: "year",
      yKey: "three",
      yName: "Three",
      stacked: true,
    },
    {
      type: "bar",
      xKey: "year",
      yKey: "four",
      yName: "Four",
      stacked: true,
    },
    {
      type: "bar",
      xKey: "year",
      yKey: "five",
      yName: "Five",
      stacked: true,
    },
  ],
  axes: {
    x: {
      type: "category",
      label: {
        autoRotate: false,
      },
    },
  },
};

const lineOptions = {
  series: [
    {
      type: "line",
      xKey: "year",
      yKey: "one",
      yName: "One",
    },
    {
      type: "line",
      xKey: "year",
      yKey: "two",
      yName: "Two",
    },
    {
      type: "line",
      xKey: "year",
      yKey: "three",
      yName: "Three",
    },
    {
      type: "line",
      xKey: "year",
      yKey: "four",
      yName: "Four",
    },
    {
      type: "line",
      xKey: "year",
      yKey: "five",
      yName: "Five",
    },
  ],
  axes: {
    x: {
      type: "number",
      nice: false,
      label: {
        autoRotate: false,
      },
    },
  },
};

const areaOptions = {
  series: [
    {
      type: "area",
      xKey: "year",
      yKey: "one",
      yName: "One",
      stacked: true,
    },
    {
      type: "area",
      xKey: "year",
      yKey: "two",
      yName: "Two",
      stacked: true,
    },
    {
      type: "area",
      xKey: "year",
      yKey: "three",
      yName: "Three",
      stacked: true,
    },
    {
      type: "area",
      xKey: "year",
      yKey: "four",
      yName: "Four",
      stacked: true,
    },
    {
      type: "area",
      xKey: "year",
      yKey: "five",
      yName: "Five",
      stacked: true,
    },
  ],
  axes: {
    x: {
      type: "number",
      nice: false,
      label: {
        autoRotate: false,
      },
    },
  },
};

const donutOptions = {
  series: [
    {
      type: "pie",
      title: {
        text: "One",
      },
      calloutLabelKey: "year",
      legendItemKey: "year",
      angleKey: "one",
      outerRadiusRatio: 0.6,
    },
    {
      type: "donut",
      title: {
        text: "Two",
      },
      calloutLabelKey: "year",
      legendItemKey: "year",
      angleKey: "two",
      showInLegend: false,
    },
  ],
};

function getGeneratedData() {
  return getData(start, variance, offset, length, seed);
}

ModuleRegistry.registerModules([
  AnimationModule,
  AreaSeriesModule,
  BarSeriesModule,
  CategoryAxisModule,
  CrosshairModule,
  DonutSeriesModule,
  LegendModule,
  LineSeriesModule,
  NumberAxisModule,
  PieSeriesModule,
  ContextMenuModule,
]);

const ChartExample = defineComponent({
  template: `
    <div class="example-controls">
      <div class="controls-row">
        <div class="button-group gap-right" role="group" aria-label="Series Type">
          <input type="radio" id="series-bar" name="series-type" value="bar" checked="" v-on:change="seriesTypeChange($event)">
            <label for="series-bar">Bar</label>
            <input type="radio" id="series-line" name="series-type" value="line" v-on:change="seriesTypeChange($event)">
              <label for="series-line">Line</label>
              <input type="radio" id="series-area" name="series-type" value="area" v-on:change="seriesTypeChange($event)">
                <label for="series-area">Area</label>
                <input type="radio" id="series-donut" name="series-type" value="donut" v-on:change="seriesTypeChange($event)">
                  <label for="series-donut">Pie &amp; Donut</label>
                </div>
                <button class="animation-data-updates__action" v-on:click="add()">Add</button>
                <button class="animation-data-updates__action" v-on:click="remove()">Remove</button>
                <button class="animation-data-updates__action gap-right" v-on:click="update()">Update</button>
                <button class="animation-data-updates__action" v-on:click="addRemoveUpdate()">Add &amp; Remove &amp; Update</button>
              </div>
            </div>
            <ag-charts
              :options="options"
            />
  `,
  components: {
    "ag-charts": AgCharts,
  },
  setup(props) {
    const options = ref<AgCartesianChartOptions | AgPolarChartOptions>({
      animation: {
        enabled: true,
      },
      data: getGeneratedData(),
      ...barOptions,
    });

    const seriesTypeChange = (event) => {
      const optionsCopy = clone(options.value);

      const seriesType = event.target.value;
      offset = 0;
      seed = 1234;
      switch (seriesType) {
        case "bar":
          variance = 20;
          length = 8;
          optionsCopy.series = barOptions.series;
          optionsCopy.axes = barOptions.axes;
          break;
        case "line":
          variance = 4;
          length = 30;
          optionsCopy.series = lineOptions.series;
          optionsCopy.axes = lineOptions.axes;
          break;
        case "area":
          variance = 20;
          length = 30;
          optionsCopy.series = areaOptions.series;
          optionsCopy.axes = areaOptions.axes;
          break;
        case "donut":
          variance = 30;
          length = 6;
          optionsCopy.series = donutOptions.series;
          optionsCopy.axes = donutOptions.axes;
          break;
      }
      optionsCopy.data = getGeneratedData();

      options.value = optionsCopy;
    };
    const add = () => {
      const optionsCopy = clone(options.value);

      offset++;
      length++;
      optionsCopy.data = getGeneratedData();

      options.value = optionsCopy;
    };
    const remove = () => {
      const optionsCopy = clone(options.value);

      if (optionsCopy.series?.[0].type === "pie") offset--;
      length = Math.max(0, length - 1);
      optionsCopy.data = getGeneratedData();

      options.value = optionsCopy;
    };
    const update = () => {
      const optionsCopy = clone(options.value);

      seed = Math.floor(random() * 1000);
      optionsCopy.data = getGeneratedData();

      options.value = optionsCopy;
    };
    const addRemoveUpdate = () => {
      const optionsCopy = clone(options.value);

      if (optionsCopy.series?.[0].type === "pie") offset--;
      if (optionsCopy.series?.[0].type !== "pie") offset++;
      seed = Math.floor(random() * 1000);
      optionsCopy.data = getGeneratedData();

      options.value = optionsCopy;
    };

    return {
      options,
      seriesTypeChange,
      add,
      remove,
      update,
      addRemoveUpdate,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: Line Series Data Updates](https://www.ag-grid.com/charts/archive/14.2.0/vue3/animation/examples/data-updates/)

## Duration

You can use the `duration` option to specify the length of all animations in milliseconds.

For an initial load, this is simply the duration of the whole animation.

For a data update, the duration is the total time of all three animation phases together — remove, update then add.

```js
{
    animation: {
        duration: 500,
    },
}
```

In this example, click a duration then change the series type to see the initial load animation.

#### Duration

```ts
import { createApp, defineComponent, ref } from "vue";
import { AgCharts } from "ag-charts-vue3";
import type { AgChartOptions } from "ag-charts-types";
import {
  AnimationModule,
  AreaSeriesModule,
  BarSeriesModule,
  CategoryAxisModule,
  ContextMenuModule,
  CrosshairModule,
  DonutSeriesModule,
  LegendModule,
  LineSeriesModule,
  ModuleRegistry,
  NumberAxisModule,
  PieSeriesModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";

const numFormatter = new Intl.NumberFormat("en-US");

const tooltip = {
  renderer: ({ datum, yKey, yName }) => {
    return {
      data: [{ label: yName, value: numFormatter.format(Number(datum[yKey])) }],
    };
  },
};

const barOptions = {
  series: [
    {
      type: "bar",
      xKey: "station",
      yKey: "early",
      stacked: true,
      yName: "Early",
      tooltip,
    },
    {
      type: "bar",
      xKey: "station",
      yKey: "morningPeak",
      yName: "Morning peak",
      stacked: true,
      tooltip,
    },
    {
      type: "bar",
      xKey: "station",
      yKey: "interPeak",
      yName: "Between peak",
      stacked: true,
      tooltip,
    },
    {
      type: "bar",
      xKey: "station",
      yKey: "afternoonPeak",
      yName: "Afternoon peak",
      stacked: true,
      tooltip,
    },
    {
      type: "bar",
      xKey: "station",
      yKey: "evening",
      yName: "Evening",
      stacked: true,
      tooltip,
    },
  ],
  axes: {
    y: {
      type: "number",
      label: {
        formatter: (params) => {
          return params.value / 1000 + "k";
        },
      },
    },
  },
};

const lineOptions = {
  series: [
    {
      type: "line",
      xKey: "station",
      yKey: "early",
      yName: "Early",
      tooltip,
    },
    {
      type: "line",
      xKey: "station",
      yKey: "morningPeak",
      yName: "Morning peak",
      tooltip,
    },
    {
      type: "line",
      xKey: "station",
      yKey: "interPeak",
      yName: "Between peak",
      tooltip,
    },
    {
      type: "line",
      xKey: "station",
      yKey: "afternoonPeak",
      yName: "Afternoon peak",
      tooltip,
    },
    {
      type: "line",
      xKey: "station",
      yKey: "evening",
      yName: "Evening",
      tooltip,
    },
  ],
  axes: {
    y: {
      type: "number",
      label: {
        formatter: (params) => {
          return params.value / 1000 + "k";
        },
      },
    },
  },
};

const areaOptions = {
  series: [
    {
      type: "area",
      xKey: "station",
      yKey: "early",
      stacked: true,
      yName: "Early",
      tooltip,
    },
    {
      type: "area",
      xKey: "station",
      yKey: "morningPeak",
      yName: "Morning peak",
      stacked: true,
      tooltip,
    },
    {
      type: "area",
      xKey: "station",
      yKey: "interPeak",
      yName: "Between peak",
      stacked: true,
      tooltip,
    },
    {
      type: "area",
      xKey: "station",
      yKey: "afternoonPeak",
      yName: "Afternoon peak",
      stacked: true,
      tooltip,
    },
    {
      type: "area",
      xKey: "station",
      yKey: "evening",
      yName: "Evening",
      stacked: true,
      tooltip,
    },
  ],
  axes: {
    y: {
      type: "number",
      label: {
        formatter: (params) => {
          return params.value / 1000 + "k";
        },
      },
    },
  },
};

const donutOptions = {
  series: [
    {
      type: "pie",
      title: {
        text: "Morning Peak",
      },
      calloutLabelKey: "station",
      legendItemKey: "station",
      angleKey: "morningPeak",
      outerRadiusRatio: 0.6,
    },
    {
      type: "donut",
      title: {
        text: "Afternoon Peak",
      },
      calloutLabelKey: "station",
      legendItemKey: "station",
      angleKey: "afternoonPeak",
      showInLegend: false,
    },
  ],
};

ModuleRegistry.registerModules([
  AnimationModule,
  AreaSeriesModule,
  BarSeriesModule,
  CategoryAxisModule,
  CrosshairModule,
  DonutSeriesModule,
  LegendModule,
  LineSeriesModule,
  NumberAxisModule,
  PieSeriesModule,
  ContextMenuModule,
]);

const ChartExample = defineComponent({
  template: `
    <div class="example-controls">
      <div class="controls-row">
        <div class="button-group gap-right" role="group" aria-label="Series Type">
          <input type="radio" id="series-bar" name="series-type" value="bar" checked="" v-on:change="seriesTypeChange($event)">
            <label for="series-bar">Bar</label>
            <input type="radio" id="series-line" name="series-type" value="line" v-on:change="seriesTypeChange($event)">
              <label for="series-line">Line</label>
              <input type="radio" id="series-area" name="series-type" value="area" v-on:change="seriesTypeChange($event)">
                <label for="series-area">Area</label>
                <input type="radio" id="series-donut" name="series-type" value="donut" v-on:change="seriesTypeChange($event)">
                  <label for="series-donut">Pie &amp; Donut</label>
                </div>
                <div class="button-group" role="group" aria-label="Animation Duration">
                  <input type="radio" id="duration-500" name="animation-duration" value="500" checked="" v-on:change="durationChange($event)">
                    <label for="duration-500">Duration: 500ms</label>
                    <input type="radio" id="duration-2000" name="animation-duration" value="2000" v-on:change="durationChange($event)">
                      <label for="duration-2000">Duration: 2000ms</label>
                    </div>
                  </div>
                </div>
                <ag-charts
                  :options="options"
                />
  `,
  components: {
    "ag-charts": AgCharts,
  },
  setup(props) {
    const options = ref<
      AgCartesianChartOptions<DataType> | AgPolarChartOptions<DataType>
    >({
      data: getData(),
      animation: {
        enabled: true,
        duration: 500,
      },
      ...barOptions,
    });

    const seriesTypeChange = (event) => {
      const optionsCopy = clone(options.value);

      const value = event.target.value;
      switch (value) {
        case "bar":
          optionsCopy.series = barOptions.series;
          optionsCopy.axes = barOptions.axes;
          break;
        case "line":
          optionsCopy.series = lineOptions.series;
          optionsCopy.axes = lineOptions.axes;
          break;
        case "area":
          optionsCopy.series = areaOptions.series;
          optionsCopy.axes = areaOptions.axes;
          break;
        case "donut":
          optionsCopy.series = donutOptions.series;
          optionsCopy.axes = donutOptions.axes;
          break;
      }

      options.value = optionsCopy;
    };
    const durationChange = (event) => {
      const optionsCopy = clone(options.value);

      const duration = Number(event.target.value);
      optionsCopy.animation = { enabled: true, duration };

      options.value = optionsCopy;
    };

    return {
      options,
      seriesTypeChange,
      durationChange,
    };
  },
});

createApp(ChartExample).mount("#app");
```

[Live example: Duration](https://www.ag-grid.com/charts/archive/14.2.0/vue3/animation/examples/duration/)

To highlight data changes with a flash effect, see [Flash On Update](https://www.ag-grid.com/charts/archive/14.2.0/vue/flash-on-update/).

## API Reference

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| enabled | boolean |  | Set to `true` to enable the animation module. Defaults to `false` when `flashOnUpdate.enabled` is `true`. |
| duration | DurationMs |  | The total duration of the animation on initial load and updates. |
