在 G2 内部,我们默认为一些场景内置了动画,包括入场、更新、出场动画等。同时,我们还提供了自定义动画的机制,以满足更广泛的需求,让用户能更系统、更全面的控制 G2 的动画。

  • 动画注册 Animate.registAnimation()
  1. const { Animate } = G2;
  2. /**
  3. * @param {String} animationType 动画场景类型 appear enter leave update
  4. * @param {String} 动画名称,用户自定义即可
  5. * @param {Function} 动画执行函数
  6. **/
  7. Animate.registerAnimation(animationType, animationName, animationFun);
  • 动画配置 geom.animate()
  1. chart.interval().position('x*y').animate({
  2. enter:{
  3. animation: 'fadeIn', // 动画名称
  4. easing: 'easeQuartIn', // 动画缓动效果
  5. delay: 100, // 动画延迟执行时间
  6. duration: 600 // 动画执行时间
  7. }
  8. });

在 G2 中,我们提供了四种动画场景类型:

  • appear: 初始化时的入场动画;

  • enter: 更新时的出现动画;

  • update: 更新时的变化动画;

  • leave: 更新时的动画;

上述方法更详细的使用说明详见: G2 Animate API

1 分钟上手自定义动画

以柱状图为例:

自定义动画 - 图1

  1. const Animate = G2.Animate;
  2. Animate.registerAnimation('appear', 'delayScaleInY', function(shape, animateCfg) {
  3. const box = shape.getBBox(); // 获取柱子包围盒
  4. const origin = shape.get('origin'); // 获取柱子原始数据
  5. const points = origin.points; // 获取柱子顶点
  6. // 计算柱子的变换中点
  7. const centerX = (box.minX + box.maxX) / 2;
  8. let centerY;
  9. if (points[0].y - points[1].y <= 0) { // 当顶点在零点之下
  10. centerY = box.maxY;
  11. } else {
  12. centerY = box.minY;
  13. }
  14. // 设置初始态
  15. shape.attr('transform', [
  16. ['t', -centerX, -centerY],
  17. ['s', 1, 0.1],
  18. ['t', centerX, centerY]
  19. ]);
  20. const index = shape.get('index');
  21. let delay = animateCfg.delay;
  22. if (G2.Util.isFunction(delay)) {
  23. delay = animateCfg.delay(index);
  24. }
  25. let easing = animateCfg.easing;
  26. if (G2.Util.isFunction(easing)) {
  27. easing = animateCfg.easing(index);
  28. }
  29. // 设置动画目标态
  30. shape.animate({
  31. transform: [
  32. ['t', -centerX, -centerY],
  33. ['s', 1, 10],
  34. ['t', centerX, centerY]
  35. ]
  36. }, animateCfg.duration, easing, animateCfg.callback, delay);
  37. });
  38. const data = [];
  39. for (let i = 0; i < 50; i++) {
  40. data.push({
  41. x: i,
  42. y: (Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5
  43. });
  44. }
  45. const chart = new G2.Chart({
  46. container: 'c1',
  47. forceFit: true,
  48. height: 400
  49. });
  50. chart.axis('x', false);
  51. chart.legend(false);
  52. chart.source(data);
  53. chart.interval()
  54. .position('x*y')
  55. .color('y', '#4a657a-#308e92-#b1cfa5-#f5d69f-#f5898b-#ef5055')
  56. .animate({
  57. appear: {
  58. animation: 'delayScaleInY',
  59. easing: 'easeElasticOut',
  60. delay: index => {
  61. return index * 10;
  62. }
  63. }
  64. });
  65. chart.render();
  66. $('button#refresh').click(ev => {
  67. chart.clear();
  68. chart.interval()
  69. .position('x*y')
  70. .color('y', '#4a657a-#308e92-#b1cfa5-#f5d69f-#f5898b-#ef5055')
  71. .animate({
  72. appear: {
  73. animation: 'delayScaleInY',
  74. easing: 'easeElasticOut',
  75. delay: index => {
  76. return index * 10;
  77. }
  78. }
  79. });
  80. chart.render();
  81. });

第一步:获取 Animate 对象

  1. const Animate = G2.Animate;

第二步:自定义动画(核心)

自定义动画的核心在于:

  • 设置图形的初始状态

  • 确定图形的结束状态

  • 调用动画函数

这里以定义一个柱状图的动画示例:

  1. 首先获取每根柱子的包围盒。包围盒的意思是能包围图形的最小矩形,所以包围盒含有 minX、minY、maxX、maxY 四个属性,这四个参数限定的区间即为图形的包围盒。

  2. 计算变换中点。当顶点在零点之上时,延 Y 轴正向放大,所以变换的中点在包围盒底部中间;当顶点在零点之下时,延 Y 轴反向放大。所以变换的中点在包围盒顶部中间。

  3. 设置动画初始状态。要实现柱子的放大,需要先将柱子缩到最小。为 shape 设置 transform 属性,先将坐标系的原点移到变换中点,然后将柱子的 y 值缩小到 0.1 倍,最后将坐标系的原点移到原处。

  4. 实现延迟放大效果的动画。调用 shape 的 animate() 方法,传入变换的结束状态、动画时间和缓动函数。结束状态中可以配置延迟参数 delay ,给每个 shape 的动画添加一个跟序号成正比的延迟,即可实现依次放大的效果。

  1. // shape 是柱子对象,animateCfg 是动画配置
  2. const animateFun = function(shape, animateCfg) {
  3. const box = shape.getBBox(); // 获取柱子包围盒
  4. const origin = shape.get('origin'); // 获取柱子原始数据
  5. const points = origin.points; // 获取柱子顶点
  6. // 计算柱子的变换中点
  7. const centerX = (box.minX + box.maxX) / 2;
  8. let centerY;
  9. if (points[0].y - points[1].y <= 0) { // 当顶点在零点之下
  10. centerY = box.maxY;
  11. } else {
  12. centerY = box.minY;
  13. }
  14. // 设置初始态
  15. shape.attr('transform', [
  16. [ 't', -centerX, -centerY ],
  17. [ 's', 1, 0.1 ],
  18. [ 't', centerX, centerY ]
  19. ]);
  20. const index = shape.get('index');
  21. let delay = animateCfg.delay;
  22. if (G2.Util.isFunction(delay)) {
  23. delay = animateCfg.delay(index);
  24. }
  25. let easing = animateCfg.easing;
  26. if (G2.Util.isFunction(easing)) {
  27. easing = animateCfg.easing(index);
  28. }
  29. // 设置动画目标态
  30. shape.animate({
  31. transform: [
  32. [ 't', -centerX, -centerY ],
  33. [ 's', 1, 10 ],
  34. [ 't', centerX, centerY ]
  35. ]
  36. }, animateCfg.duration, easing, animateCfg.callback, delay);
  37. }

第三步:注册动画

  1. Animate.registerAnimation('appear', 'delayScaleInY', animateFun);

第四步:绘制柱状图,配置动画参数

  1. chart.interval()
  2. .position('x*y')
  3. .color('y', '#4a657a-#308e92-#b1cfa5-#f5d69f-#f5898b-#ef5055')
  4. .animate({
  5. appear: {
  6. animation: 'delayScaleInY',
  7. easing: 'easeElasticOut',
  8. delay: index => {
  9. return index * 10;
  10. }
  11. }
  12. });