自定义 Animate
动画注册机制
使用动画注册机制以达到动画函数的复用。使用方式如下:
// 加载动画注册类
const Animate = require('@antv/f2/lib/animation/animate');
/**
* @param {String} animationName 动画名称,用户自定义即可
* @param {Function} animationFun 动画执行函数
**/
Animate.registerAnimation('animationName', animationFun); // 注册名为 animationName 的动画函数
// 使用上述注册的函数
chart.line().animate({
appear: {
animation: 'animationName' // 对应上述注册的动画函数名
}
})
自定义动画详解
F2 提供了完善的动画自定义机制,用户可对任意支持动画的图形元素定制不同状态下的动画行为,这里所说的状态即为 appear enter leave update 这四种动画类型。
在 F2 中执行的都是 Shape(图形) 元素的动画,通过逐帧改变 shape 对象的图形属性来达到动画的效果,以下面圆的移动动画为例:
这个动画的实现非常简单,由于动画的最终效果是将圆移至 B 点(画布坐标为 { x: 230, y: 50 }
),那么我们只需要通过调用 shape.animate()
方法指定 shape 的最终状态(图形属性)即可:
// circle 初始画布位置为 x: 100, y: 100
circle.animate().to({
attrs: {
x: 230, // 最终的 x 坐标
y: 50 // 最终的 y 坐标
}, // 指定最终的图形属性
easing: 'linear', // 指定动画的缓动效果
duration: 1500 // 指定动画的执行时间
})
各类型 shape 的图形属性说明见 graphic 图形 api。
F2 会为用户自定义的动画函数传递三个参数,按照顺序,分别为 shape
、animateCfg
、coord
chart.line().animate({
appear: {
animation: (shape, animateCfg, coord) => {}
}
})
shape
,shape 对象,当前执行动画的主体
通过操作该 shape 对象的图形属性,即可进行动画的个性化定制。
shape 对象具体提供了以下属性来帮助用户进行操作:
属性名 | 获取方式 | 类型 | 解释 |
---|---|---|---|
attrs | shape.get('attrs') | Object | 获取 shape 全部的图形属性 |
className | shape.get('className') | String | 获取当前 shape 的图形元素类型 |
origin | shape.get('origin') | Object | 获取当前 shape 的绘制数据以及对应的原始数据记录 |
index | shape.get('index') | Number | 获取当前 shape 的索引值,即顺序 |
另外图形属性的获取还可以通过调用 shape.attr(name)
方法来获取,更多 shape 对象的方法请阅读 Shape API。
另外对于处理 update
更新状态下的 shape 对象,我们还会提供一个 cacheShape
属性,该属性为一个 Object 对象,存储的是当前 shape 在上一个状态(数据变更前)的内容,以便于用户进行变更动画的定制,该属性包含的内容如下:
{
animateCfg: {}, // 动画效果配置
attrs: {}, // 上一个状态的图形属性
className: "", // 图形元素名称
}
animateCfg
,Object 类型,动画的配置
该对象包含的内容如下:
{
easing: , // 缓动函数配合
duration: , // 动画执行时间
delay: // 动画延迟时间
}
coord
,Coord 坐标系对象,表示当前 chart 的坐标系,该对象包含的属性详见 Coordinate API
示例
下面的示例对柱状图的初始化出场动画(appear)进行了自定义:
const { Chart, Animate, Util, G } = F2;
// 注册函数名为 delayScaleInY 的自定义动画,实现柱子 y 轴方向的放大效果
Animate.registerAnimation('delayScaleInY', function(shape, animateCfg) {
const box = shape.getBBox(); // 获取图形的包围盒
const origin = shape.get('origin'); // 获取当前 shape 的绘制数据
const points = origin.points; // 获取柱子的各个顶点
const centerX = (box.minX + box.maxX) / 2;
let centerY;
if (points[0].y - points[1].y <= 0) { // 当顶点在零点之下
centerY = box.maxY;
} else {
centerY = box.minY;
}
shape.transform([
[ 't', centerX, centerY ],
[ 's', 1, 0.1 ],
[ 't', -centerX, -centerY ]
]); // 进行矩阵变换,将 shape 的原始状态改变,y 方向缩小至 0.1 倍
const index = shape.get('index');
let delay = animateCfg.delay; // 获取动画配置
if (Util.isFunction(delay)) {
delay = animateCfg.delay(index); // 根据 shape 的索引设置不同的延迟时间
}
const easing = animateCfg.easing; // 获取动画配置
const matrix = shape.getMatrix(); // 获取当前矩阵
const endMatrix = G.Matrix.transform(matrix, [
[ 't', centerX, centerY ],
[ 's', 1, 10 ],
[ 't', -centerX, -centerY ]
]); // shape 最终状态下的矩阵
shape.animate().to({
attrs: {
matrix: endMatrix
},
delay,
easing,
duration: animateCfg.duration
}); // 执行动画
});
const data = [];
for (let i = 0; i < 50; i++) {
data.push({
x: i,
y: (Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5
});
}
const chart = new Chart({
id: 'mountNode',
width: 375,
height: 200,
pixelRatio: window.devicePixelRatio
});
chart.axis('x', false);
chart.legend(false);
chart.source(data);
chart.interval()
.position('x*y')
.color('y', '#4a657a-#308e92-#b1cfa5-#f5d69f-#f5898b-#ef5055')
.animate({ // 进行自定义的动画配置
appear: {
animation: 'delayScaleInY', // 使用上面注册过的动画 delayScaleInY,当然也可以使用回调函数
easing: 'elasticOut', // 定义缓动函数
delay(index) {
return index * 10;
} // 根据索引值为各个 shape 设置不同的动画延迟执行时间
}
});
chart.render();