数据过渡
Apache EChartsTM 在添加、更新和移除数据时,会对位置、缩放、形状应用过渡动画。这使得图表更平滑,能更好地展示数据之间的关系。开发者通常不需要担心如何使用动画,只需使用 setOption 更新数据,ECharts 就会找出新旧数据之间的差异,并自动应用最合适的过渡动画。
例如,下面的示例展示了饼图数据定时更新时的过渡效果。
function makeRandomData() { return [ { value: Math.random(), name: 'A' }, { value: Math.random(), name: 'B' }, { value: Math.random(), name: 'C' } ]; } option = { series: [ { type: 'pie', radius: [0, '50%'], data: makeRandomData() } ] }; setInterval(() => { myChart.setOption({ series: { data: makeRandomData() } }); }, 2000);
过渡动画的配置
由于添加和更新数据通常需要不同的动画效果(例如,我们希望数据更新动画更短),ECharts 区分了这两种动画配置。
- 对于添加数据,我们会应用“入场”动画,使用
animationDuration、animationEasing和animationDelay分别配置动画的时长、缓动效果和延迟。 - 对于更新数据,我们会应用“更新”动画,使用
animationDurationUpdate、animationEasingUpdate和animationDelayUpdate分别配置动画的时长、缓动效果和延迟。
如你所见,更新动画的配置项就是在入场动画配置项后加上 Update 后缀。
每次在 ECharts 中使用 setOption 时,数据都会与上次更新的数据进行差分(diff),并根据差分结果对数据执行三种状态的操作:添加、更新和移除。这种差分是基于数据的
name进行的。例如,如果上次更新有三个name为'A'、'B'、'C'的数据,而新更新变成了'B'、'C'、'D',那么数据'B'、'C'将被更新,数据'A'将被移除,数据'D'将被添加。如果是第一次执行setOption,因为没有旧数据,所有数据都将被添加。根据这三种状态,ECharts 将分别应用入场动画、更新动画和离场动画。
所有这些配置都可以在 option 的顶层为所有系列和组件进行设置,也可以为每个系列单独设置。
如果我们想关闭动画,只需将 option.animation 设置为 false。
动画时长
animationDuration 和 animationDurationUpdate 用于设置动画时长,单位为 ms(毫秒)。设置较长的动画时长可以让用户更清晰地看到过渡动画的效果,但我们也需要注意,过长的时间可能会让用户在等待动画完成时失去耐心。
设置为 0 将关闭动画。当我们只想单独关闭入场动画或更新动画时,可以通过将对应的配置项单独设置为 0 来实现。
动画缓动
animationEasing 和 animationEasingUpdate 配置项用于设置动画的缓动函数,这是一个输入动画时间并输出动画进度的函数。
(t: number) => number;常见的动画缓动函数(如 'cubicIn' 和 'cubicOut')已内置在 ECharts 中,可以直接使用。
内置缓动函数。
动画延迟
animationDelay 和 animationDelayUpdate 用于设置动画延迟开始的时间。通常我们会使用回调函数为不同的数据设置不同的延迟,以达到交错动画的效果。
var xAxisData = []; var data1 = []; var data2 = []; for (var i = 0; i < 100; i++) { xAxisData.push('A' + i); data1.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5); data2.push((Math.cos(i / 5) * (i / 5 - 10) + i / 6) * 5); } option = { legend: { data: ['bar', 'bar2'] }, xAxis: { data: xAxisData, splitLine: { show: false } }, yAxis: {}, series: [ { name: 'bar', type: 'bar', data: data1, emphasis: { focus: 'series' }, animationDelay: function(idx) { return idx * 10; } }, { name: 'bar2', type: 'bar', data: data2, emphasis: { focus: 'series' }, animationDelay: function(idx) { return idx * 10 + 100; } } ], animationEasing: 'elasticOut', animationDelayUpdate: function(idx) { return idx * 5; } };
动画的性能优化
当数据量特别大时,运行动画可能会出现性能问题,因此我们可以设置 animation: false 来关闭动画。
对于数据量动态变化的图表,我们建议使用 animationThreshold 配置项。当画布中的图形数量超过此阈值时,它允许 ECharts 自动关闭动画以提高绘制性能。这通常是一个经验值,ECharts 通常能够实时渲染数千个图形(我们的默认值也设为 2000),但如果你的图表很复杂,或者用户环境较差,并且页面上同时运行着大量其他复杂代码,那么适当调低这个值以确保整个应用的流畅度可能是合适的。
监听动画结束
有时我们想获取当前的渲染结果。如果不使用动画,ECharts 会在 setOption 后直接执行渲染,我们可以使用 getDataURL 方法同步获取渲染结果。
const chart = echarts.init(dom);
chart.setOption({
animation: false
//...
});
// can be executed directly and synchronously
const dataUrl = chart.getDataURL();但如果图表是有动画的,立即执行 getDataURL 得到的是动画开始时的图片,而不是最终结果。因此,我们需要知道动画何时结束,然后再执行 getDataURL 以获取结果。
如果你确定动画的时长,一个简单粗暴的方法是根据动画时长使用 setTimeout 延迟执行。
chart.setOption({
animationDuration: 1000
//...
});
setTimeout(() => {
const dataUrl = chart.getDataURL();
}, 1000);或者,我们可以使用 ECharts 提供的 rendered 事件来判断 ECharts 是否已完成动画并停止渲染。
chart.setOption({
animationDuration: 1000
//...
});
function onRendered() {
const dataUrl = chart.getDataURL();
// ...
// This event will also be triggered if there is a subsequent interaction and the interaction is redrawn, so it needs to be removed when you're done using it
chart.off('rendered', onRendered);
}
chart.on('rendered', onRendered);