使用javascript和css模拟帧动画的几种方法浅析
来源:互联网 发布:杭州seo外包 编辑:程序博客网 时间:2024/06/06 01:35
转载地址:http://blog.sina.com.cn/s/blog_830edcf30101mxma.html
我们平时在开发前端页面的时候,经常会播放一段帧序列。这段帧序列就像gif图片那样,反复循环播放。那大家可能会说,直接用gif图片就好了,干嘛还去模拟呢?那是因为要做得更加灵活,我们要做到以下几点:
1、我们希望这段帧动画只循环播放所指定的次数。
2、我们希望帧动画结束的瞬间执行某种操作。这个在游戏中大量存在。
3、我们想自如的控制播放的速度。
4、我们想尽可能让这个帧动画的实现方式兼容大部分浏览器,在移动和pc端都能运行良好。
有了以上四点要求,那就不是gif图片所能完成的了。下面,我们先探讨有哪些技术可以实现我所说的功能。首先我们先准备好一张帧序列图片。如下图所示:
一、使用CSS3动画。
CSS3动画的timing-function里有一个step-end方式,可以不用缓慢过渡,而是直接以跳帧的方式实现变化。这个方式我认为是最省事的办法了,然而在CSS3还未完全兼容的时代,step-end的兼容性更加差。就不说IE,我在智能机的几种基于webkit的低版本浏览器中测试时也发现一些不兼容现象。考虑到css3的普及速度,此种方式依然值得大家学习。具体代码实现参考如下(篇幅考虑仅列出webkit的写法):
<html> <head> <style type="text/css"> #anim{ background-image: url(anim.png); width:120px; height:120px; -webkit-animation: auto-circle 0.5s step-end infinite; } @-webkit-keyframes auto-circle{ 0%{ background-position-x: 0; } 20%{ background-position-x: 120px; } 40%{ background-position-x: 240px; } 60%{ background-position-x: 360px; } 80%{ background-position-x: 480px; } 100%{ background-position-x: 600px; } } </style> </head> <body> <div id="anim"> </div> </body></html>
<html> <head> <style type="text/css"> #animbg{ width:120px; height:120px; overflow: hidden; } #anim{ -webkit-animation: auto-circle 0.5s step-end 0 5; } @-webkit-keyframes auto-circle{ 0%{ -webkit-transform:translate3d(0,0,0); } 20%{ -webkit-transform:translate3d(-120px,0,0); } 40%{ -webkit-transform:translate3d(-240px,0,0); } 60%{ -webkit-transform:translate3d(-360px,0,0); } 80%{ -webkit-transform:translate3d(-480px,0,0); } 100%{ -webkit-transform:translate3d(-600px,0,0); } } </style> </head> <body> <div id="animbg"> <img id="anim" src="anim.png"></div> </div> </body> <script type="text/javascript"> document.addEventListener('webkitAnimationEnd',function(){ document.getElementByIdx_x('animbg').style.display = 'none'; }); </script></html>
最后的js代码中的webkitAnimationEnd就是用来绑定当css动画结束后的动作。
二、使用canvas
说道帧动画,很容易就联想到canvas。用drawImage方法将图片绘制到canvas上面,不断重绘就能得到我们想要的效果。使用canvas的好处是,只要有一个基于canvas模拟帧动画的类库,就可以随意使用。操作js比操作css要灵活,可以传递各种参数实现不同的要求,还可以使用回调函数来设置动画结束时的操作。缺点是老式浏览器不兼容canvas,而且如果需求简单的话,使用canvas有些大材小用。一个最简单的循环动画类如下所示:
function MovieClip(x, y, img, width, height, totalFrame, fps){ this.x = x; this.y = y; this.img = document.getElementByIdx_x(img); this.time = 0; this.frame = 0; this.width = width; this.height = height; this.totalFrame = totalFrame; this.fps = fps || 1;}MovieClip.prototype.draw = function(){ this.time ++; if(this.time % this.fps == 0) { this.frame ++; if(this.frame == this.totalFrame) this.frame = 0; } var frame = this.frame; context.drawImage(this.img, this.frame * 120, 0, 120, 120, this.x, this.y, this.width, this.height);}
这段代码来自于王劲的html5小游戏billd源码,对canvas感兴趣的人可以去看看http://06wjin.sinaapp.com/html5/billd/
我也写了一个简单的操作工具库,可以用来操作canvas元素。代码如下:
(function(){ window['canvasgif'] = { canvas:null,//canvas元素 context:null,//canvas环境 fps:30,//帧频 loopCount:1,//循环次数 tempCount:0,//当前的循环次数,用来计数 img_obj : {//图片信息保存变量 'source': null, 'current': 0, 'total_frames': 0, 'width': 0, 'height': 0 }, init:function(canvas,imgsrc,frames,fps,loopCount,fn){//初始化canvas和图片信息 var me = this; me.canvas = canvas; me.context = canvas.getContext("2d"); me.fps = fps || 30; me.loopCount = loopCount || 1; var img = new Image(); img.src = imgsrc || 'anim.png'; img.onload = function () { me.img_obj.source = img; me.img_obj.total_frames = frames; me.img_obj.width = this.width/frames; me.img_obj.height = this.height; me.loopDraw(fn); } }, draw_anim:function(context,iobj){//绘制单张图片 if (iobj.source != null){ context.drawImage(iobj.source, iobj.current * iobj.width, 0, iobj.width, iobj.height,0, 0, iobj.width, iobj.height); iobj.current = (iobj.current + 1) % iobj.total_frames; //如果不是无限循环,则需要计算当前循环次数 if(this.loopCount != -1 && iobj.current == iobj.total_frames - 1){ this.tempCount++; } } }, render:function(canvas,imgsrc,frames,fps,loopCount,fn){ this.init(canvas,imgsrc,frames,fps,loopCount,fn); }, loopDraw:function(fn){//循环绘制图片 var me = this; var ctx = me.context; var pic = me.img_obj; var width = me.canvas.width,height = me.canvas.height; var intervalid = setInterval((function(){ ctx.clearRect(0,0,width,height); me.draw_anim(ctx,pic); if(me.loopCount != -1 && me.tempCount == me.loopCount){ me.tempCount = 0; clearInterval(intervalid); ctx.clearRect(0,0,width,height); typeof fn == "function" && fn(); } }),1000/this.fps); } } })();
三、使用javascript操作css属性
第三种方法是最保险的方法,因为既不使用css3,也不使用canvas,保证兼容了大部分的浏览器。思路很简单,就是靠javascript不断的改变帧图片的background-position。这里为了方便起见,使用的jquery。代码如下:
<html> <head> <style type="text/css"> #animbg{ background-image: url(anim.png); width:120px; height:120px; background-repeat: no-repeat; } </style> <script type="text/javascript" src="jquery-1.4.4.min.js"></script> <script type="text/javascript"> (function(window){ window.frameAnimation = { anims:(function(){ return function(obj,width,steps,eachtime,times, callback){ var runing = false; var handler = null; //obj,width,steps,eachtime,times定时器 var step = 0; //当前帧 var time = 0; //当前第几轮 var speed = eachtime*1000/steps; //间隔时间 var oneStepWidth = width/steps; function _play(){ if(step >= steps){ step = 0; time++; } if(0 == times || time <times){ obj.css('background-position', -oneStepWidth * step + 'px 0px'); step++; }else{ control.stop(); callback && callback(); } } var control = { start:function(){ if(!runing){ runing = true; step = time = 0; handler = setInterval(_play, speed); } return this; } ,stop:function(restart){ if(runing){ runing = false; if(handler){ clearInterval(handler); handler = null; } if(restart){ obj.css('background-position', '0 0'); step = 0; time = 0; } } } ,dispose:function(){ this.stop(); //console.log('anim dispose'); } }; return control; } })() } })(window); function play(){ var anim = frameAnimation.anims($('#animbg'),720,6,1,0); anim.start(); } </script> </head> <body onload="play()"> <div id="animbg"></div> </body></html>
总结:
三种方法各有优势和劣势。如果明确了浏览器的型号和版本支持css3时,推荐使用第一种方法。如果是为了广泛使用,推荐使用第三种方法。当序列帧很简单的时候,不建议使用canvas来实现功能。
- 使用javascript和css模拟帧动画的几种方法浅析
- 使用javascript和css模拟帧动画的几种方法浅析
- 关于css样式表的的使用和插入css样式表的几种方法
- 原生javascript 获得css样式的几种方法
- UITableView使用reloadData的几种动画方法
- php模拟get和post的几种方法
- JavaScript学习笔记之浅析几种创建对象的方法
- 浅析清除session的几种方法
- 黑马程序员_HTML中CSS使用的几种方法
- 利用CSS和DIV的几种布局方法(1)
- 利用CSS和DIV的几种布局方法(2)
- 利用CSS和DIV的几种布局方法(3)
- 利用CSS和DIV的几种布局方法(4)
- 利用CSS和DIV的几种布局方法(1)
- 利用CSS和DIV的几种布局方法(2)
- 利用CSS和DIV的几种布局方法(3)
- 利用CSS和DIV的几种布局方法(4)
- Html+css+javascript的浅析
- JQuery筛选器全系列介绍
- DefWindowProc WindowProc TranslateMessage PreTranslateMessage
- 关于tableviewHeader盖住cell的问题解决
- spring cron定时器表达式
- Spring MVC之@RequestParam @RequestBody @RequestHeader 等详解
- 使用javascript和css模拟帧动画的几种方法浅析
- Kinect手势识别 - Dollar One算法
- OC语言——把四个十进制三位数存放到一个数组中,然后按升序排序
- iOS开发——加密
- 视频时间戳转换
- Solr配置中文分词器mmseg4j详解
- UICollectionView详解
- MXNet设计和实现简介 a short introduction to mxnet design and implementation
- android实现之高清音频录制编码