js 动画二

作者: wpzero | 来源:发表于2016-03-23 16:57 被阅读151次

    这一篇是接着上一篇 翻译。原文点击
    上一篇主要讲了animate的基本原理。这一篇主要将几种常见的delta。

    进度函数delta

    动画是随着时间变化而变化的,在javascript动画中,这个变化的原则是由delta来决定的。
    不同的delta使动画的变化速度,加速度和其他的一些参数完全不同。
    数学公式经常会被用到。对于一些已经离开学校多年的web从业者可能对于这些公式比较陌生。但是,在这里我将应用一些非常流行的函数,来看看他们怎么工作。
    下面这里的动画例子依次提供不同的delta。

    线性 delta

    function linear(progress){
      return progress;
    }
    
    Paste_Image.png
    水平线是progress(时间的进度),垂直线是delta(progress) 也就是动画移动的进度。
    我们已经看出来,线性的delta使动画匀速进行。
    <div onclick="move(this.children[0], linear)" class=''example_path">
      <div class="exmple_block"></div>
    </div>
    

    n次幂函数

    delta函数是progress的n次幂,比较特殊的情况,比如 n = 2n = 3

    例如:

    function quad(progress){
      return Math.pow(progress, 2);
    }
    
    Paste_Image.png

    Circ: a piece of circle

    例如

    function circ(progress){
      return 1 - Math.sin(Math.acos(progess))
    }
    
    Paste_Image.png

    Back: the bow function

    这个函数像一个弓:首先我们先拉弓,然后发射。

    function back(progress, x) {
      return Math.pow(progress, 2) * ((x + 1) * progress - x)
    }
    
    Paste_Image.png

    Bounce

    想象一下,我们放开一个球自由落体,然后反弹几次最后停止。
    这个bounce函数正好和这个效果相反,开始时候'bounce'直到它到达这个目标点。
    如下:

    function bounce(progress) {
      for(var a = 0, b = 1, result; 1; a += b, b /= 2) {
        if (progress >= (7 - 4 * a) / 11) {
          return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2)
        }
      }
    }
    
    

    还有其他的bounce函数。

    Elastic

    这个函数依靠x这个额外的参数,这个参数定义了初始的范围。

    function elastic(progress, x) {
      return Math.pow(2, 10 * (progress-1)) * Math.cos(20*Math.PI*x/3*progress)
    }
    
    
    Paste_Image.png

    反函数(easeIn, easeOut, easeInOut)

    一个javascript框架通常提供一系列的delta,这正向的使用叫做easeIn
    有的时候,我们要求这个动画和时间的进度相反的,这个叫做easeOut
    并且应用通过"time-reversing"delta。

    easeOut

    deltaEaseOut = 1 - delta(1 - progress)
    例如:

    function bounce(progress) {
      for(var a = 0, b = 1, result; 1; a += b, b /= 2) {
        if (progress >= (7 - 4 * a) / 11) {
          return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2);
        }
      }
    }
    
    function makeEaseOut(delta) {  
      return function(progress) {
        return 1 - delta(1 - progress)
      }
    }
    
    var bounceEaseOut = makeEaseOut(bounce)
    
    Paste_Image.png
    easeInOut

    另一个选项是delta影响开始的时候和结束的时候,叫做 easeInOut

    if (progress <= 0.5) { // the first half of the animation)
      return delta(2 * progress) / 2
    } else { // the second half
      return (2 - delta(2 * (1 - progress))) / 2
    }
    
    function makeEaseInOut(delta) {  
      return function(progress) {
        if (progress < .5)
          return delta(2*progress) / 2
        else
          return (2 - delta(2*(1-progress))) / 2
      }
    }
    
    bounceEaseInOut = makeEaseInOut(bounce)
    
    
    Paste_Image.png

    step执行函数

    几乎所有的东西,你都可以animate,除了移动,还有change opaciy, width, height, color...等等其他任何你可以想想的。

    例如改变背景色:

    function highlight(elem) {
      var from = [255,0,0], to = [255,255,255]
      animate({
        delay: 10,
        duration: 1000,
        delta: linear,
        step: function(delta) {
          elem.style.backgroundColor = 'rgb(' +
            Math.max(Math.min(parseInt((delta * (to[0]-from[0])) + from[0], 10), 255), 0) + ',' +
            Math.max(Math.min(parseInt((delta * (to[1]-from[1])) + from[1], 10), 255), 0) + ',' +
            Math.max(Math.min(parseInt((delta * (to[2]-from[2])) + from[2], 10), 255), 0) + ')'
        }
      })  
    }
    
    

    例如利用bounce模仿text type:

    function animateText(textArea) {
      var text = textArea.value
      var to = text.length, from = 0
      
      animate({
        delay: 20,
        duration: 5000,
        delta: bounce,
        step: function(delta) {
          var result = (to-from) * delta + from
          textArea.value = text.substr(0, Math.ceil(result))
        }
      })
    }
    
    

    例如模仿足球掉落:

    var img = document.getElementById('ball')
    var field = document.getElementById('field')
    img.onclick = function() {
      var from = 0
      var to = field.clientHeight - img.clientHeight
      animate({
        delay: 20,
        duration: 1000,
    delta: makeEaseOut(bounce), 
        step: function(delta) {
          img.style.top = to*delta + 'px'
        }
      })
    }
    

    例如模仿足球向左向下掉落:

    img.onclick = function() {
    
      var height  = document.getElementById('field').clientHeight - img.clientHeight
      var width  = 100
      
      animate({
        delay: 20,
        duration: 1000,
        delta: makeEaseOut(bounce), 
        step: function(delta) {
          img.style.top = height*delta + 'px'
        }
      })
      
    animate({
        delay: 20,
        duration: 1000, 
        delta: makeEaseOut(quad),
        step: function(delta) {
          img.style.left = width*delta  + "px"
        }
      })
    }
    

    css 变化(transitions)

    现在大部分现代的浏览器支持css transition, 一种通过css来实现的动画。
    这种动画很简单,设置css transition-duration属性和transition-property属性。
    例如:

    .animated {
      transition-property: background-color;
      transition-duration: 2s;
    }
    
    

    具体例子:

    <style>
    .animated {
      transition: background-color 2s;
      -webkit-transition: background-color 2s;
      -o-transition: background-color 2s;
      -moz-transition: 2s;
    }
    </style>
    <div class="animated" onclick="this.style.backgroundColor='red'">
      <span style="font-size:150%">Click to animate (no IE, no FF<4)</span>
    </div>
    
    

    因为css transition还是一个草案,所以需要加上前缀。
    通常没有浏览器支持没有前缀的tansition属性。

    css transition的一些限制:

    1. css transition 可以设置 delta, 但是只有有限的种类。
    2. 只有css的属性可以操纵,但是好处是多个属性可以一起改变。

    优化的一些建议

    1. 多个timer导致cpu过载。解决方案一次redraw(也就是一个timer中)完成多个 step 动作。
    2. 由于元素在document中的位置越深,计算量越大。解决方案如下:
    • 把该元素提取出来,加到body中,然后position:absolute。
    • 操作它
    • 插回去

    总结

    动画都是通过setInterval来完成的。通常delay在10ms ~ 50ms,在每一个delay中,更新元素的某些属性。
    其实这个不局限在元素上,也可以是别的东西。
    通常的animate框架接受的参数:
    1.delay - 帧之间的间隔
    2.duration - 动画的时间
    3.delta - 时间进度和动画进度的对应关系
    4.step - 真正的动画操作

    请记住:如果你感觉动画卡顿,把多个动画和到一个timer中,或者把元素提取到body 上作为绝对元素来操作。

    相关文章

      网友评论

        本文标题:js 动画二

        本文链接:https://www.haomeiwen.com/subject/uvmllttx.html