Home  >  Article  >  Web Front-end  >  基于HTML5 Canvas实现视频破碎重组特效

基于HTML5 Canvas实现视频破碎重组特效

PHP中文网
PHP中文网Original
2017-03-30 13:24:062310browse

  也许你见过HTML5图片破碎动画特效,实现的原理也挺简单的。但是你应该没有见过视频也可以破碎重组,这个HTML5动画就是利用Canvas的相关特性,实现了点击鼠标让视频破碎重组的效果。在视频区域点击鼠标,即可让该区域的视频破碎,然后经过一段时间,破碎的区域又可以重组还原,视觉效果也很棒,非常值得一试。

基于HTML5 Canvas实现视频破碎重组特效

HTML代码

<p 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>
</p>
<p>
<center>
	<p 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!</p>
<canvas id="output" width="1000" height="600" 
onmousedown="dropBomb(event, this)" style="border: 0 none"> </canvas>
</center>
</p>

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(&#39;sourcevid&#39;);
	copycanvas = document.getElementById(&#39;sourcecopy&#39;);
	copy = copycanvas.getContext(&#39;2d&#39;);
	var outputcanvas = document.getElementById(&#39;output&#39;);
	draw = outputcanvas.getContext(&#39;2d&#39;);
	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(&#39;trace&#39;).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>

以上就是基于HTML5 Canvas实现视频破碎重组特效的内容,更多相关内容请关注PHP中文网(www.php.cn)!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn