声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢!
几天前同事给我看了一个特效,是一个拼图游戏,不同的是,拼图里的是动画。他让我看下做个DEMO,于是就自己整了一会,也确实不难。用canvas很容易做。所以这篇博文不适合高手看。。。。就是随便写来玩玩的。
效果图:。。。至少我刚看到这个的时候觉得挺新颖的,所以才会想到做出来玩玩,觉得楼主out的哥们请轻喷
不多说,先上DEMO:视频拼图 (或许要等一会才能看到效果,我是直接在w3school那里搞了个视频链接过来的,拖动什么的都做的很简单,或许还有些bug,毕竟就只是做一个DEMO玩玩而已,说说原理就行了),还有一点,直接把视频的当前帧画到canvas中在移动设备上好像还不支持。。。至少我用ipad看了一下,发现画不上去,如果有知道肿么解决这问题的大牛请为小弟解答一下,不甚感激
原理:每一块拼图就是一个canvas,同时还需要一个离屏canvas。先整一个video标签
<video id="video" src="http://www.w3school.com.cn/example/html5/mov_bbb.mp4" width="600px" height="400px" controls="control" loop="loop" style="display:block;position:absolute;top:-6000px;"></video>
并且把video隐藏掉,然后播放视频的时候把每一帧都画到离屏canvas中(离屏canvas就是隐藏了的canvas,用于保存数据),写法很简单:
ctx.drawImage(video , 0 , 0 , vw , vh);
,直接用drawImage方法画上去就行了。为何要先用离屏canvas呢,因为如果直接把每一帧数据同时画到所有拼图块的canvas中,浏览器会瞬间崩掉。所以用一个离屏canvas作为缓冲。先把当前帧的数据保存到canvas,然后再将canvas画到作为拼图块的canvas中。将canvas画到canvas中也很简单,也是用drawImage就可以搞定:
ctx2.drawImage(cs , -this.cols*this.w , -this.rows*this.h , vw , vh);
然后。。。。原理就这么简单,之后提醒一点,用requestAnimationFrame循环取帧时,要限一下速,例如下面所写的,我是每30毫秒取一次,推荐30~50毫秒,太低浏览器容易崩溃,太高的话视频出现卡帧现象了:
1 function animate(){ 2 var newTime = new Date(); 3 if(newTime - lastTime > 30){ 4 lastTime = newTime; 5 ctx.drawImage(video , 0 , 0 , vw , vh); 6 canvases.forEach(function(){ 7 var ctx2 = this.cas.getContext('2d'); 8 ctx2.drawImage(cs , -this.cols*this.w , -this.rows*this.h , vw , vh); 9 }); 10 } 11 if("requestAnimationFrame" in window){ 12 requestAnimationFrame(animate); 13 } 14 else if("webkitRequestAnimationFrame" in window){ 15 webkitRequestAnimationFrame(animate); 16 } 17 else if("msRequestAnimationFrame" in window){ 18 msRequestAnimationFrame(animate); 19 } 20 else if("mozRequestAnimationFrame" in window){ 21 mozRequestAnimationFrame(animate); 22 } 23 }
最后贴出所有代码:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> 5 <style> 6 body{margin:0;padding:0;} 7 .allCanvas{ 8 position: relative; 9 margin:50px auto; 10 600px; 11 } 12 .vcanvas{ 13 position: absolute; 14 display: block; 15 border: 1px solid; 16 } 17 </style> 18 <title>视频拼图</title> 19 </head> 20 <body> 21 <div class="allCanvas"> 22 <canvas id="liping" width="600" height="400" style="display:none"></canvas> 23 </div> 24 <video id="video" src="http://www.w3school.com.cn/example/html5/mov_bbb.mp4" width="600px" height="400px" controls="control" loop="loop" style="display:block;position:absolute;top:-6000px;"></video> 25 <script> 26 var video = document.getElementById("video"); 27 var cs = document.getElementById("liping"); 28 var ctx = cs.getContext('2d') 29 var rows = 3, 30 cols = 3, 31 cb = document.querySelector(".allCanvas"), 32 vw = 600, 33 vh = 400, 34 canvases = []; 35 36 function createCanvas(){ 37 var num = rows*cols; 38 for(var i=0;i<cols;i++){ 39 for(var j=0;j<rows;j++){ 40 var canvas = new vCanvas(Math.random()*600, Math.random()*600 , vw/rows , vh/cols , j , i); 41 canvases.push(canvas); 42 } 43 } 44 } 45 46 var vCanvas = function(x,y,w,h,cols,rows){ 47 this.x = x; 48 this.y = y; 49 this.w = w; 50 this.h = h; 51 this.cols = cols; 52 this.rows = rows; 53 this.creat(); 54 this.behavior(); 55 } 56 vCanvas.prototype = { 57 creat:function(){ 58 this.cas = document.createElement("canvas"); 59 cb.appendChild(this.cas); 60 this.cas.className = "vcanvas"; 61 this.cas.id = "vc_"+(this.cols+1)*(this.rows+1); 62 this.cas.style.left = this.x+"px"; 63 this.cas.style.top = this.y+"px"; 64 this.cas.width = this.w; 65 this.cas.height = this.h; 66 }, 67 behavior:function(){ 68 this.cas.onmousedown = function(e){ 69 e = e || window.event; 70 var that = this; 71 var om = { 72 x:e.clientX, 73 y:e.clientY 74 } 75 window.onmousemove = function(e){ 76 e = e || window.event; 77 var nm = { 78 x:e.clientX, 79 y:e.clientY 80 } 81 that.style.left = parseInt(that.style.left.replace("px","")) + (nm.x-om.x) + "px"; 82 that.style.top = parseInt(that.style.top.replace("px","")) + (nm.y-om.y) + "px"; 83 om = nm; 84 } 85 window.onmouseup = function(){ 86 this.onmousemove = null; 87 } 88 } 89 } 90 } 91 92 Array.prototype.forEach = function(callback){ 93 for(var i=0;i<this.length;i++){ 94 callback.call(this[i]); 95 } 96 } 97 98 var lastTime = 0; 99 function initAnimate(){ 100 lastTime = new Date(); 101 createCanvas(); 102 animate(); 103 } 104 105 function animate(){ 106 var newTime = new Date(); 107 if(newTime - lastTime > 30){ 108 lastTime = newTime; 109 ctx.drawImage(video , 0 , 0 , vw , vh); 110 canvases.forEach(function(){ 111 var ctx2 = this.cas.getContext('2d'); 112 ctx2.drawImage(cs , -this.cols*this.w , -this.rows*this.h , vw , vh); 113 }); 114 } 115 if("requestAnimationFrame" in window){ 116 requestAnimationFrame(animate); 117 } 118 else if("webkitRequestAnimationFrame" in window){ 119 webkitRequestAnimationFrame(animate); 120 } 121 else if("msRequestAnimationFrame" in window){ 122 msRequestAnimationFrame(animate); 123 } 124 else if("mozRequestAnimationFrame" in window){ 125 mozRequestAnimationFrame(animate); 126 } 127 } 128 129 video.play(); 130 initAnimate(); 131 </script> 132 </body> 133 </html>