第三十七课:动画的原理和设计

js里面最简单的动画原理:在setTimeout或setInterval定时器中,每隔20-30ms改变元素的样式,于是就有了动画。比如:改变宽高,就叫缩放;改变坐标,就叫做位移;改变坐标轴,就叫旋转;改变透明度,就叫做淡入淡出。

css3中有一个transform样式,它的值可以是rotate()旋转,skew()扭曲,scale()缩放,translate()位移,matrix()矩阵。这里不仅支持2D的操作,也支持3D的操作。

我们先举一个小小的例子,来实现一个方块的移动,达到动画的效果。

让一个方块动起来,其实就是改变这个方块的位置。在css中对应元素的left和top样式。要想用left和top,我们还需要让元素相对定位或绝对定位。通常的做法是父元素相对定位,称为包含块,子元素绝对定位。只有定位了,left和top才是可计算的像素值。首先,我们需要取到元素的原始位置,然后让用户传入结束位置,起始位置与结束位置之间的距离,就是我们要一点点操作的变量。动画还涉及到时间,也就是动画执行的总时间,这里的意思就是方块从起始位置到结束位置,总共花了多长时间。动画最重要的一点就是每次变动的相隔时间,这个通常由引擎决定,当然也可以自己设定,我们一般叫它fps。

fps通俗的讲就是一秒内更新多少次画面。一般来说,一秒更新30张画左右,就会有动画的效果。也就是说,一张画停留大概33毫秒(1000/30)。

现在,我们用代码来实现上面的这个例子。我们假设从原始位置到目的位置,总共需要2秒钟(动画总时间),fps为30帧(一秒内更新30张画)。

<style type="text/css">

  #parent{   //父元素

    width:800px;  height: 100px; background:#e8e8ff; position:relative;

  }

  #move{    //移动的元素,也就是做动画的元素

    position:absolute;  left:0px; width:100px; height:100px; background:#a9ea00;

  }

</style>

<script>

  var el = document.getElementById("move");

  var parent = document.getElementById("parent");

  var distance = parent.offsetWidth - el.offsetWidth;   //需要移动的距离

  var begin = 0;    //move元素的开始位置

  var end = begin + distance;   //move元素的目的位置

  var fps = 30;

  var interval = 1000/fps;   //每相隔多少毫秒刷新一次,也就是一张画停留多少毫秒,然后切换下一张画。

  var duration = 2000;

  var times = duration /interval;   //这个动画,总共要刷新多少次,也就是说总共有多少张画要显示。

  var step = distance / times;  //这个动画,每次刷新,要移动多少距离。

  el.onclick = function(){

    var now = new Date();

    var id = setInterval(function(){

      if(begin>=end){

        el.style.left = end + "px";

        clearInterval(id);

      }else{

        begin + = step;   //每次刷新,元素需要移动的距离

        el.style.left = begin + "px";

      }

    },interval);    //每相隔interval就刷新一次画面,也就是移动元素

  }

</script>

上例中,我们使用了最简单的累加来实现。现在我们改写一下,加入进度这个变量,让其具有广泛性。

el.onclick = function(){

    var now = new Date();

    var id = setInterval(function(){

      var t = new Date() - now;   //当前时间减去动画开始的时间,也就是动画执行了多少毫秒

      if(t>=duration){    //如果动画执行的时间大于或等于总时间,就停止

        el.style.left = end + "px";

        clearInterval(id);

      }else{

        var per = t/duration;    //当前动画执行的进度

        el.style.left = begin + per*distance + "px";   //当前的进度乘以总距离,就得到它当前的位置

      }

    },interval);    //每相隔interval就刷新一次画面,也就是移动元素

}

如果我们随意能够控制per这个数值,那么就能轻易的实现加速和减速。于是,人们发明了缓动公式,缓动公式可以让我们很轻松的模拟现实中的加速,减速,弹簧等效果。

现在的缓动公式的命名是有一定的规律的:基本函数:linear(easeNone)匀速,easeIn加速,easeOut减速,easeInOut先加速再减速。

高阶函数与三角函数:Sine表示由三角函数实现,Quad是二次方,Cubic是三次方,Quart是四次方,Quint是五次方,Circ使用开平方根的Math.sqrt,Expo使用开立方根的Math.pow,Elastic则是结合三角函数与开立三方根的初级弹簧效果,Back则使用一个1.70158常数来计算回退效果,Bounce则是高级弹簧效果。

