当前位置主页 > 资料库 > 前端教程 > 如何使用Snap.svg制作SVG路径动画

如何使用Snap.svg制作SVG路径动画

2016-01-22

可以用于制作SVG路径动画的JavaScript库有很多,本文将为大家介绍如何使用Snap.svg动画库来制作效果非常酷的SVG路径动画效果。

先来一张GIF格式的SVG路径动画预览图看看效果!

使用Snap.svg制作的SVG路径动画效果

SVG和SnapSVG动画库介绍

SVG是可缩放矢量图形(stands for Scalable Vector Graphics)。SVG基于XML格式来定义矢量图,它支持二维的矢量图格式,并且可以交互和制作动画效果。所有的现代浏览器都支持SVG格式。

作为矢量图格式,SVG常用于制作以下一些图形:

  • 二维的矢量图。
  • 线性图表,饼状图表等。
  • 桌面、平板电脑、手机和APP应用中的可缩放图标和logo。
  • 建筑与设计图。

SnapSVG是一款基于JavaScript的动画库,它可以非常轻松的实现一些SVG的交互动画效果。

其它还有一些类似的SVG动画库,如raphaeljsbonsaijsvelocityjs等。

制作SVG路径动画

关于示例中的SVG矢量图是直接从illustrator中导出的,在压缩包中有该矢量图的源文件,你使用Save as选项就可以直接将它导出为SVG格式。另外需要注意的是宇宙飞船的SVG矢量图是单独进行导出的。

下面开始来制作小宇宙飞船的路径动画。首先我们需要绘制一条动画的路径。代码如下:

flight_path = map.path('M339.233,312.53c-37.779,
              16.943-119.567-21.598-134.165-71.924c-19.086-65.802,
              19.072-124.856,64.665-145.753s157.388-22.525,219.128,
              74.23s-20.242,229.959-114.73,
              240.688c-88.678,10.069-230.255-62.044-230.25-163.305')
              .attr({ 'fill': 'none', 'stroke': 'none'});                                
                            

关于SVG路径的更多信息可以参考这里。在上面的代码中是使用SnapSVG的path()方法来直接生成一条路径。

为了制作路径动画,我们需要知道路径的长度。我们可以通过Snap.path.getTotalLength(path)方法来获取。

flight_path_length = Snap.path.getTotalLength(flight_path);                                
                            

SnapSVG为我们提供了1个用于动画的方法:

Snap.animate(from, to, setter, duration, [easing], [callback])                                
                            
  • from:是动画的开始点,通常为0,0表示从路径的开始位置开始动画。
  • to:是动画的结束点,它等于路径的长度。
  • setter:是一个在动画中每一步都被调用的函数。Setter中传入一个称为step的整数参数。我们将使用这个参数来计算和动画元素的位置。
  • callback:是动画结束之后的回调函数。我们可以使用这个函数来制作进一步的飞船动画。

需要注意的是,Snap.animate()是一个用于动画两个数值的通用函数,而不是直接动画元素的函数。

我们已经知道了SVG路径的长度,所以我们可以开始使用Snap.animate()函数来制作动画了,代码如下:

Snap.animate(0, flight_path_length, function(step){
                //这里编写位置的代码
            }, 5000, function(){
                //这里是回调函数
            });                                
                            

重点是要看setter函数该如何编写。setter函数接收一个step参数,我们将使用step参数来获取通过Snap.path.getPointAtLength(flight_path, step)方法得到的指定的点,并使宇宙飞船沿这些点进行动画。

Snap.animate()函数的最终代码应该像下面这样:

Snap.animate(0, flight_path_length, function( step ) {
    moveToPoint = Snap.path.getPointAtLength( flight_path, step );
    x = moveToPoint.x - (spaceshipbbox.width/2);
    y = moveToPoint.y - (spaceshipbbox.height/2);
    spaceship.transform('translate(' + x + ',' + y + ') 
                         rotate('+ (moveToPoint.alpha - 90)+', 
                         '+spaceshipbbox.cx+', '+spaceshipbbox.cy+')');
},5000, mina.easeout ,function(){
    ship_move_up();
});
                            
其它动画代码

在DEMO中还有另外2个小动画效果。小火箭的推进器是一个无限循环的上下运动动画,还有就是在路径动画结束时,小火箭的上下运动动画效果。这两个动画都是上下运动的动画,我们使用transform(x,y)属性来制作这两个动画效果。

整个SVG路径动画的完整代码如下:

var paper, map, spaceship, thruster, moon, flight_path, flight_path_length, last_point;
window.onload = function () {
    paper               = map;
    map                 = Snap('#svg-doc');
    spaceship           = map.select('#spaceship');
    spaceshipbbox       = spaceship.getBBox();
    thruster            = map.select('#thruster');
    moon                = map.select('#moon');
    flight_path         = map.path('M339.233,312.53c-37.779,16.943-119.567-21.598-134.165-71.924c-19.086-65.802,19.072-124.856,64.665-145.753s157.388-22.525,219.128,74.23s-20.242,229.959-114.73,240.688   c-88.678,10.069-230.255-62.044-230.25-163.305').attr({ 'fill': 'none', 'stroke': 'none'});
    flight_path_length  = Snap.path.getTotalLength(flight_path);
    last_point          = flight_path.getPointAtLength(flight_path_length);
    // starting the thruster animation
    animate_thruster_down();
    Snap.animate(0, flight_path_length, function( step ) {
                    moveToPoint = Snap.path.getPointAtLength( flight_path, step );
                    x = moveToPoint.x - (spaceshipbbox.width/2);
                    y = moveToPoint.y - (spaceshipbbox.height/2);
                    spaceship.transform('translate(' + x + ',' + y + ') rotate('+ (moveToPoint.alpha - 90)+', '+spaceshipbbox.cx+', '+spaceshipbbox.cy+')');
                },5000, mina.easeout ,function(){
                    ship_move_up();
                });
};
function ship_move_up(){
    spaceship.animate({'transform': 'translate(' + (last_point.x - (spaceshipbbox.width/2)) 
                        + ',' + (last_point.y - (spaceshipbbox.height / 2) - 20) + ')'},1300,
                        function(){
                        ship_move_down();
                    });
}
function ship_move_down(){
    spaceship.animate({'transform': 'translate(' + (last_point.x - (spaceshipbbox.width/2)) 
                        + ',' + (last_point.y - (spaceshipbbox.height / 2)) + ')'},1100, 
                        function(){
                        ship_move_up();
                    });
}
function animate_thruster_up(){
    thruster.animate({'transform': 'translate(0,-5)'},100, function(){
        animate_thruster_down();
    });
}
function animate_thruster_down(){
    thruster.animate({'transform': 'translate(0,0)'},100, function(){
        animate_thruster_up();
    });
}                                
                            

查看演示 下载地址

相关阅读
Previous:
上一篇:使用CSS flexbox制作响应式等高列布局
Next:
下一篇:了解CSS浏览器前缀(CSS Vendor Prefixes)
返回顶部