您的位置:首页 > Web前端 > HTML5

html5烟花绽放效果

2015-10-11 17:09 731 查看


制作效果!!!个人认为很棒



首先来看看html,里面就放了一个canvas对象。

[html] view
plaincopyprint?





<!-- setup our canvas element -->

<canvas id="canvas">Canvas is not supported in your browser.</canvas>

css文件

[css] view
plaincopyprint?





body {

background: #000;

margin: 0;

}

canvas {

cursor: crosshair;

display: block;

}

接着是JS,首先使用“RequestAnimationFrame”实现动画,可以有效解决setTimeout和setInterval的浪费CPU问题。关于RequestAnimationFrame方法的特性和优势,大家可以参考以下几篇文章。

CSS-Tricks上的《Using requestAnimationFrame

Treehouse Blog上的《Efficient Animations with requestAnimationFrame

W3c的候选推荐标准《Timing control for script-based animations

以及Erik Möller提供的polyfill(在旧版浏览器上模拟标准 API 的 JavaScript 补充)。

[javascript] view
plaincopyprint?





// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel

// MIT license

(function() {

var lastTime = 0;

var vendors = ['ms', 'moz', 'webkit', 'o'];

for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {

window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];

window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']

|| window[vendors[x]+'CancelRequestAnimationFrame'];

}

if (!window.requestAnimationFrame)

window.requestAnimationFrame = function(callback, element) {

var currTime = new Date().getTime();

var timeToCall = Math.max(0, 16 - (currTime - lastTime));

var id = window.setTimeout(function() { callback(currTime + timeToCall); },

timeToCall);

lastTime = currTime + timeToCall;

return id;

};

if (!window.cancelAnimationFrame)

window.cancelAnimationFrame = function(id) {

clearTimeout(id);

};

}());

本案例需要两个类烟花沫粒子和烟花。首先来看烟花沫类

[javascript] view
plaincopyprint?





// create particle

function Particle( x, y ) {

this.x = x;

this.y = y;

// track the past coordinates of each particle to create a trail effect, increase the coordinate count to create more prominent trails

this.coordinates = [];

this.coordinateCount = 5;

while( this.coordinateCount-- ) {

this.coordinates.push( [ this.x, this.y ] );

}

// set a random angle in all possible directions, in radians

this.angle = random( 0, Math.PI * 2 );

this.speed = random( 1, 10 );

// friction will slow the particle down

this.friction = 0.95;

// gravity will be applied and pull the particle down

this.gravity = 1;

// set the hue to a random number +-20 of the overall hue variable

this.hue = random( hue - 20, hue + 20 );

this.brightness = random( 50, 80 );

this.alpha = 1;

// set how fast the particle fades out

this.decay = random( 0.015, 0.03 );

}

// update particle

Particle.prototype.update = function( index ) {

// remove last item in coordinates array

this.coordinates.pop();

// add current coordinates to the start of the array

this.coordinates.unshift( [ this.x, this.y ] );

// slow down the particle

this.speed *= this.friction;

// apply velocity

this.x += Math.cos( this.angle ) * this.speed;

this.y += Math.sin( this.angle ) * this.speed + this.gravity;

// fade out the particle

this.alpha -= this.decay;

// remove the particle once the alpha is low enough, based on the passed in index

if( this.alpha <= this.decay ) {

particles.splice( index, 1 );

}

}

// draw particle

Particle.prototype.draw = function() {

ctx. beginPath();

// move to the last tracked coordinates in the set, then draw a line to the current x and y

ctx.moveTo( this.coordinates[ this.coordinates.length - 1 ][ 0 ], this.coordinates[ this.coordinates.length - 1 ][ 1 ] );

ctx.lineTo( this.x, this.y );

ctx.strokeStyle = 'hsla(' + this.hue + ', 100%, ' + this.brightness + '%, ' + this.alpha + ')';

ctx.stroke();

}

生成粒子的函数

[javascript] view
plaincopyprint?





// create particle group/explosion

function createParticles( x, y ) {

// increase the particle count for a bigger explosion, beware of the canvas performance hit with the increased particles though

var particleCount = 30;

while( particleCount-- ) {

particles.push( new Particle( x, y ) );

}

}

烟花类

[javascript] view
plaincopyprint?





// create firework

function Firework( sx, sy, tx, ty ) {

// actual coordinates

this.x = sx;

this.y = sy;

// starting coordinates

this.sx = sx;

this.sy = sy;

// target coordinates

this.tx = tx;

this.ty = ty;

// distance from starting point to target

this.distanceToTarget = calculateDistance( sx, sy, tx, ty );

this.distanceTraveled = 0;

// track the past coordinates of each firework to create a trail effect, increase the coordinate count to create more prominent trails

this.coordinates = [];

this.coordinateCount = 3;

// populate initial coordinate collection with the current coordinates

while( this.coordinateCount-- ) {

this.coordinates.push( [ this.x, this.y ] );

}

this.angle = Math.atan2( ty - sy, tx - sx );

this.speed = 2;

this.acceleration = 1.05;

this.brightness = random( 50, 70 );

// circle target indicator radius

this.targetRadius = 1;

}

// update firework

