如何用svg动画打动一个女孩
by addy 原创文章,欢迎转载,但希望全文转载,注明本文地址。
本文地址:http://www.iamaddy.net/2017/05/svg-animation-gift-for-a-girl/
研究SVG源于给女朋友做一个小礼物,这个创意也是从我同事那里抄袭过来的。当时看到就非常震撼,是个很不错的idea。
svg是矢量图形,那有什么方法可以使他动起来呢。
使用 SMIL 的 SVG 动画
这种语言很好懂,只要在一个SVG元素内添加一个SVG元素比如说<animate>
,就能实现让元素动起来。在这元素上添加一些属性来控制需要改变的属性。
- attributeName 变动的属性的属性名。
- from 变动的初始值。
- to 变动的终值
-
dur 动画的持续时间(举个例子,写“5s”代表5秒表)
具体我就不展开讲了,因为文档上都能查看到,SVG_animation_with_SMIL、animate。
不过Chrome 45弃用了SML,以利于CSS动画以及Web动画。所以利用CSS动画,我们也可以让SVG动起来。
使用CSS 属性的SVG动画
如何做到如下图这样的一种画线的动画呢?下面这段代码就可以做到。
var path = document.querySelector('.path');
var length = path.getTotalLength();
// 清除之前的动作
path.style.transition = path.style.WebkitTransition =
'none';
// 设置起始点
path.style.strokeDasharray = length + ' ' + length;
path.style.strokeDashoffset = length;
// 获取一个区域,获取相关的样式,让浏览器寻找一个起始点。
path.getBoundingClientRect();
// 定义动作
path.style.transition = path.style.WebkitTransition =
'stroke-dashoffset 2s ease-in-out';
// Go!
path.style.strokeDashoffset = '0';
我来说明下上面的关键点,针对path元素,设置transition动画属性,动画目标的属性是path元素的stroke-dashoffset,这个属性是指定了dash模式到路径开始的距离。这个官方定义听着有点迷糊,先来看下strokeDasharray属性,它既可以是style属性,也可以是元素属性,用来定义线条虚实的宽度。 比如:
<line stroke-dasharray="5, 5" x1="10" y1="10" x2="190" y2="10" />
<line stroke-dasharray="5, 10" x1="10" y1="30" x2="190" y2="30" />
会输出下面的两条虚线,很容易明白吧,前面的数字代表实现的长度,后面的数字代表了间隔的长度。
回过头看最前面的那段代码就是设置虚实的长度都等于路径本身的长度。
然后dashoffset呢?第一条虚线最左边的起点是以实现开始,如果设置dashoffset = 5,那么就是以虚线开始。
而且线条会循环,如果设置dashoffset = 180,线条并不会偏移180像素,因为这不是margin,而是相当于dashoffset = 0。所以设置dashoffset等于path长度变为dashoffset=0则会让线条从无到有的出现。如果加上transion,这就可以让线条动起来了。同理,只要css可以控制的动画属性,都可以做出动画效果。
但是如果路径图形很复杂,又要控制动画的协调与连贯性,就比较复杂。业界也有一些类库来实现,比如vivus。我的动画页面就是基于此做的,功能还是很强大,有不同的动画效果。
vivus
我们来看下vivus的原理。最直接的方法就是看源码了:https://maxwellito.github.io/vivus/
vivus会把所有的svg元素转换为path元素来表示,因为任意的svg元素实质上都可以用path来表示。接着我们可以看到代码会设置dashoffset相关属性:
path.style.strokeDasharray = pathObj.length + ' ' + (pathObj.length + this.dashGap * 2);
path.style.strokeDashoffset = pathObj.length + this.dashGap;
vivus这个库就是用来画图形的轮廓,所以划线就是改变strokeDashoffset 的值,但他不是利用css来做动画,而是通过js来控制。每一条path都有一个开始绘制的属性和绘制时长属性,可以精密的控制线条绘制的时长。而且轮廓的绘制可以定制为几种类型:
- Delayed 延迟
- Sync 同步
- OneByOne 一个接一个
每种绘制都有着不同的视觉效果,如果你的SVG图像做的很丰富,可以看到很绚丽的动画。
从vivus的源码看来,只能是绘制path轮廓,不能是其他的像矩形填充的动画。
实例讲解
我最终的成品就是这张明信片:
推荐在AI(Adobe Illustrator)里面制作的,真是的设计的利器。对于我这种初学者也很友好,绘制后的图像,可以直接导出SVG的代码,方面我们在程序中使用。
要注意的一点是:文字要转为轮廓,不然导出来的代码是text元素,达不到我们的目的了,因为vivus是没有把text转为path。她只支持['line', 'ellipse', 'circle', 'polygon', 'polyline', 'rect']这几种格式的转换。
导出的SVG,要注意大小,如果太大了(我的已经快1M了),在iPhone上出现绘制不了的情况,不知道是不是这个库的bug,导致我花了大量时间来定位。由于时间关系,不得不删掉了部分元素。合理的是可以拆分为好几个svg,通过css控制每个svg的位置就好,也可以组合出完美的图像。
var _Vivus = new Vivus('add', {
duration: /android/i.test(navigator.userAgent) ? 4000: 6000,
type: 'oneByOne',
onReady: function(id){
id.el.setAttribute('height', document.documentElement.clientHeight - 10);
},
start: 'autostart'
}, function(e) {
callback();
});
Android上的性能不够好,绘制有点卡顿,而且明显要比iPhone上要慢,所以可以针对不同的平台做测试以达到满足自己的需求。 另外,可以在ready的时候在设置svg画布的大小,不然没有铺满就不太好看。 因为我的图像不仅仅是一个素描画,画完轮廓后需要上色,但是vivus这个库是不支持的。所以需要自己去写代码完成,在绘制之前把svg的填充色清空。svg元素的颜色最好用class来控制,会更加方便些代码 。
var paths = document.querySelectorAll('path');
for(var i = 0; i < paths.length; i++){
paths[i].style.cssText = 'fill:none;stroke-width:0.2px;stroke:black;';
}
绘制之前先清空填充色。颜色的动画我是用透明度来控制:
全部绘制完成,设置原本的opacity值,再加上一个transition动画,就可以让颜色以动画效果出来。
paths[i].style.cssText = 'fill-opacity:' + paths[i].getAttribute('data-opacity');
可以参考作者的一个小例子animate fill。
另外在这个例子上,因为需要用到音乐,但iPhone是不能自动播放的。考虑到传播路径主要在微信里面,而且微信提供了接口可以做到。
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
wx.config({
// 配置信息, 即使不正确也能使用 wx.ready
debug: false,
appId: '',
timestamp: 1,
nonceStr: '',
signature: '',
jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage',]
});
wx.ready(function() {
document.getElementById('music').play();
});
基本上这个例子就完成了,看到这里就把链接放出来PC点这里,手机端点这里,源码自己看。
以上,看完不要忘了点赞哦~
本文为原创文章,可能会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,谢谢合作
本文地址:http://www.iamaddy.net/2017/05/svg-animation-gift-for-a-girl/
个人知乎,欢迎关注:https://www.zhihu.com/people/iamaddy
欢迎关注公众号【入门游戏开发】
近期评论