由于,我们一般只使用基本函数,因此熟悉基本函数就OK了,至于高阶函数,了解就行。实现这些缓动公式的库:AS库,jquery.easing.js,mootools库等。

我们根据上面的例子,把缓动公式加入进去:

var bounce = function(per){     //缓动公式

  if(per < (1 / 2.75) ){

    return (7.5625*per*per);

  }else if(per < (2/2.75)){

    return (7.5625 * (per-=(1.5/2.75)) * per + 0.75);

  }

  else if(per < (2.5/2.75)){

    return (7.5625 * (per-=(2.25/2.75)) * per + 0.9375);

  }else{

    return (7.5625 * (per-=(2.625/2.75)) * per + 0.984375);

  }

}

el.onclick = function(){

    var now = new Date();

    var id = setInterval(function(){

      var per = (new Date() - now)/duration;   //当前时间减去动画开始的时间,也就是动画执行了多少毫秒,除以动画执行的总时间,就是当前动画执行的进度(0-1之间)

      if(per>=1){    //如果动画执行的时间大于或等于总时间,就停止

        el.style.left = end + "px";

        clearInterval(id);

      }else{

        el.style.left = begin + bounce(per)*distance + "px";   //当前的进度(这里的进度是通过缓动公式生成的,因此具有缓动公式的效果)乘以总距离,就得到了它当前的位置,然后把元素移动到当前位置。

      }

    },interval);    //每相隔interval就刷新一次画面,也就是移动元素

}

上面的动画,你会发现,当你点击它时,方块到终点后还弹回来,再过去,又弹回来,渐渐的停止。以上的缓动公式不用理解,知道它是个缓动公式就行,关键是掌握缓动公式在动画中的应用。

最后,我们来看一下jQuery的动画API的设计:

animate(properties, duration , easing , complete)

animate(properties, options)

第一种方式,后面的三个参数是可选的,第一个参数是一个属性集的json对象,比如:{width:800px;height:500px},它代表元素,将从原始的width:100和height:100变成width:800和width:500,出现动画效果,至于动画的时长,变换规则(缓动公式),通过后面的参数设置,如果后面没有设置参数,那么将使用jQuery里面默认的值。第二个参数代表动画的时长,第三个参数代表动画使用什么样的缓动公式,第四个参数代表动画执行结束后,执行的回调方法。

第二种方式,第一个参数跟第一种方式是一样的,它的第二个参数是一个json对象,里面大概是这样的{animation-duration:2,animation-timing-function:ease-in-out},通过options这个对象来设置动画的时长,缓动公式等。它跟CSS3的动画设置非常相似。举个例子:

.animate {    //这个animate类名加在上面的那个方块元素中,这个类名也可以是其他名字,比如:.move,只要设置的是那个方块元素就OK了。

  animation-duration:3s;

  animation-name:slidein;

  animation-timing-function:ease-in-out;

  animation-fill-mode:forwards;

}

@keyframes slidein {   //设置这个动画的初始位置和目的位置

  from{  left:0%; background:white;  }

  to{     left:700px; background: red;  }

}

上面的动画,是通过css3来设置的,它总共有两个样式设置,第一个样式规则,用于描述动画所需的时长,缓动公式,动画结束后保留的状态,以及动画的名字。

第二个样式规则,设置动画slidein的关键帧,这里只设置了两个关键帧,实际上我们可以插入更多(通过50%,80%),最开始与结束的帧可以通过from(0%)和to(100%)命名,其实当你用js去获取这个值时,from和to会自动转换成百分数,0%,100%。结束的帧是最重要的,我们必须设置,它对应于jQuery的animate方法的第一个参数,至于最开始的帧,css3的方式,浏览器会自动计算,jQuery的animate方式,animate方法中会用js获取。

jQuery的animate的第二个参数options就对应第一个样式规则。

jQuery的animate方法,里面使用的是一个叫做queue队列的数据结构,目的让作用于同一个元素的动画进行排队,先处理完这个动画,再处理后一个,比如:

$(this).animate({width:300},2000).animate({left:300},2000); 前两秒,宽度从100变成300,然后,后两秒,left从0到300.具体请看:http://www.cnblogs.com/chaojidan/p/4183687.html

