# How to Customize Animations and Transitions in ECharts: A Complete Developer Guide

> Unlock ECharts animation customization. Learn to control global defaults, series animations, and ZRender utilities for dynamic transitions and shape morphing in this developer guide.

- Repository: [The Apache Software Foundation/echarts](https://github.com/apache/echarts)
- Tags: how-to-guide
- Published: 2026-03-04

---

**You can customize animations in ECharts through three configuration layers: global defaults set during `echarts.init()`, series-level options with callback functions for dynamic timing, and low-level ZRender utilities like `createWrap()` and Universal Transition for shape morphing between chart types.**

The Apache ECharts library builds its animation system on top of ZRender, providing granular control over how visual elements enter, update, and transition. Whether you need staggered entrance effects, data-driven duration calculations, or seamless morphing between a bar chart and a pie chart, the source code in `apache/echarts` exposes a three-tier configuration API. This guide explains how to customize animations and transitions in ECharts using the actual implementation details found in [`src/model/globalDefault.ts`](https://github.com/apache/echarts/blob/main/src/model/globalDefault.ts), [`src/util/types.ts`](https://github.com/apache/echarts/blob/main/src/util/types.ts), and the animation utility modules.

## Global Animation Defaults

Default animation behavior is defined in [`src/model/globalDefault.ts`](https://github.com/apache/echarts/blob/main/src/model/globalDefault.ts) and automatically merged into every chart instance unless overridden. These settings control the baseline timing and easing for all series.

```typescript
// src/model/globalDefault.ts (lines 108-114)
export default {
    animation: 'auto',
    animationDuration: 1000,
    animationDurationUpdate: 500,
    animationEasing: 'cubicInOut',
    animationEasingUpdate: 'cubicInOut',
    animationThreshold: 2000,
    // …
};

```

Override these values globally by passing an options object as the third argument to `echarts.init()`:

```javascript
const chart = echarts.init(dom, null, {
  animationDuration: 800,
  animationEasing: 'elasticOut'
});

```

## Series-Level Animation Options

Each series can independently enable or disable animation, set data-size thresholds, and supply callback functions for dynamic durations or delays. The `AnimationOptionMixin` interface in [`src/util/types.ts`](https://github.com/apache/echarts/blob/main/src/util/types.ts) (lines 1018-1056) defines the available properties:

```typescript
export interface AnimationOptionMixin {
    animation?: boolean;
    animationThreshold?: number;
    animationDuration?: number | AnimationDurationCallback;
    animationEasing?: AnimationEasing;
    animationDelay?: number | AnimationDelayCallback;
    animationDurationUpdate?: number | AnimationDurationCallback;
    animationEasingUpdate?: AnimationEasing;
    animationDelayUpdate?: number | AnimationDelayCallback;
}

```

The `Series` model in [`src/model/Series.ts`](https://github.com/apache/echarts/blob/main/src/model/Series.ts) (lines 525-536) implements the threshold logic that disables animation when data counts exceed the limit:

```typescript
let animationEnabled = this.getShallow('animation');
if (animationEnabled && this.getData().count() > this.getShallow('animationThreshold')) {
  animationEnabled = false;
}
return !!animationEnabled;

```

Practical usage combines boolean flags with callback functions to create staggered or data-driven effects:

```javascript
option = {
  series: [{
    type: 'bar',
    data: [12, 19, 3, 5, 2, 3],
    animation: true,
    animationThreshold: 1000,
    animationDuration: idx => idx * 100 + 500,  // Staggered duration
    animationDelay: idx => Math.random() * 200, // Random wave effect
    animationEasingUpdate: 'bounceOut'
  }]
};

```

## Element-Level Animation Control

For direct manipulation of ZRender graphic elements, ECharts provides the `createWrap()` utility in [`src/util/animation.ts`](https://github.com/apache/echarts/blob/main/src/util/animation.ts) (lines 20-55). This helper batches multiple element animations with a single completion callback.

```javascript
import { createWrap } from 'echarts/lib/util/animation';

const wrap = createWrap();
wrap.add(el1, { x: 100, y: 0 }, 800, 0, 'cubicOut')
    .add(el2, { x: 0, y: 150 }, 600, 200, 'elasticIn')
    .finished(() => console.log('All animations complete'))
    .start();

```

This low-level approach bypasses the declarative series configuration and targets the underlying `Displayable` or `Path` objects directly.

## Universal Transition for Cross-Series Morphing

ECharts 5 introduced Universal Transition, enabling smooth morphing between any two series types (e.g., line to pie) while preserving element identity. The core algorithm lives in [`src/animation/universalTransition.ts`](https://github.com/apache/echarts/blob/main/src/animation/universalTransition.ts).

The system performs three key operations:

1. **Data diffing** via `flattenDataDiffItems` (lines 18-44) matches old and new data items using `groupId` or `childGroupId`
2. **Morph animation** via `applyMorphAnimation` (line 25) creates path interpolation between shapes
3. **Performance guarding** disables the feature when data exceeds 10,000 items (`DATA_COUNT_THRESHOLD` at lines 25-31)

Enable Universal Transition by maintaining consistent series IDs across `setOption` calls:

```javascript
option = {
  series: [
    {
      type: 'bar',
      id: 'mySeries',
      data: [12, 19, 3, 5]
    }
  ],
  universalTransition: {
    enabled: true,
    divideShape: 'clone'
  }
};

// Later update to pie chart triggers morphing
chart.setOption({
  series: [{
    type: 'pie',
    id: 'mySeries',  // Same ID enables transition
    data: [20, 40, 30]
  }]
});

```

## Complete Working Example

This example demonstrates all three animation layers: global defaults, series callbacks, and Universal Transition:

```javascript
// 1. Initialize with custom global animation settings
const chart = echarts.init(document.getElementById('main'), null, {
  animationDuration: 1200,
  animationEasing: 'quadraticOut'
});

// 2. Define series with per-datum animation callbacks
chart.setOption({
  series: [{
    type: 'bar',
    id: 'sales',
    data: [120, 200, 150, 80, 70, 110, 130],
    animationDuration: idx => 400 + idx * 80,
    animationDelay: idx => idx * 100,
    animationEasingUpdate: 'elasticOut'
  }]
});

// 3. Trigger Universal Transition to line chart after 3 seconds
setTimeout(() => {
  chart.setOption({
    series: [{
      type: 'line',
      id: 'sales',
      data: [100, 180, 130, 90, 60, 120, 140],
      animationDurationUpdate: 800,
      animationEasingUpdate: 'cubicInOut'
    }],
    universalTransition: { enabled: true }
  });
}, 3000);

```

The initial render animates each bar with a staggered delay based on data index. After three seconds, the chart morphs the bar rectangles into line points while preserving the visual continuity through shape interpolation.

## Summary

- **Global defaults** in [`src/model/globalDefault.ts`](https://github.com/apache/echarts/blob/main/src/model/globalDefault.ts) set baseline animation timing via `echarts.init()` options
- **Series-level control** through `AnimationOptionMixin` allows dynamic durations, delays, and thresholds to disable animation for large datasets
- **Element-level utilities** like `createWrap()` in [`src/util/animation.ts`](https://github.com/apache/echarts/blob/main/src/util/animation.ts) provide imperative control over ZRender graphic objects
- **Universal Transition** in [`src/animation/universalTransition.ts`](https://github.com/apache/echarts/blob/main/src/animation/universalTransition.ts) enables cross-series morphing by matching data items via series ID and morphing paths through `applyMorphAnimation`

## Frequently Asked Questions

### How do I completely disable animations in ECharts?

Set the `animation` property to `false` either globally during initialization or per-series. In [`src/model/Series.ts`](https://github.com/apache/echarts/blob/main/src/model/Series.ts), the framework checks `this.getShallow('animation')` and returns false to disable all tweening for that series. For global disablement, pass `{ animation: false }` as the third argument to `echarts.init()`.

### What is the purpose of the `animationThreshold` option?

The `animationThreshold` guards performance by automatically disabling animation when the data count exceeds the specified number. According to [`src/model/Series.ts`](https://github.com/apache/echarts/blob/main/src/model/Series.ts) (lines 525-536), when `getData().count()` exceeds the threshold, the `animationEnabled` flag is forced to false. The default threshold is 2000 for standard animations and 10000 for Universal Transition.

### How does Universal Transition match elements between different chart types?

Universal Transition uses a data diffing algorithm in [`src/animation/universalTransition.ts`](https://github.com/apache/echarts/blob/main/src/animation/universalTransition.ts) (lines 18-44) that flattens old and new series data into comparable items. It matches elements using `groupId` or `childGroupId` properties, then applies morphing via `applyMorphAnimation` to interpolate between the source shape (e.g., a bar rectangle) and target shape (e.g., a pie sector).

### Can I animate individual graphic elements independently of series data?

Yes. Import `createWrap` from [`src/util/animation.ts`](https://github.com/apache/echarts/blob/main/src/util/animation.ts) to batch animations for individual ZRender elements such as `Path` or `Displayable` objects. This utility accepts target properties, duration, delay, and easing parameters, allowing you to animate graphic elements added via the `graphic` component or custom renderers outside of standard series updates.