使用Snap.svg制作动画_网站前端开发_前端开发者

网站前端开发_前端开发者html css   web前端开发

https://www.rokub.com

使用Snap.svg制作动画一、Snap.svg是什么从主要功能上说,Snap.svg.js是一个操纵SVG节点/制作SVG动画的框架,简单点理解可以看下面文字:Snap.svg是一个可以使你操纵SVG资源jquery操作DOM一样简单的类库——译自官网拿Snap.svg(下文简称Snap)和jquery(下文简称JQ)来做对比最合适不过,很可能作者也是参考了JQ的API设计,那么它们的相似程度有多高呢?请看下面的对比表:/context(上下文)选择器事件绑定节点操作属性操作链式写法SnapsvgSnap.select(‘circle’)el.click(…)/el.touchend(…)after()/remove()/append()attr()svg.paper.circle(50,50,40).attr({

fill:”#f00”
});
JQdocumentjQuery(‘div’)el.click(…)after()/remove()/append()attr()elem.addClass(‘hide’).remove();
在JQ中,可操作的最外层DOM边界是document。而在Snap的概念里,可操作的最外层的节点是svg,svg节点的选择、事件绑定都需要在这个上下文里完成。在上面的对比图可以看出很多JQ的影子,无论是选择器、事件绑定、节点操作等等,都是非常的类似JQ,有JQ基础的同学基本可以半天掌握Snap的全部API。二、Snap的代码结构笔者根据Snap的API制作了上面的图表,并且简单标注了注释方便大家理解,可以重点关注一下Element和Paper这两个类。1.Element这个部分是节点操作相关的方法集,也是该类库最基础的部分。选择节点
var svg=Snap(‘#svg’);
svg.select(‘circle’);
选择svg.select(‘.rect_01’);
选择1234选择节点
var svg=Snap(‘#svg’);
svg.select(‘circle’);
选择svg.select(‘.rect_01’);
选择事件绑定
var svg=Snap(‘#svg’);
svg.select(‘circle’).click(function(){
dosomething
});
12345事件绑定
var svg=Snap(‘#svg’);
svg.select(‘circle’).click(function(){
dosomething
});
更多方法请参考文后API资料。2.Paper这部分是画图相关的方法集,这是几乎每个动画框架都有的部分,类似于createjs的Graphics。SVG有6种基本图形:矩形、圆形、椭圆、线条、折线、多边形。还有另外一种:路径(path),path是最复杂的一种绘图方式,它可以绘制复杂的图形——当然6种基本图形也不在话下。而关于基本图像与path之间的转换,可以参考本站的另外一篇文章:聊聊SVG基本形状转换那些事。Paper方法集主要可以绘制6种基本图形(节点),以及文本(节点)、图片(节点)、渐变等。画一个圆
var svg=Snap(‘#svg’);
svg.paper.circle({
cx:100,
cy:100,
r:50,
fill:’#f00′
});
创建一张图片svg.paper.image(‘url.jpg’,0,400,300,300);
1234567891011画一个圆
var svg=Snap(‘#svg’);
svg.paper.circle({
cx:100,
cy:100,
r:50,
fill:’#f00′
});
创建一张图片svg.paper.image(‘url.jpg’,0,400,300,300);
3.Snap工具方法Snap下有不少实用工具,比如Snap.ajax、Snap.format模板、颜色格式转换和插件方法等。扩展Snap,为其添加插件方法Snap.plugin(function(Snap,Element,Paper,global,Fragment){
Snap.newmethod=function(){};
Element.prototype.newmethod=function(){};
Paper.prototype.newmethod=function(){};
});
123456扩展Snap,为其添加插件方法Snap.plugin(function(Snap,Element,Paper,global,Fragment){
Snap.newmethod=function(){};
Element.prototype.newmethod=function(){};
Paper.prototype.newmethod=function(){};
});
三、用Snap制作动画1.制作动画的方法Snap的做动画主要有两种方式:使用Element里的animate方法,Element.animate(attrs,duration,[easing],[callback])使用Snap的静态方法,Snap.animate(from,to,setter,duration,[easing],[callback]),这种方法更通用也更强大,指定开始结束值,setter里面可以放置多个节点的动画。样例:演示Element.animate方法的使用。预览地址点此动画样例1
var svg=Snap(‘#svg’);
svg.select(‘circle’).animate({
r:100
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
动画样例2
var svg=Snap(‘#svg’);
var circle=svg.select(‘circle’);
var rect=svg.select(‘rect’);
Snap.animate(0,100,function(val){
circle.attr({
r:val
});
rect.attr({
x:val
});
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
12345678910111213141516动画样例1
var svg=Snap(‘#svg’);
svg.select(‘circle’).animate({
r:100
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
动画样例2
var svg=Snap(‘#svg’);
var circle=svg.select(‘circle’);
var rect=svg.select(‘rect’);
Snap.animate(0,100,function(val){
circle.attr({
r:val
});
rect.attr({
x:val
});
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
2.动画的属性在Snap中,可作为动画的属性有哪些呢?笔者大致分为了几类:简单数值类,如坐标、宽高、opacity、大部分PaperAPI可配置的属性值,甚至滤镜相关的属性。如{
x:100
}->{
x:200
},{
width:0
}->{
width:100
}
path相关动画,如d属性(变形动画)、描边动画、路径跟随动画matrix类,放大缩小、位移、旋转等,和css的transform类似颜色类,颜色变换动画,如fill、stroke属性,如{
fill:’#f00’
}->{
fill:’#f0f’
}
样例:颜色变换动画,预览地址点此动画样例,颜色变化动画
var svg=Snap(‘#svg’);
var circle=svg.paper.circle({
cx:100,
cy:100,
r:50,
fill:’#f00′
});
circle.animate({
fill:’#00f’
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
123456动画样例,颜色变化动画
var svg=Snap(‘#svg’);
var circle=svg.paper.circle({
cx:100,
cy:100,
r:50,
fill:’#f00′
});
circle.animate({
fill:’#00f’
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
四、path&matrix动画详解这个小节重点会讲上面第2小节提到的path、matrix相关动画方式,以及和css的transform动画的异同。1.path动画1).path变形动画这种类型的动画非常强大。上文已提到基本图形和path是可以相互转换的,所以基本图形间的变形动画也是成立的。不仅如此,更复杂的path图形,比如波浪、房子、汽车、白云、小icon等,都是可以互相变形。path的d属性在Snap的解析规则里可以通过一系列的数学运算,动画中通过插值,达到最终态的d值,不过中间的插值计算我们无法干预。开始态
var path=svg.paper.path({
d:’M0.500,65.500C18.680,33.75845.141,-6.79772.500,2.500C99.859,11.79772.148,59.02779.500,98.500C86.852,137.973117.668,128.914138.500,59.500C159.332,-9.914246.500,59.500246.500,59.500C273.181,117.750137.350,184.417225.500,173.500C351.137,157.940155.369,160.617162.500,86.500C165.180,58.645237.169,-2.418283.500,2.500C357.654,10.371363.758,80.355364.500,109.500′,
stroke:’#f00′,
fill:’rgba(0,0,0,0)’
});
setTimeout(function(){
终止态:曲线变直path.animate({
d:’M1,100L350,100′
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
终止态:心形path.animate({
d:’M114.500,58.500C106.230,58.75123.907,-37.2625.500,21.500C-26.759,124.483111.761,221.360119.500,219.500C154.464,211.096201.234,149.580220.500,104.500C250.260,34.864220.892,7.159194.500,1.500C160.455,-5.800122.344,58.262114.500,58.500Z’
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
},1000);
123456789101112开始态
var path=svg.paper.path({
d:’M0.500,65.500C18.680,33.75845.141,-6.79772.500,2.500C99.859,11.79772.148,59.02779.500,98.500C86.852,137.973117.668,128.914138.500,59.500C159.332,-9.914246.500,59.500246.500,59.500C273.181,117.750137.350,184.417225.500,173.500C351.137,157.940155.369,160.617162.500,86.500C165.180,58.645237.169,-2.418283.500,2.500C357.654,10.371363.758,80.355364.500,109.500′,
stroke:’#f00′,
fill:’rgba(0,0,0,0)’
});
setTimeout(function(){
终止态:曲线变直path.animate({
d:’M1,100L350,100′
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
终止态:心形path.animate({
d:’M114.500,58.500C106.230,58.75123.907,-37.2625.500,21.500C-26.759,124.483111.761,221.360119.500,219.500C154.464,211.096201.234,149.580220.500,104.500C250.260,34.864220.892,7.159194.500,1.500C160.455,-5.800122.344,58.262114.500,58.500Z’
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
},1000);
样例:曲线变直线,预览地址点此样例:曲线变心形,预览地址点此2).path描边动画这种动画主要用的是svg的stroke-dasharray、stroke-dashoffset属性,这中动画方式在本站的另外一篇文章有详细介绍,这里不再赘述:三看SVGWeb动效样例:简单曲线描边动画var path=svg.paper.path({
d:’M0.500,65.500C18.680,33.75845.141,-6.79772.500,2.500C99.859,11.79772.148,59.02779.500,98.500C86.852,137.973117.668,128.914138.500,59.500C159.332,-9.914246.500,59.500246.500,59.500C273.181,117.750137.350,184.417225.500,173.500C351.137,157.940155.369,160.617162.500,86.500C165.180,58.645237.169,-2.418283.500,2.500C357.654,10.371363.758,80.355364.500,109.500′,
stroke:’#f00′,
fill:’rgba(0,0,0,0)’
});
var length=Snap.path.getTotalLength(path);
path.attr({
‘stroke-dashoffset’:length,
‘stroke-dasharray’:length用Snap的API计算复杂的path长度
});
Snap.animate(length,0,function(val){
path.attr({
‘stroke-dashoffset’:val
});
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
12345678910111213
var path=svg.paper.path({
d:’M0.500,65.500C18.680,33.75845.141,-6.79772.500,2.500C99.859,11.79772.148,59.02779.500,98.500C86.852,137.973117.668,128.914138.500,59.500C159.332,-9.914246.500,59.500246.500,59.500C273.181,117.750137.350,184.417225.500,173.500C351.137,157.940155.369,160.617162.500,86.500C165.180,58.645237.169,-2.418283.500,2.500C357.654,10.371363.758,80.355364.500,109.500′,
stroke:’#f00′,
fill:’rgba(0,0,0,0)’
});
var length=Snap.path.getTotalLength(path);
path.attr({
‘stroke-dashoffset’:length,
‘stroke-dasharray’:length用Snap的API计算复杂的path长度
});
Snap.animate(length,0,function(val){
path.attr({
‘stroke-dashoffset’:val
});
},1000,mina.easeout(),function(){
console.log(‘animationend’);
});
或者用css实现:@keyframesdemo4{
100%{
stroke-dashoffset:0
}
}.demo4{
animation:demo41sease-outinfiniteboth;
}
12345678@keyframesdemo4{
100%{
stroke-dashoffset:0
}
}.demo4{
animation:demo41sease-outinfiniteboth;
}
样例:花纹描边。这是codepen上一个复杂的例子——复杂花纹的描边动画,预览地址点此:3).path路径跟随动画这种动画是指一个svg节点(基本图形、文本、图片等)沿着轨迹移动的动画,主要适用于模拟交通工具航行轨迹、粒子散开轨迹等。这种动画的关键之处在于要知道path的长度与坐标之间的对应关系,Snap提供了可供获取path的长度以及根据长度获取位置坐标的API。结合上面的Snap.animate方法,路径跟随动画的制作会变得非常简单。样例:跟随曲线运动的小飞机,预览地址点此:
var length=Snap.path.getTotalLength(path);
获取path的长度Snap.animate(0,length,function(val){
var point=Snap.path.getPointAtLength(path,val);
根据path长度变化获取坐标
var m=newSnap.Matrix();
m.translate(point.x,point.y);
m.rotate(point.alpha-90);
使飞机总是朝着曲线方向。point.alpha:点的切线和水平线形成的夹角plane.transform(m);
},30000,mina.easeout(),function(){
console.log(‘animationend’);
});
12345678910
var length=Snap.path.getTotalLength(path);
获取path的长度Snap.animate(0,length,function(val){
var point=Snap.path.getPointAtLength(path,val);
根据path长度变化获取坐标
var m=newSnap.Matrix();
m.translate(point.x,point.y);
m.rotate(point.alpha-90);
使飞机总是朝着曲线方向。point.alpha:点的切线和水平线形成的夹角plane.transform(m);
},30000,mina.easeout(),function(){
console.log(‘animationend’);
});
样例:双12开场动画,这是笔者去年双12做的一个路径跟随动画效果,预览地址点此:另外,用新的css属性motion-path也可以实现类似效果,但目前支持程度堪忧,只有PC的chrome以及Opera、最新的X5内核手机浏览器支持情况较好。@keyframesdemo5{
0%{
motion-offset:0;
}
100%{
motion-offset:100%;
}
}.demo5{
motion-path:path(“M221.712,180.442C237.176,177.728,279.348,178.094,261,152c-18.742-26.654-48.543-28.207-63-22-14.981,6.431-34.763,6.357-34,40s66.09,74.162,88,68,60.358-23.742,67-49,14.211-59.957-27-81S163.688,88.664,153,98c-7.828,6.838-32.045,22.952-32,64,0.039,35.491,7.878,62.872,14,78s52.737,39.557,73,41,58.638,16.552,105-7c44.249-22.478,75.073-94.409,55-164C349.768,46.792,217.142,54.519,200,55S104.613,66.128,78,111c-16.922,28.532-16.5,96.616,1,134,14.482,30.932,51.88,58.52,68,64,39.988,13.593,100.081,21.615,129,17”);
motion-rotation:auto90deg;
使飞机方向始终朝着曲线animation:demo510slinearinfiniteboth;
}
12345678910111213@keyframesdemo5{
0%{
motion-offset:0;
}
100%{
motion-offset:100%;
}
}.demo5{
motion-path:path(“M221.712,180.442C237.176,177.728,279.348,178.094,261,152c-18.742-26.654-48.543-28.207-63-22-14.981,6.431-34.763,6.357-34,40s66.09,74.162,88,68,60.358-23.742,67-49,14.211-59.957-27-81S163.688,88.664,153,98c-7.828,6.838-32.045,22.952-32,64,0.039,35.491,7.878,62.872,14,78s52.737,39.557,73,41,58.638,16.552,105-7c44.249-22.478,75.073-94.409,55-164C349.768,46.792,217.142,54.519,200,55S104.613,66.128,78,111c-16.922,28.532-16.5,96.616,1,134,14.482,30.932,51.88,58.52,68,64,39.988,13.593,100.081,21.615,129,17”);
motion-rotation:auto90deg;
使飞机方向始终朝着曲线animation:demo510slinearinfiniteboth;
}
预览地址点此(请在最新版chrome、Opera或最新的X5内核手机浏览器查看)2.matrix动画Snap的matrix动画包含各位熟悉的translate/scale/rotate/skew动画,原理和CSS的transform也几乎一致。1)matrix简单位移动画,预览地址点此:简单位移动画
var rect=svg.paper.rect({
x:100,
y:100,
width:50,
height:30,
fill:’#f00′
});
var anim=function(){
Snap.animate(0,150,function(val){
var m=newSnap.Matrix();
m.translate(val,0);
translate位移APIrect.transform(m);
在rect节点应用matrix
},1000,mina.easeout(),function(){
console.log(‘animationend’);
setTimeout(anim,300);
});
}
anim();
12345678910111213简单位移动画
var rect=svg.paper.rect({
x:100,
y:100,
width:50,
height:30,
fill:’#f00′
});
var anim=function(){
Snap.animate(0,150,function(val){
var m=newSnap.Matrix();
m.translate(val,0);
translate位移APIrect.transform(m);
在rect节点应用matrix
},1000,mina.easeout(),function(){
console.log(‘animationend’);
setTimeout(anim,300);
});
}
anim();
2)matrix位移、旋转复合动画,预览地址点此:位移、旋转复合动画
var rect=svg.paper.rect({
x:10,
y:100,
width:50,
height:30,
fill:’#f00′
});
var g=svg.paper.group(rect);
创建了一个分组节点g作为位移动画节点
var anim_rotate=function(){
节点旋转部分Snap.animate(0,250,function(val){
var m=newSnap.Matrix();
m.rotate((val/250)*360,10+25,100+15);
注意,后面两位数是旋转中心点,属于绝对坐标,svg里节点的变换中心都是绝对坐标,和CSS的transform-origin取值不太一样rect.transform(m);
},500,mina.easeout(),function(){
console.log(‘animationend’);
anim_rotate();
});
};
anim_rotate();
var anim_move=function(){
节点位移部分Snap.animate(0,250,function(val){
var m=newSnap.Matrix();
m.translate(val,0);
g.transform(m);
},2000,mina.easeout(),function(){
console.log(‘animationend’);
anim_move();
});
};
anim_move();
12345678910111213141516171819202122232425位移、旋转复合动画
var rect=svg.paper.rect({
x:10,
y:100,
width:50,
height:30,
fill:’#f00′
});
var g=svg.paper.group(rect);
创建了一个分组节点g作为位移动画节点
var anim_rotate=function(){
节点旋转部分Snap.animate(0,250,function(val){
var m=newSnap.Matrix();
m.rotate((val/250)*360,10+25,100+15);
注意,后面两位数是旋转中心点,属于绝对坐标,svg里节点的变换中心都是绝对坐标,和CSS的transform-origin取值不太一样rect.transform(m);
},500,mina.easeout(),function(){
console.log(‘animationend’);
anim_rotate();
});
};
anim_rotate();
var anim_move=function(){
节点位移部分Snap.animate(0,250,function(val){
var m=newSnap.Matrix();
m.translate(val,0);
g.transform(m);
},2000,mina.easeout(),function(){
console.log(‘animationend’);
anim_move();
});
};
anim_move();
上面两个动画用CSS的方式实现代码如下:@keyframesdemo6{
100%{
transform:translate3d(250px,0,0);
}
}
简单位移动画CSS版.demo6{
animation:demo62slinearinfiniteboth;
}
@keyframesdemo7_rotate{
100%{
transform:rotate(360deg);
}
}
@keyframesdemo7_move{
100%{
transform:translate3d(250px,0,0);
}
}
旋转、位移符合动画CSS版.demo7{
animation:demo7_move2slinearinfiniteboth;rect{
transform-origin:35px115px;
animation:demo7_rotate.5slinearinfiniteboth;
}
}
12345678910111213141516171819202122232425262728@keyframesdemo6{
100%{
transform:translate3d(250px,0,0);
}
}
简单位移动画CSS版.demo6{
animation:demo62slinearinfiniteboth;
}
@keyframesdemo7_rotate{
100%{
transform:rotate(360deg);
}
}
@keyframesdemo7_move{
100%{
transform:translate3d(250px,0,0);
}
}
旋转、位移符合动画CSS版.demo7{
animation:demo7_move2slinearinfiniteboth;rect{
transform-origin:35px115px;
animation:demo7_rotate.5slinearinfiniteboth;
}
}
简单位移动画CSS版预览点此;旋转、位移符合动画CSS版预览点此。五、几个兼容性说明及建议这部分会说一下笔者在开发过程中遇到的一些兼容性问题以及使用建议。当然还会有更多的笔者没遇到的问题,欢迎各位看官多多评论交流,不吝赐教。总的来说,Snap的API兼容性不错,官网声称兼容IE9及以上、Safari、Chrome、Firefox、Opera;而移动设备方面,经笔者测试iOS、安卓X5内核、安卓原生浏览器兼容性都不错,文中的例子除了特殊说明外的都可以执行,官网声称兼容;而移动设备方面,经笔者测试兼容性都不错,文中的例子除了特殊说明外的都可以执行作用于svg节点的CSStransform动画在安卓原生浏览器下兼容性不好,X5则正常下兼容性不好,X5则正常在iOS7和8下innerHTML方法不能用于svg里下innerHTML方法不能用于svg里安卓原生浏览器绘制svg图形很可能会产生渲染模糊的现象(如下图),在svg里加上一个text节点即可神奇的修复这样的节点<text>a</text>即可修复模糊的问题,但不能display:none隐藏在使用建议方面:一般来说,transform动画可以优先使用CSS的方式实现,但如果需要复杂的分段控制或者更好的兼容性,可以试试Snap的transform&matrix方式Snap的有些动画需要大量计算,虽然svg里的节点属于“绝对定位”,动画时一般不会引起重排(参考下图),但在移动设备上也要注意动画元素不宜过多。以image动画为例,经笔者测试,150×150左右的图片动画节点控制在10个左右基本能达到大部分机型的性能要求滤镜类属性在移动设备上不宜做动画小飞机动画在chrome的渲染层边界图:橙色边为svg的边界(即渲染层,为了便于查看svg节点经过了transform:rotateY(30deg);绿色为重绘部分。可以看出svg里的动画元素只会引起重绘,而里面的节点用translateZ也并不会新开一个渲染层。六、参考资料Snap.svg官网。
» 本文来自:前端开发者 » 《使用Snap.svg制作动画_网站前端开发_前端开发者》
» 本文链接地址:https://www.rokub.com/2348.html
» 您也可以订阅本站:https://www.rokub.com
赞(0)
64K

评论 抢沙发

评论前必须登录!