下一课,我们将通过源码来分析动画引擎的实现原理

加油!

时间: 2024-10-11 01:50:20

第三十七课:动画的原理和设计的相关文章

NeHe OpenGL教程 第三十七课:卡通映射

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第三十七课:卡通映射 卡通映射: 什么是卡通了,一个轮廓加上少量的几种颜色.使用一维纹理映射,你也可以实现这种效果. 看到人们仍然e-mail我请求在文章中使用我方才在GameDev.net上写的源代码,还看到文章的第二版(在那每一

第三十七课 Spark之Task执行原理及结果

主要内容 1.     Task执行原理流程图 2.     Task执行源码 3.     Task执行结果在Driver端的处理 一.Task在Executor(worker)端执行及返回Driver流程图 图37-1 Driver端与Executor交互图 二.Executor(worker)端执行源码解析 1.接收Driver端发来的消息 当Driver中的SchedulerBackend给ExecutorBackend发送LaunchTask之后,ExecutorBackend在接收到

第三十七课、深度解析QMap与QHash

一.QMap深度解析 1.QMap是一个以升序键顺序存储键值对的数据结构 (1)QMap原型为class QMap<K, T>模板 (2).QMap中的键值对根据key进行了排序 (3).QMap中的key类型必须重载operator <     (小于操作符) 2.QMap使用实例一 3.QMap使用实例二 4.QMap的注意事项 (1).通过key获取Value时 A.当key存在,返回对应的Value B.当key不存在,返回值类型所对应的"零"值 (2).插入

JAVA学习第三十七课(常用对象API)- 集合框架(五)— Set集合:TreeSet集合

一.LinkedHashSet集合 HashSet下有子类LinkedHashSet API文档关于LinkedHashSet的解释: 具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现.此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表.此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代.注意,插入顺序不 受在 set 中重新插入的 元素的影响.(如果在 s.contains(e) 返回 true 后立即调用 s.add(

centos shell编程3【告警系统】 第三十七节课

centos shell编程3[告警系统]  第三十七节课 上半节课 下半节课 整个项目没有任何架构,都是单机的,没有服务器端和客户端的概念只是简单调用一下shell脚本,子shell,通过添加更多的shell脚本扩展功能 mail.sh:做邮件收敛uptime或w 获取load average 需要安装php环境yum install -y php 需求: 使用shell定制各种个性化告警工具,但需要统一化管理.规范化管理. 思路:指定一个脚本包,包含主程序.子程序.配置文件.邮件引擎.输出日

NeHe OpenGL教程 第十七课:2D图像文字

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第十七课:2D图像文字 2D图像文字: 在这一课中,你将学会如何使用四边形纹理贴图把文字显示在屏幕上.你将学会如何把256个不同的文字从一个256x256的纹理图像中分别提取出来,并为每一个文字创建一个显示列表,接着创建一个输出函数

jQuery动画实现原理

前言 jQuery动画是通过animate这个API设置执行的,其内部也是按照每一个animate的划分封装了各自动画组的行为, 包括数据过滤.缓动公式.一些动画默认参数的设置.元素状态的调整.事件的处理通知机制.执行等等 换句话说,我们可以把animate看作一个对象,对象封装自己的一系列属性与方法. jQuery可以支持连续动画,那么animate与animate之间的切换就是通过队列.queue,这个之前就已经详细的解释过了 动画的参数 jQuery的内部的方法都是针对API的处理范围设计

JavaScript动画工作原理之(完结篇)

原作者:Steven Riche 发布时间:2014年2月18日 原文链接:http://code.tutsplus.com/tutorials/javascript-animation-that-works-part-4-of-4--net-35263 翻译:子毅 --------- 将JavaScript进行到底 碎碎两句 折腾了一个多月,杂七杂八的事情加在一起,简直糟透了.博客停了大概有一个月了,从今天起一切都是新的,做好自己就OK了 ---------------------------

写多个物件css3循环动画案例原理

div { background-color: #67CF22; height: 100%; width: 6px; display: inline-block; -webkit-animation: stretchdelay 1.2s infinite ease-in-out; animation: stretchdelay 1.2s infinite ease-in-out; } .spinner .rect2 { -webkit-animation-delay: -1.1s; animat