Firework.prototype.update = function( index ) {

// remove last item in coordinates array

this.coordinates.pop();

// add current coordinates to the start of the array

this.coordinates.unshift( [ this.x, this.y ] );

// cycle the circle target indicator radius

if( this.targetRadius < 8 ) {

this.targetRadius += 0.3;

} else {

this.targetRadius = 1;

}

// speed up the firework

this.speed *= this.acceleration;

// get the current velocities based on angle and speed

var vx = Math.cos( this.angle ) * this.speed,

vy = Math.sin( this.angle ) * this.speed;

// how far will the firework have traveled with velocities applied?

this.distanceTraveled = calculateDistance( this.sx, this.sy, this.x + vx, this.y + vy );

// if the distance traveled, including velocities, is greater than the initial distance to the target, then the target has been reached

if( this.distanceTraveled >= this.distanceToTarget ) {

createParticles( this.tx, this.ty );

// remove the firework, use the index passed into the update function to determine which to remove

fireworks.splice( index, 1 );

} else {

// target not reached, keep traveling

this.x += vx;

this.y += vy;

}

}

// draw firework

Firework.prototype.draw = function() {

ctx.beginPath();

// move to the last tracked coordinate in the set, then draw a line to the current x and y

ctx.moveTo( this.coordinates[ this.coordinates.length - 1][ 0 ], this.coordinates[ this.coordinates.length - 1][ 1 ] );

ctx.lineTo( this.x, this.y );

ctx.strokeStyle = 'hsl(' + hue + ', 100%, ' + this.brightness + '%)';

ctx.stroke();

ctx.beginPath();

// draw the target for this firework with a pulsing circle

ctx.arc( this.tx, this.ty, this.targetRadius, 0, Math.PI * 2 );

ctx.stroke();

}

定义好了主要的类,我们来设置一些常见的变量和函数。

[javascript] view
plaincopyprint?





// now we will setup our basic variables for the demo

var canvas = document.getElementById( 'canvas' ),

ctx = canvas.getContext( '2d' ),

// full screen dimensions

cw = window.innerWidth,

ch = window.innerHeight,

// firework collection

fireworks = [],

// particle collection

particles = [],

// starting hue

hue = 120,

// when launching fireworks with a click, too many get launched at once without a limiter, one launch per 5 loop ticks

limiterTotal = 5,

limiterTick = 0,

// this will time the auto launches of fireworks, one launch per 80 loop ticks

timerTotal = 80,

timerTick = 0,

mousedown = false,

// mouse x coordinate,

mx,

// mouse y coordinate

my;

// set canvas dimensions

canvas.width = cw;

canvas.height = ch;

// now we are going to setup our function placeholders for the entire demo

// get a random number within a range

function random( min, max ) {

return Math.random() * ( max - min ) + min;

}

// calculate the distance between two points

function calculateDistance( p1x, p1y, p2x, p2y ) {

var xDistance = p1x - p2x,

yDistance = p1y - p2y;

return Math.sqrt( Math.pow( xDistance, 2 ) + Math.pow( yDistance, 2 ) );

}

不断释放烟花的函数,需要利用RequestAnimationFrame不断地执行函数。

[javascript] view
plaincopyprint?





// main demo loop

function loop() {

// this function will run endlessly with requestAnimationFrame

requestAnimFrame( loop );

// increase the hue to get different colored fireworks over time

hue += 0.5;

// normally, clearRect() would be used to clear the canvas

// we want to create a trailing effect though

// setting the composite operation to destination-out will allow us to clear the canvas at a specific opacity, rather than wiping it entirely

ctx.globalCompositeOperation = 'destination-out';

// decrease the alpha property to create more prominent trails

ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';

ctx.fillRect( 0, 0, cw, ch );

// change the composite operation back to our main mode

// lighter creates bright highlight points as the fireworks and particles overlap each other

ctx.globalCompositeOperation = 'lighter';

// loop over each firework, draw it, update it

var i = fireworks.length;

while( i-- ) {

fireworks[ i ].draw();

fireworks[ i ].update( i );

}

// loop over each particle, draw it, update it

var i = particles.length;

while( i-- ) {

particles[ i ].draw();

particles[ i ].update( i );

}

// launch fireworks automatically to random coordinates, when the mouse isn't down

if( timerTick >= timerTotal ) {

if( !mousedown ) {

// start the firework at the bottom middle of the screen, then set the random target coordinates, the random y coordinates will be set within the range of the top half of the screen

fireworks.push( new Firework( cw / 2, ch, random( 0, cw ), random( 0, ch / 2 ) ) );

timerTick = 0;

}

} else {

timerTick++;

}

// limit the rate at which fireworks get launched when mouse is down

if( limiterTick >= limiterTotal ) {

if( mousedown ) {

// start the firework at the bottom middle of the screen, then set the current mouse coordinates as the target

fireworks.push( new Firework( cw / 2, ch, mx, my ) );

limiterTick = 0;

}

} else {

limiterTick++;

}

}

绑定鼠标事件

[javascript] view
plaincopyprint?





// mouse event bindings

// update the mouse coordinates on mousemove

canvas.addEventListener( 'mousemove', function( e ) {

mx = e.pageX - canvas.offsetLeft;

my = e.pageY - canvas.offsetTop;

});

// toggle mousedown state and prevent canvas from being selected

canvas.addEventListener( 'mousedown', function( e ) {

e.preventDefault();

mousedown = true;

});

canvas.addEventListener( 'mouseup', function( e ) {

e.preventDefault();

mousedown = false;

});

在窗口加载完毕,单击鼠标前,我们也需要一些烟花

[javascript] view
plaincopyprint?





// once the window loads, we are ready for some fireworks!

window.onload = loop;

完毕。

---------------------------------------------------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: