如何让图像沿着SVG路径移动?

欢迎来到这篇教程,今天将向你展示如何使用snapsvg javascript 库使得SVG沿着自定义路径执行动画。我在浏览的过程中发现过很多类似的例子,但它们都没有做出适当的叙述,所以我决定借助一个简单明了的例子来描述一下这个过程。

88148785 - design, sharing - 如何让图像沿着SVG路径移动?

下面是本例的DEMO链接和AI文件的链接:

素材:https://pan.baidu.com/s/1jJmdg6i 密码:qb5p

DEMO:http://demo.icanbecreative.com/animate-along-svg-path/

 

SVG和SnapSVG库的介绍

SVG代表可缩放矢量图形(Scalable Vector Graphics),以XML格式定义,是支持交互性和动画的二位矢量图形格式。现代浏览器可以像处理图像或HTML视频等其他类型的媒体一样显示SVG。

作为矢量格式,SVG主要用于适合矢量的图片或表格,比如:

  • 以X、Y作为坐标系统的二维图片
  • 折线图、饼图等
  • 用于网页、平板电脑、APP和Web应用的可伸缩的图标和Logo
  • 建筑和设计图

SnapSVG是一个基于JavaScript的库,提供创建交互式矢量图形的工具。 可以说SnapSVG之于SVG,就相当于jQuery之于HTML。

其他一些SVG库比如raphaeljs、bonsaijs和velocityjs等也可以达到相同的效果。

就说这么多,下面我们开始吧!

 

导出场景元素

我们的目标是创建沿着自定义路径运动的SVG动画,所以这部分会比较简单。图形是矢量图,案例所给的素材使用AI创建。打开,然后选择另存为,格式选择SVG保存即可。

记住我们的飞船是单独导出的。

 

基于路径的动画

导入场景元素后,接下来的工作就比较有趣了。

首先,我们需要画出我们要播放动画的路径,代码如下:

1
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'});

为了形成动画,我们需要了解我们路径的属性。它的长度是多少?可以通过Snap.path.getTotalLength(path)来获取:

1
flight_path_length = Snap.path.getTotalLength(flight_path);

现在我们可以继续了,SnapSVG为我们提供的动画方法是:Snap.animate(from, to, setter, duration, [easing], [callback])。下面介绍一下它的参数:

  1. from:起点,我们这里设置为0,因为我们希望运动从起点开始。
  2. to:终点:使用我们上面获取的路径长度。
  3. setter:这是一个在动画的每一步都会生效的函数。Setter函数会接受叫做step(步数)的参数,使用整数形式。这里这个参数将被用来计算动画中我们元素的位置。
  4. callback:这个函数会在动画结束后生效,我们将使用它来完成接下来的飞船动画。

重要提示:Snap.animate()是一个通用的动画功能,但它的作用是使数字变化,而不是元素本身。

在我们了解路径长度和Snap.animate()后,就可以来编辑动画的函数了,代码如下:

1
2
3
4
5
Snap.animate(0, flight_path_length, function(step){
//position code goes here
}, 5000, function(){
//callback
});

 

接下来我们将利用setter函数。注意setter函数接受叫做step的参数,通过调用Snap.path.getPointAtLength(flight_path, step)来使用step参数可以获取特定的点,然后把我们的飞船传递过去。setter是一个迭代器,随着动画进行step参数会发生变化。代码看起来会是这样的:

1
2
3
4
5
6
7
8
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();
});

 

其他效果和最终代码

 

请注意我们的例子中还有另外两个小动画过程。

我们的宇宙飞船,推进器的火焰会不断上下运动,而在路径动画结束后,我们的飞船本身也会上下运动。这些动画都是通过将动作拆分成向上运动和向下运动两部分实现的,我们使用动画的transform(x,y)熟悉就可以实现。

最终代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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();
});
}

思考

请记住,其他JavaScript也可以帮你实现这种效果。

如果你喜欢这个教程并觉得有用,请不要犹豫,下载下面的本案例源代码,并尝试自己制作一个类似的项目。

 

英文来源:I can be creative

英文标题:How To Animate Element Along SVG Path

翻译:卡米雷特

微信打赏支付宝打赏

感谢您的支持!

文章来源:卡米雷特的小站www.kamilet.cn)转载请注明出处。

卡米雷特

视觉控&技术控,不断学习中!


您可能还喜欢...

2 条回复

  1. 趣头条说道:

    鸟儿叫,花儿笑,一年一季春来到!

  2. 屌炸天说道:

    新春佳节到。祝好!祝好!

发表评论

电子邮件地址不会被公开。 必填项已用*标注