JavaScript+html5 canvas實(shí)現(xiàn)圖片破碎重組動(dòng)畫(huà)特效
也許你見(jiàn)過(guò)HTML5圖片破碎動(dòng)畫(huà)特效,實(shí)現(xiàn)的原理也挺簡(jiǎn)單的。但是你應(yīng)該沒(méi)有見(jiàn)過(guò)視頻也可以破碎重組,這個(gè)HTML5動(dòng)畫(huà)就是利用Canvas的相關(guān)特性,實(shí)現(xiàn)了點(diǎn)擊鼠標(biāo)讓視頻破碎重組的效果。在視頻區(qū)域點(diǎn)擊鼠標(biāo),即可讓該區(qū)域的視頻破碎,讓后經(jīng)過(guò)一段時(shí)間后,破碎的區(qū)域又可以重組還原,視覺(jué)效果非常棒。

HTML代碼
<div style="display:none"> <video id="sourcevid" autoplay="true" loop="true"> <source src="BigBuckBunny_640x360.mp4" type="video/mp4"/> <source src="BigBuckBunny_640x360.ogv" type="video/ogg"/> </video> <canvas id="sourcecopy" width="640" height="360"></canvas> </div> <div> <center> <div style="z-index:1;position:relative;text-align:center;font-size:16px;font-weight:bold;width:1000px;top:60px;">Click video to blow it up!</div> <canvas id="output" width="1000" height="600" onmousedown="dropBomb(event, this)" style="border: 0 none"> </canvas> </center> </div>
JavaScript代碼
var video;
var copy;
var copycanvas;
var draw;
var TILE_WIDTH = 32;
var TILE_HEIGHT = 24;
var TILE_CENTER_WIDTH = 16;
var TILE_CENTER_HEIGHT = 12;
var SOURCERECT = {x:0, y:0, width:0, height:0};
var PAINTRECT = {x:0, y:0, width:1000, height:600};
function init(){
video = document.getElementById('sourcevid');
copycanvas = document.getElementById('sourcecopy');
copy = copycanvas.getContext('2d');
var outputcanvas = document.getElementById('output');
draw = outputcanvas.getContext('2d');
setInterval("processFrame()", 33);
}
function createTiles(){
var offsetX = TILE_CENTER_WIDTH+(PAINTRECT.width-SOURCERECT.width)/2;
var offsetY = TILE_CENTER_HEIGHT+(PAINTRECT.height-SOURCERECT.height)/2;
var y=0;
while(y < SOURCERECT.height){
var x=0;
while(x < SOURCERECT.width){
var tile = new Tile();
tile.videoX = x;
tile.videoY = y;
tile.originX = offsetX+x;
tile.originY = offsetY+y;
tile.currentX = tile.originX;
tile.currentY = tile.originY;
tiles.push(tile);
x+=TILE_WIDTH;
}
y+=TILE_HEIGHT;
}
}
var RAD = Math.PI/180;
var randomJump = false;
var tiles = [];
var debug = false;
function processFrame(){
if(!isNaN(video.duration)){
if(SOURCERECT.width == 0){
SOURCERECT = {x:0,y:0,width:video.videoWidth,height:video.videoHeight};
createTiles();
}
//this is to keep my sanity while developing
if(randomJump){
randomJump = false;
video.currentTime = Math.random()*video.duration;
}
//loop
if(video.currentTime == video.duration){
video.currentTime = 0;
}
}
var debugStr = "";
//copy tiles
copy.drawImage(video, 0, 0);
draw.clearRect(PAINTRECT.x, PAINTRECT.y,PAINTRECT.width,PAINTRECT.height);
for(var i=0; i<tiles.length; i++){
var tile = tiles[i];
if(tile.force > 0.0001){
//expand
tile.moveX *= tile.force;
tile.moveY *= tile.force;
tile.moveRotation *= tile.force;
tile.currentX += tile.moveX;
tile.currentY += tile.moveY;
tile.rotation += tile.moveRotation;
tile.rotation %= 360;
tile.force *= 0.9;
if(tile.currentX <= 0 || tile.currentX >= PAINTRECT.width){
tile.moveX *= -1;
}
if(tile.currentY <= 0 || tile.currentY >= PAINTRECT.height){
tile.moveY *= -1;
}
}else if(tile.rotation != 0 || tile.currentX != tile.originX || tile.currentY != tile.originY){
//contract
var diffx = (tile.originX-tile.currentX)*0.2;
var diffy = (tile.originY-tile.currentY)*0.2;
var diffRot = (0-tile.rotation)*0.2;
if(Math.abs(diffx) < 0.5){
tile.currentX = tile.originX;
}else{
tile.currentX += diffx;
}
if(Math.abs(diffy) < 0.5){
tile.currentY = tile.originY;
}else{
tile.currentY += diffy;
}
if(Math.abs(diffRot) < 0.5){
tile.rotation = 0;
}else{
tile.rotation += diffRot;
}
}else{
tile.force = 0;
}
draw.save();
draw.translate(tile.currentX, tile.currentY);
draw.rotate(tile.rotation*RAD);
draw.drawImage(copycanvas, tile.videoX, tile.videoY, TILE_WIDTH, TILE_HEIGHT, -TILE_CENTER_WIDTH, -TILE_CENTER_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
draw.restore();
}
if(debug){
debug = false;
document.getElementById('trace').innerHTML = debugStr;
}
}
function explode(x, y){
for(var i=0; i<tiles.length; i++){
var tile = tiles[i];
var xdiff = tile.currentX-x;
var ydiff = tile.currentY-y;
var dist = Math.sqrt(xdiff*xdiff + ydiff*ydiff);
var randRange = 220+(Math.random()*30);
var range = randRange-dist;
var force = 3*(range/randRange);
if(force > tile.force){
tile.force = force;
var radians = Math.atan2(ydiff, xdiff);
tile.moveX = Math.cos(radians);
tile.moveY = Math.sin(radians);
tile.moveRotation = 0.5-Math.random();
}
}
tiles.sort(zindexSort);
processFrame();
}
function zindexSort(a, b){
return (a.force-b.force);
}
function dropBomb(evt, obj){
var posx = 0;
var posy = 0;
var e = evt || window.event;
if (e.pageX || e.pageY){
posx = e.pageX;
posy = e.pageY;
}else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
var canvasX = posx-obj.offsetLeft;
var canvasY = posy-obj.offsetTop;
explode(canvasX, canvasY);
}
function Tile(){
this.originX = 0;
this.originY = 0;
this.currentX = 0;
this.currentY = 0;
this.rotation = 0;
this.force = 0;
this.z = 0;
this.moveX= 0;
this.moveY= 0;
this.moveRotation = 0;
this.videoX = 0;
this.videoY = 0;
}
/*
getPixel
return pixel object {r,g,b,a}
*/
function getPixel(imageData, x, y){
var data = imageData.data;
var pos = (x + y * imageData.width) * 4;
return {r:data[pos], g:data[pos+1], b:data[pos+2], a:data[pos+3]}
}
/*
setPixel
set pixel object {r,g,b,a}
*/
function setPixel(imageData, x, y, pixel){
var data = imageData.data;
var pos = (x + y * imageData.width) * 4;
data[pos] = pixel.r;
data[pos+1] = pixel.g;
data[pos+2] = pixel.b;
data[pos+3] = pixel.a;
}
/*
copyPixel
faster then using getPixel/setPixel combo
*/
function copyPixel(sImageData, sx, sy, dImageData, dx, dy){
var spos = (sx + sy * sImageData.width) * 4;
var dpos = (dx + dy * dImageData.width) * 4;
dImageData.data[dpos] = sImageData.data[spos]; //R
dImageData.data[dpos+1] = sImageData.data[spos+1]; //G
dImageData.data[dpos+2] = sImageData.data[spos+2]; //B
dImageData.data[dpos+3] = sImageData.data[spos+3]; //A
}
</script>
希望本文所述對(duì)大家學(xué)習(xí)javascript程序設(shè)計(jì)有所幫助。
- 純JavaScript實(shí)現(xiàn)HTML5 Canvas六種特效濾鏡示例
- 教你用幾十行js實(shí)現(xiàn)很炫的canvas交互特效
- js canvas實(shí)現(xiàn)星空連線背景特效
- js canvas實(shí)現(xiàn)隨機(jī)粒子特效
- javascript結(jié)合html5 canvas實(shí)現(xiàn)(可調(diào)畫(huà)筆顏色/粗細(xì)/橡皮)的涂鴉板
- Javascript保存網(wǎng)頁(yè)為圖片借助于html2canvas庫(kù)實(shí)現(xiàn)
- js+canvas實(shí)現(xiàn)滑動(dòng)拼圖驗(yàn)證碼功能
- JavaScript+html5 canvas實(shí)現(xiàn)本地截圖教程
- JS+Canvas 實(shí)現(xiàn)下雨下雪效果
- html5 canvas js(數(shù)字時(shí)鐘)實(shí)例代碼
- js和canvas繪制圓形金屬質(zhì)感特效
相關(guān)文章
JS實(shí)現(xiàn)的漢字與Unicode碼相互轉(zhuǎn)化功能分析
這篇文章主要介紹了JS實(shí)現(xiàn)的漢字與Unicode碼相互轉(zhuǎn)化功能,結(jié)合實(shí)例形式分析了javascript實(shí)現(xiàn)漢字與Unicode碼轉(zhuǎn)換相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-05-05
JavaScript基本語(yǔ)法_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了JavaScript基本語(yǔ)法,適合剛?cè)腴T(mén)的同學(xué),有興趣的可以了解下。2017-06-06
JavaScript實(shí)現(xiàn)Tab欄切換特效
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)Tab欄切換特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
BootStrap實(shí)現(xiàn)帶關(guān)閉按鈕功能
這篇文章主要介紹了BootStrap實(shí)現(xiàn)帶關(guān)閉按鈕功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02
Uncaught?SyntaxError:Unexpected?token?'<'?(
這篇文章主要為大家介紹了JS判斷趨近于直線的多邊形(退化多邊形)實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01

