IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    HTML5 SVG实践(二):栅格动画

    Rykka发表于 2014-09-12 23:02:00
    love 0

    本文主要演示了如何通过Snap.SVG创造一组栅格动画。

    首先演示了如何用Snap.SVG创造元素, 然后说明了如何使设置元素的属性。 之后让一组元素平滑的进行动画, 最后使这组动画无限循环。

    点击预览最终 Demo

    目录

    • 1. 什么是Snap.SVG?
    • 2. Snap a SVG
    • 3. 控制SVG
      • 3.1. 添加SVG
      • 3.2. 更改属性
      • 3.3. 进行动画
    • 4. 让一组元素平滑动画
      • 4.1. 创建一组元素
      • 4.2. 让这组元素动起来
    • 5. 循环动画

    1. 什么是Snap.SVG?

    Snap.svg 是Adobe的一个开源JavaScript库, 用来更方便的控制SVG元素,就像用jQuery控制DOM元素一样。

    在使用前,我们需要在官网上下载相对应的js文件。

    这里只对功能做大致描述。 具体文档见 http://snapsvg.io/docs/

    也可以查看 张鑫旭同学的中文文档

    2. Snap a SVG

    通过Snap.svg,我们可以Snap一个SVG元素:

    var svg = Snap(width, height) ;
    

    得到的svg元素则被Snap化了,使得我们更方便进行操控。 我们也可以像jQuery一样,直接选择一个SVG元素:

    var svg = Snap("#svg-elem") ;
    

    首先我们在页面的showSVG的div中创建一个SVG元素:

    var showSVG = document.querySelector(".showSVG");
    var svg = Snap(100, 100) ;
    showSVG.append(svg.node);
    

    接下来我们就可以对其中的元素进行控制了。

    3. 控制SVG

    3.1. 添加SVG

    添加一个元素, 比如 svg.paper.rect(x, y, h, w, [rx], [ry]):

    var r1 = svg.paper.rect(0,0,20,100);
    

    相当于在svg中插入一个rect:

    
    

    返回一个snap元素。

    3.2. 更改属性

    我们可以直接对得到的snap元素进行赋值:

    r1.attr({fill:'#f33'});
    

    则相当于为r1添加相应属性。

    3.3. 进行动画

    更重要的是,我们可以对元素直接赋予动画, 这样就避免了书写复杂的SVG动画。

    比如:

    r1.animate({x:100},1000);
    

    表示在1000ms的持续时间内, 将r1的x坐标移动到100。

    Snap本身也有一个动画函数,可以更平滑的控制动画

    Snap.animate(from, to, setter, duration, [easing], [callback]):

    Snap.animate(0,100,function(val){
        r1.attr({x:val})
    }, 1000)
    

    该动画效果类似上一个效果。 但是我们可以同时对多个元素和属性进行同步设置。

    4. 让一组元素平滑动画

    让一组元素平滑的进行动画,则需要我们对一组元素按顺序进行控制。

    4.1. 创建一组元素

    首先我们创建一组元素,代码如下

    var g = svg.paper.g();
    var c = Array.apply(null, {length: 20})
        .map(Number.call, Number)
        .map(function(num){
            var _t = svg.paper.rect((num-1)*10, 0,
                    9, 100).attr({fill:'#b00'});
            g.add(_t);
            return _t;
        });
    var s = g.selectAll('rect');
    

    这里我们创建了一个包含20个元素的数组c, 里面每一个元素的x坐标分别增加10。

    并将这些元素在SVG里面用Paper.g()进行分组。 最后将这些元素放到一个s的Snap.set里面,方便进行控制。

    4.2. 让这组元素动起来

    首先我们可以想到的,就是用 Snap.animate()

    我们可以先添加元素到一个Snap.set组里面, 然后在进行动画时,在setter函数里逐个对set元素组里的的attr进行设置。

    Snap.animate(0,100,function(val){
        s.forEach(function(elem,i){
            elem.attr({y : val/10+i*10});
        });
    },1000)
    

    但是这样有几个弊端:

    1. 我们很难设置其他属性,比如颜色的变化。
    2. 每一个元素不能设置相应的easing特效。比如有的元素用bounce,有的用ease-in.
    3. 很难使用路径。

    那么,我们想这样,对组里的每一个元素 分时段分别开始进行animate。

    即类似以下伪代码:

    for i in [i1,i2,i3]
        i animate
        wait 500
    endfor
    

    那么我们需要实现一个简单的 step_animate。

    代码如下:

    // animate by step
    // steps is the total number of step,
    // after init timeout
    // run step_func with each step.
    // call the callback after finished.
    function step_animate(init_timeout, steps, total_time, step_func, callback){
        setTimeout(function(){
            var intervalId = setInterval(step_func, total_time/steps);
            setTimeout(function(){
                clearInterval(intervalId);
                if (callback != null) {
                    callback();
                }
            }, total_time);
        },init_timeout)
    }
    

    注:不用Snap.animate进行step的设置,而是直接用setInterval, 因为Snap.animate有时运行会顿一下,然后Step就会出现间隔。

    直接使用即可:

    var k = 0;
    step_animate(0,20, 2000, function(){
        c[k].animate({y:300},1500);
        c[k].animate({fill:'#3800BA'},1500);
        k++;
    })
    

    测试代码,则可以看到可以运行了。

    5. 循环动画

    最后一个问题。 怎么让动画无限循环呢?

    我们可以通过将step_animate函数包裹在一个Wrapper Function里面, 并在 callback里面递归调用Wrapper Function来实现:

    function Anim() {
         var k = 0 ;
         s.attr({y:0});
         s.attr({fill:'#c00'});
         step_animate(0,20, 3000, function(){
             c[k].animate({y:300},1500);
             c[k].animate({fill:'#3800BA'},1500);
             k++;
         },
         function(){
             setTimeout(Anim, 1600);
         })
     }
     Anim();
    

    需要注意的是,我们必须在step_animate开始前对相应属性初始化。 同时setTimeout应该在所有子元素的动画都完成之后再开始。

    而如果我们要加入多重动画的话,则我们必须嵌套多层step_animation。

    最后再进行了一些调整和内容的丰富, 预览见 Demo

    本文完



沪ICP备19023445号-2号
友情链接