js 动画二

这一篇是接着上一篇 翻译。原文点击
上一篇主要讲了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 上作为绝对元素来操作。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容

  • 实现鼠标移动改变图片的透明度 所用知识:透明度属性:opacitysetInterval()方法:设置时间函数 实...
    大海孤了岛阅读 227评论 0 0
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,274评论 25 707
  • 只愿一人无拘无忧 无惧无愁 只愿一生长安长乐 不思离愁
    姚小玘阅读 1,268评论 0 0
  • duiwe对象的基本特征之一就是封装---对外部世界隐藏其内部细节.封装往往伴随着委托. 比如你问你的主管是否有时...
    rxdxxxx阅读 445评论 0 0
  • 很开心今天比平日早起了两小时。 给自己放假把这两小时用来看综艺然而却一发不可收拾收拾。 好容易关掉综艺打开PPT打...
    錦一阅读 201评论 0 0