Initial Load Copy Link
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.
import { Component } from "@angular/core";
import { AgCharts } from "ag-charts-angular";
import {
AgCartesianChartOptions,
AgCartesianSeriesTooltipRendererParams,
AgChartOptions,
AgPolarChartOptions,
AgTooltipRendererResult,
AnimationModule,
AreaSeriesModule,
BarSeriesModule,
CategoryAxisModule,
ContextMenuModule,
CrosshairModule,
DonutSeriesModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
PieSeriesModule,
} from "ag-charts-enterprise";
import { DataType, getData } from "./data";
import clone from "clone";
const numFormatter = new Intl.NumberFormat("en-US");
const tooltip = {
renderer: ({
datum,
yKey,
yName,
}: AgCartesianSeriesTooltipRendererParams<DataType>): AgTooltipRendererResult => {
return {
data: [
{ label: yName!, value: numFormatter.format(Number(datum[yKey])) },
],
};
},
};
const barOptions: AgCartesianChartOptions<DataType> = {
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: AgCartesianChartOptions<DataType> = {
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: AgCartesianChartOptions<DataType> = {
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: AgPolarChartOptions<DataType> = {
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,
]);
@Component({
selector: "my-app",
standalone: true,
imports: [AgCharts],
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="" (change)="seriesTypeChange($event)">
<label for="series-bar">Bar</label>
<input type="radio" id="series-line" name="series-type" value="line" (change)="seriesTypeChange($event)">
<label for="series-line">Line</label>
<input type="radio" id="series-area" name="series-type" value="area" (change)="seriesTypeChange($event)">
<label for="series-area">Area</label>
<input type="radio" id="series-donut" name="series-type" value="donut" (change)="seriesTypeChange($event)">
<label for="series-donut">Pie & Donut</label>
</div>
</div>
</div>
<ag-charts
[options]="options"
></ag-charts>
`,
})
export class AppComponent {
public options;
constructor() {
this.options = {
data: getData(),
animation: {
enabled: true,
},
...barOptions,
};
}
seriesTypeChange = (event: Event) => {
const options = clone(this.options);
const value = (event.target as HTMLInputElement).value;
const seriesOptions = {
bar: barOptions,
line: lineOptions,
area: areaOptions,
donut: donutOptions,
}[value]!;
options.series = seriesOptions.series;
options.axes = seriesOptions.axes;
this.options = options;
};
}
Data Updates Copy Link
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:
import { Component } from "@angular/core";
import { AgCharts } from "ag-charts-angular";
import {
AgCartesianChartOptions,
AgChartOptions,
AgPolarChartOptions,
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: AgCartesianChartOptions = {
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: AgCartesianChartOptions = {
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: AgCartesianChartOptions = {
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: AgPolarChartOptions = {
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,
]);
@Component({
selector: "my-app",
standalone: true,
imports: [AgCharts],
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="" (change)="seriesTypeChange($event)">
<label for="series-bar">Bar</label>
<input type="radio" id="series-line" name="series-type" value="line" (change)="seriesTypeChange($event)">
<label for="series-line">Line</label>
<input type="radio" id="series-area" name="series-type" value="area" (change)="seriesTypeChange($event)">
<label for="series-area">Area</label>
<input type="radio" id="series-donut" name="series-type" value="donut" (change)="seriesTypeChange($event)">
<label for="series-donut">Pie & Donut</label>
</div>
<button class="animation-data-updates__action" (click)="add()">Add</button>
<button class="animation-data-updates__action" (click)="remove()">Remove</button>
<button class="animation-data-updates__action gap-right" (click)="update()">Update</button>
<button class="animation-data-updates__action" (click)="addRemoveUpdate()">Add & Remove & Update</button>
</div>
</div>
<ag-charts
[options]="options"
></ag-charts>
`,
})
export class AppComponent {
public options;
constructor() {
this.options = {
animation: {
enabled: true,
},
data: getGeneratedData(),
...barOptions,
};
}
seriesTypeChange = (event: Event) => {
const options = clone(this.options);
const seriesType = (event.target as HTMLInputElement).value as
| "bar"
| "line"
| "area"
| "donut";
offset = 0;
seed = 1234;
switch (seriesType) {
case "bar":
variance = 20;
length = 8;
options.series = barOptions.series;
options.axes = barOptions.axes;
break;
case "line":
variance = 4;
length = 30;
options.series = lineOptions.series;
options.axes = lineOptions.axes;
break;
case "area":
variance = 20;
length = 30;
options.series = areaOptions.series;
options.axes = areaOptions.axes;
break;
case "donut":
variance = 30;
length = 6;
options.series = donutOptions.series;
options.axes = donutOptions.axes;
break;
}
options.data = getGeneratedData();
this.options = options;
};
add = () => {
const options = clone(this.options);
offset++;
length++;
options.data = getGeneratedData();
this.options = options;
};
remove = () => {
const options = clone(this.options);
if (options.series?.[0].type === "pie") offset--;
length = Math.max(0, length - 1);
options.data = getGeneratedData();
this.options = options;
};
update = () => {
const options = clone(this.options);
seed = Math.floor(random() * 1000);
options.data = getGeneratedData();
this.options = options;
};
addRemoveUpdate = () => {
const options = clone(this.options);
if (options.series?.[0].type === "pie") offset--;
if (options.series?.[0].type !== "pie") offset++;
seed = Math.floor(random() * 1000);
options.data = getGeneratedData();
this.options = options;
};
}
Duration Copy Link
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.
{
animation: {
duration: 500,
},
}In this example, click a duration then change the series type to see the initial load animation.
import { Component } from "@angular/core";
import { AgCharts } from "ag-charts-angular";
import {
AgCartesianChartOptions,
AgCartesianSeriesTooltipRendererParams,
AgChartOptions,
AgPolarChartOptions,
AgTooltipRendererResult,
AnimationModule,
AreaSeriesModule,
BarSeriesModule,
CategoryAxisModule,
ContextMenuModule,
CrosshairModule,
DonutSeriesModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
PieSeriesModule,
} from "ag-charts-enterprise";
import { DataType, getData } from "./data";
import clone from "clone";
const numFormatter = new Intl.NumberFormat("en-US");
const tooltip = {
renderer: ({
datum,
yKey,
yName,
}: AgCartesianSeriesTooltipRendererParams<DataType>): AgTooltipRendererResult => {
return {
data: [
{ label: yName!, value: numFormatter.format(Number(datum[yKey])) },
],
};
},
};
const barOptions: AgCartesianChartOptions<DataType> = {
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: AgCartesianChartOptions<DataType> = {
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: AgCartesianChartOptions<DataType> = {
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: AgPolarChartOptions<DataType> = {
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,
]);
@Component({
selector: "my-app",
standalone: true,
imports: [AgCharts],
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="" (change)="seriesTypeChange($event)">
<label for="series-bar">Bar</label>
<input type="radio" id="series-line" name="series-type" value="line" (change)="seriesTypeChange($event)">
<label for="series-line">Line</label>
<input type="radio" id="series-area" name="series-type" value="area" (change)="seriesTypeChange($event)">
<label for="series-area">Area</label>
<input type="radio" id="series-donut" name="series-type" value="donut" (change)="seriesTypeChange($event)">
<label for="series-donut">Pie & 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="" (change)="durationChange($event)">
<label for="duration-500">Duration: 500ms</label>
<input type="radio" id="duration-2000" name="animation-duration" value="2000" (change)="durationChange($event)">
<label for="duration-2000">Duration: 2000ms</label>
</div>
</div>
</div>
<ag-charts
[options]="options"
></ag-charts>
`,
})
export class AppComponent {
public options;
constructor() {
this.options = {
data: getData(),
animation: {
enabled: true,
duration: 500,
},
...barOptions,
};
}
seriesTypeChange = (event: Event) => {
const options = clone(this.options);
const value = (event.target as HTMLInputElement).value;
switch (value) {
case "bar":
options.series = barOptions.series;
options.axes = barOptions.axes;
break;
case "line":
options.series = lineOptions.series;
options.axes = lineOptions.axes;
break;
case "area":
options.series = areaOptions.series;
options.axes = areaOptions.axes;
break;
case "donut":
options.series = donutOptions.series;
options.axes = donutOptions.axes;
break;
}
this.options = options;
};
durationChange = (event: Event) => {
const options = clone(this.options);
const duration = Number((event.target as HTMLInputElement).value);
options.animation = { enabled: true, duration };
this.options = options;
};
}
To highlight data changes with a flash effect, see Flash On Update.
API Reference Copy Link
Properties available on the AgAnimationOptions interface.
- 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.
Properties available on the AgAnimationOptions interface.
- 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.