How to Customize Animations and Transitions in ECharts: A Complete Developer Guide
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, src/util/types.ts, and the animation utility modules.
Global Animation Defaults
Default animation behavior is defined in src/model/globalDefault.ts and automatically merged into every chart instance unless overridden. These settings control the baseline timing and easing for all series.
// 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():
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 (lines 1018-1056) defines the available properties:
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 (lines 525-536) implements the threshold logic that disables animation when data counts exceed the limit:
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:
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 (lines 20-55). This helper batches multiple element animations with a single completion callback.
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.
The system performs three key operations:
- Data diffing via
flattenDataDiffItems(lines 18-44) matches old and new data items usinggroupIdorchildGroupId - Morph animation via
applyMorphAnimation(line 25) creates path interpolation between shapes - Performance guarding disables the feature when data exceeds 10,000 items (
DATA_COUNT_THRESHOLDat lines 25-31)
Enable Universal Transition by maintaining consistent series IDs across setOption calls:
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:
// 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.tsset baseline animation timing viaecharts.init()options - Series-level control through
AnimationOptionMixinallows dynamic durations, delays, and thresholds to disable animation for large datasets - Element-level utilities like
createWrap()insrc/util/animation.tsprovide imperative control over ZRender graphic objects - Universal Transition in
src/animation/universalTransition.tsenables cross-series morphing by matching data items via series ID and morphing paths throughapplyMorphAnimation
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, 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 (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 (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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →