通常,框架会为你处理动画。但是,你可能想知道仅仅用 javascript 怎么来实现动画,和可能出现的一些问题。理解这项技术对于创建复杂的动画是很有帮助的,即使在在框架的帮助下。
javascript 的动画是通过周期性的改变 DOM 元素的 style 或者 canvas 的对象。
这整个的动画过程被分成了很小的碎片,每一个碎片被定时器调用。因为定时器的周期非常短,所以动画看起来是连续的。
伪代码:
- var id = setInterval(function() {
- /*当前显示帧*/
- if (
- /*完成*/
- ) clearInterval(id)
- },
- 10)
上面代码每一帧的间隔是 10ms ,意味着每秒钟有 100 帧。
在大多数的 javascript 框架中 10-15ms 的 delay 是默认的。越短的延时让动画看起来更加流畅,但是只有在浏览器足够快的时候,每一步的动画才会准时运行。
如果动画需要许多计算,CPU 可能会 100% 的负载,动画就会变得迟缓。这种情况下,delay 就应该被增加。例如,delay 40ms 就是每秒 25 帧,接近 24 帧的电影标准。
我们使用 , 而不是递归的使用 , 是因为我们想要一帧一个 delay,而不是所有帧之间有一个固定的 delay. 查阅 来了解 和递归的 之间到底有什么不同。(译者:经测试最新的 chrome > 56 中,setInterval 的行为跟本文中描述的不同。当函数执行时间超过了 delay 时间,下一个函数不会马上运行,仍然会等一个 delay 的间隔,再执行。但本文仍有参考价值)
例如,一个元素移动通过改变 从 0 到 100px。每 10ms 改变 1px。
- <html>
- <head>
- <link type="text/CSS" rel="stylesheet" href="/files/tutorial/browser/animatio/animate.css">
- <script>
- function move(elem) {
- var left = 0;
- function frame() {
- left++ // 更新参数
- elem.style.left = left + 'px' // 显示帧
- if (left === 100) //检查结束条件
- clearInterval(id)
- }
- var id = setInterval(frame, 10) //没10ms绘制一次
- }
- </script>
- </head>
- <body>
- <div onclick="move(this.children[0])" class="example_path">
- <div class="example_block">
- </div>
- </div>
- </body>
- </html>
为了让动画更加通用,我们介绍下面的一些参数:
当动画开始的时候,我们也可以用:
从 0 到动画 (duration) 结束. 但是偶尔可能会超过结束时间,因为浏览器的计时器并不准确。
例如,progress 的值为 0.5 就是说动画时间 (duration) 已经过去了一半。
例如,我们让高度属性从 0% 变化到 100%。
我们可以让动画均匀的显示,这样动画进度看起来就是线性的。
Mapping:
->progress = 0 -> height = 0%
->progress = 0.2 -> height = 20%
->progress = 0.5->height = 50%
->progress = 0.8 -> height = 80%
->progress = 1 -> height = 100%
但是我们可能想让动画缓慢的开始然后再加速。这样的话经过一半的动画时间高度可能只有 25%
,然后逐渐加速到 100%。
Mapping:
->progress = 0 -> height = 0%
->progress = 0.2 -> height = 4%
->progress = 0.5->height = 25%
->progress = 0.8 -> height = 64%
->progress = 1 -> height = 100%
delta(progress) 是一个映射动画进度增量的函数
动画进度不是一个高度,而是一个数字,通常在 0 到 1 之间。
这篇文章会用一些例子进一步讨论几种增量函数
它计算出增量的结果并且应用它。
对于这个高度的例子,他们可能是:
- function state(delta) {
- elem.style.height = 100*delta + "%"
- }
到现在为止几个重要的参数是:
->delay 是 setInterval 的第二个参数。
->duration 是动画完成需要的时间。
->progress 是动画已经经过的时间,除以 duration 使它的值在 0 到 1 之间。
->delta 通过当前的时间,计算当前的动画进度。
->step 做了视觉上 (?) 的工作。它获得当前的动画进度,并且把它应用在元素上。
让我们把上面讨论的简单的写成一个可扩展的动画核心。
下面的动画函数执行时间管理并且把工作分配给 delta 和 step:
- function animate(opts) {
- var start = new Date;
- var id = setInterval(function(){
- var timePassed = new Date - start;
- var progress = timePassed / opts.duration;
- if(progress > 1) progress = 1;
- var delta = opts.delta(progress)
- opts.step(delta)
- if(progress == 1) {
- clearInterval(id)
- }
- }, opts.delay || 10)
- }
参数对象应该包含以下的一些动画属性:
->delay
->duration
->function delta
->function step
这个算法完全遵循上面的描述
让我们基于这个来创建一个移动的动画
- function move(element, delta, duration){
- var to = 500;
- animate({
- delay: 10,
- duration: duration || 1000,
- delta: delta,
- step: function(delta){
- element.style.left = to * delta + 'px'
- }
- })
- }
它把工作指派给 animate , 给 animate 传入了 delay, 用户提供的 duration, delta, 和 step。
delta = function(p) {return p}
意味着动画进程一直是均匀的
step
用一个简单的公式映射 0..1,delta 返回一个进度值 0..to。把这些结果应用到 element.style.left。
用法:
- <div onclick="move(this.children[0], function(p) {return p})"
- class="example_path">
- <div class="example_block"></div>
- </div>
动画就是是根据给定的规则,一直改变属性。在 javascript 动画中,这个规则就是 delta 函数来实现的。
不同的 deltas 使动画的速度,加速度和其他的参数表现出各种各样的方式。
数学公式通常被用在这里。但是它们对于只做 web 编程和忘记学校里的数学的人来说,可能很陌生。在这个章节,我们将浏览很多的受欢迎的公式并看一下它们是如何工作的。
动画运动的例子,提供不同的 delta.
线性 delta
- function linear(progress){
- return progress;
- }
水平方向指的是时间进度,垂直方向指的是动画进程。
我们已经能看见了。线性的 delta 使动画以固定的速度进行。
Power of n
也是一个简单的例子。delta 是 progress 的 n 次方。例如 4 次,3 次函数等。
例如 2 次函数
- function quad(progress) {
- return Math.pow(progress, 2)
- }
图形
增加加速度的影响。例如,下面这个图片是 5 次方。
Circ: 圆的一部分
函数:
- function circ(progress) {
- return 1 - Math.sin(Math.acos(progress))
- }
图像
Back: the bow function
这个函数向弓一样工作:首先我们 "拉开工,然后发射出去"。
不像先前的函数,它会依赖于一个附加的参数 , 这就是 "弹性系数"。
它定义了 "拉弓" 的距离。
代码是:
- function back(progress, x) {
- return Math.pow(progress, 2) * ((x + 1) * progress - x)
- }
图像 x=1.5
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)
- }
- }
- }
* 这段代码曲子 MooTools.FX.Transitions. 据我所知,仍然有其他实现 bounce 的算法。
Elastic 弹性
这个函数也依赖于额外的参数 x,x 定义了初始范围。
- function elastic(progress, x){
- return Math.pow(2, 10 * (progress - 1)) * Math.cos(20 * Math.PI * x/3 *progress)
- }
在这个例子中,为了让动画更加平滑,时间是 2s.
反向函数(Reverse functions)
一个 javascript 框架经常会提供的一种 delta 函数。
它们的直接使用被称作 easeIn.
偶尔的时候,需要以时间倒退的方式来展示动画。这就叫做 被'time-reversing'delta 来实现。
第一次翻译点东西,质量不好,主要是做记录用。里面有很多比较'术语'的,不好翻,最好看原文。后面我也会继续修改。
来源: http://www.open-open.com/lib/view/open1488677809219.html