小编给大家分享一下怎么使用canvas实现烟花特效,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
canvas可以实现不同动画效果,本文主要记录几种不同节日烟花效果实现。
实现一
html
css
body{
background:#000;
margin:0;
}
canvas{
cursor:crosshair;
display:block;
}
js
//whenanimatingoncanvas,itisbesttouserequestAnimationFrameinsteadofsetTimeoutorsetInterval
//notsupportedinallbrowsersthoughandsometimesneedsaprefix,soweneedashim
window.requestAnimFrame=(function(){
returnwindow.requestAnimationFrame||
window.webkitRequestAnimationFrame||
window.mozRequestAnimationFrame||
function(callback){
window.setTimeout(callback,1000/60);
};
})();
//nowwewillsetupourbasicvariablesforthedemo
varcanvas=document.getElementById('canvas'),
ctx=canvas.getContext('2d'),
//fullscreendimensions
cw=window.innerWidth,
ch=window.innerHeight,
//fireworkcollection
fireworks=[],
//particlecollection
particles=[],
//startinghue
hue=120,
//whenlaunchingfireworkswithaclick,toomanygetlaunchedatoncewithoutalimiter,onelaunchper5loopticks
limiterTotal=5,
limiterTick=0,
//thiswilltimetheautolaunchesoffireworks,onelaunchper80loopticks
timerTotal=80,
timerTick=0,
mousedown=false,
//mousexcoordinate,
mx,
//mouseycoordinate
my;
//setcanvasdimensions
canvas.width=cw;
canvas.height=ch;
//nowwearegoingtosetupourfunctionplaceholdersfortheentiredemo
//getarandomnumberwithinarange
functionrandom(min,max){
returnMath.random()*(max-min)+min;
}
//calculatethedistancebetweentwopoints
functioncalculateDistance(p1x,p1y,p2x,p2y){
varxDistance=p1x-p2x,
yDistance=p1y-p2y;
returnMath.sqrt(Math.pow(xDistance,2)+Math.pow(yDistance,2));
}
//createfirework
functionFirework(sx,sy,tx,ty){
//actualcoordinates
this.x=sx;
this.y=sy;
//startingcoordinates
this.sx=sx;
this.sy=sy;
//targetcoordinates
this.tx=tx;
this.ty=ty;
//distancefromstartingpointtotarget
this.distanceToTarget=calculateDistance(sx,sy,tx,ty);
this.distanceTraveled=0;
//trackthepastcoordinatesofeachfireworktocreateatraileffect,increasethecoordinatecounttocreatemoreprominenttrails
this.coordinates=[];
this.coordinateCount=3;
//populateinitialcoordinatecollectionwiththecurrentcoordinates
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);
//circletargetindicatorradius
this.targetRadius=1;
}
//updatefirework
Firework.prototype.update=function(index){
//removelastitemincoordinatesarray
this.coordinates.pop();
//addcurrentcoordinatestothestartofthearray
this.coordinates.unshift([this.x,this.y]);
//cyclethecircletargetindicatorradius
if(this.targetRadius<8){
this.targetRadius+=0.3;
}else{
this.targetRadius=1;
}
//speedupthefirework
this.speed*=this.acceleration;
//getthecurrentvelocitiesbasedonangleandspeed
varvx=Math.cos(this.angle)*this.speed,
vy=Math.sin(this.angle)*this.speed;
//howfarwillthefireworkhavetraveledwithvelocitiesapplied?
this.distanceTraveled=calculateDistance(this.sx,this.sy,this.x+vx,this.y+vy);
//ifthedistancetraveled,includingvelocities,isgreaterthantheinitialdistancetothetarget,thenthetargethasbeenreached
if(this.distanceTraveled>=this.distanceToTarget){
createParticles(this.tx,this.ty);
//removethefirework,usetheindexpassedintotheupdatefunctiontodeterminewhichtoremove
fireworks.splice(index,1);
}else{
//targetnotreached,keeptraveling
this.x+=vx;
this.y+=vy;
}
}
//drawfirework
Firework.prototype.draw=function(){
ctx.beginPath();
//movetothelasttrackedcoordinateintheset,thendrawalinetothecurrentxandy
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();
//drawthetargetforthisfireworkwithapulsingcircle
ctx.arc(this.tx,this.ty,this.targetRadius,0,Math.PI*2);
ctx.stroke();
}
//createparticle
functionParticle(x,y){
this.x=x;
this.y=y;
//trackthepastcoordinatesofeachparticletocreateatraileffect,increasethecoordinatecounttocreatemoreprominenttrails
this.coordinates=[];
this.coordinateCount=5;
while(this.coordinateCount--){
this.coordinates.push([this.x,this.y]);
}
//setarandomangleinallpossibledirections,inradians
this.angle=random(0,Math.PI*2);
this.speed=random(1,10);
//frictionwillslowtheparticledown
this.friction=0.95;
//gravitywillbeappliedandpulltheparticledown
this.gravity=1;
//setthehuetoarandomnumber+-20oftheoverallhuevariable
this.hue=random(hue-20,hue+20);
this.brightness=random(50,80);
this.alpha=1;
//sethowfasttheparticlefadesout
this.decay=random(0.015,0.03);
}
//updateparticle
Particle.prototype.update=function(index){
//removelastitemincoordinatesarray
this.coordinates.pop();
//addcurrentcoordinatestothestartofthearray
this.coordinates.unshift([this.x,this.y]);
//slowdowntheparticle
this.speed*=this.friction;
//applyvelocity
this.x+=Math.cos(this.angle)*this.speed;
this.y+=Math.sin(this.angle)*this.speed+this.gravity;
//fadeouttheparticle
this.alpha-=this.decay;
//removetheparticleoncethealphaislowenough,basedonthepassedinindex
if(this.alpha<=this.decay){
particles.splice(index,1);
}
}
//drawparticle
Particle.prototype.draw=function(){
ctx.beginPath();
//movetothelasttrackedcoordinatesintheset,thendrawalinetothecurrentxandy
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();
}
//createparticlegroup/explosion
functioncreateParticles(x,y){
//increasetheparticlecountforabiggerexplosion,bewareofthecanvasperformancehitwiththeincreasedparticlesthough
varparticleCount=30;
while(particleCount--){
particles.push(newParticle(x,y));
}
}
//maindemoloop
functionloop(){
//thisfunctionwillrunendlesslywithrequestAnimationFrame
requestAnimFrame(loop);
//increasethehuetogetdifferentcoloredfireworksovertime
hue+=0.5;
//normally,clearRect()wouldbeusedtoclearthecanvas
//wewanttocreateatrailingeffectthough
//settingthecompositeoperationtodestination-outwillallowustoclearthecanvasataspecificopacity,ratherthanwipingitentirely
ctx.globalCompositeOperation='destination-out';
//decreasethealphapropertytocreatemoreprominenttrails
ctx.fillStyle='rgba(0,0,0,0.5)';
ctx.fillRect(0,0,cw,ch);
//changethecompositeoperationbacktoourmainmode
//lightercreatesbrighthighlightpointsasthefireworksandparticlesoverlapeachother
ctx.globalCompositeOperation='lighter';
vartext="HAPPYNEWYEAR!";
ctx.font="50pxsans-serif";
vartextData=ctx.measureText(text);
ctx.fillStyle="rgba("+parseInt(random(0,255))+","+parseInt(random(0,255))+","+parseInt(random(0,
255))+",0.3)";
ctx.fillText(text,cw/2-textData.width/2,ch/2);
//loopovereachfirework,drawit,updateit
vari=fireworks.length;
while(i--){
fireworks[i].draw();
fireworks[i].update(i);
}
//loopovereachparticle,drawit,updateit
vari=particles.length;
while(i--){
particles[i].draw();
particles[i].update(i);
}
//launchfireworksautomaticallytorandomcoordinates,whenthemouseisn'tdown
if(timerTick>=timerTotal){
if(!mousedown){
//startthefireworkatthebottommiddleofthescreen,thensettherandomtargetcoordinates,therandomycoordinateswillbesetwithintherangeofthetophalfofthescreen
for(varh=0;h<50;h++){
fireworks.push(newFirework(cw/2,ch/2,random(0,cw),random(0,ch)));
}
timerTick=0;
}
}else{
timerTick++;
}
//limittherateatwhichfireworksgetlaunchedwhenmouseisdown
if(limiterTick>=limiterTotal){
if(mousedown){
//startthefireworkatthebottommiddleofthescreen,thensetthecurrentmousecoordinatesasthetarget
fireworks.push(newFirework(cw/2,ch/2,mx,my));
limiterTick=0;
}
}else{
limiterTick++;
}
}
//mouseeventbindings
//updatethemousecoordinatesonmousemove
canvas.addEventListener('mousemove',function(e){
mx=e.pageX-canvas.offsetLeft;
my=e.pageY-canvas.offsetTop;
});
//togglemousedownstateandpreventcanvasfrombeingselected
canvas.addEventListener('mousedown',function(e){
e.preventDefault();
mousedown=true;
});
canvas.addEventListener('mouseup',function(e){
e.preventDefault();
mousedown=false;
});
//oncethewindowloads,wearereadyforsomefireworks!
window.onload=loop;
实现二
html
2018
css
html,
body{
padding:0px;
margin:0px;
background:#222;
font-family:'Karla',sans-serif;
color:#FFF;
height:100%;
overflow:hidden;
}
h2{
z-index:1000;
position:fixed;
top:50%;
left:50%;
transform:translateX(-50%)translateY(-100%);
font-size:58px;
overflow:hidden;
}
span{
position:relative;
display:inline-block;
animation:drop0.75sease0s;
}
canvas{
width:100%;
height:100%;
}
@keyframesdrop{
0%{
transform:translateY(-100px);
opacity:0;
}
90%{
opacity:1;
transform:translateY(10px);
}
100%{
transform:translateY(0px);
}
}
js
varctx=document.querySelector('canvas').getContext('2d')
ctx.canvas.width=window.innerWidth
ctx.canvas.height=window.innerHeight
varsparks=[]
varfireworks=[]
vari=20;
while(i--){
fireworks.push(
newFirework(Math.random()*window.innerWidth,window.innerHeight*Math.random())
)
}
render()
functionrender(){
setTimeout(render,1000/60)
ctx.fillStyle='rgba(0,0,0,0.1)';
ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height)
for(varfireworkoffireworks){
if(firework.dead)continue
firework.move()
firework.draw()
}
for(varsparkofsparks){
if(spark.dead)continue
spark.move()
spark.draw()
}
if(Math.random()<0.05){
fireworks.push(newFirework())
}
}
functionSpark(x,y,color){
this.x=x
this.y=y
this.dir=Math.random()*(Math.PI*2)
this.dead=false
this.color=color
this.speed=Math.random()*3+3;
this.walker=newWalker({
radius:20,
speed:0.25
})
this.gravity=0.25
this.dur=this.speed/0.1
this.move=function(){
this.dur--
if(this.dur<0)this.dead=true
if(this.speed<0)return
if(this.speed>0)this.speed-=0.1
varwalk=this.walker.step()
this.x+=Math.cos(this.dir+walk)*this.speed
this.y+=Math.sin(this.dir+walk)*this.speed
this.y+=this.gravity
this.gravity+=0.05
}
this.draw=function(){
drawCircle(this.x,this.y,3,this.color)
}
}
functionFirework(x,y){
this.xmove=newWalker({
radius:10,
speed:0.5
})
this.x=x||Math.random()*ctx.canvas.width
this.y=y||ctx.canvas.height
this.height=Math.random()*ctx.canvas.height/2
this.dead=false
this.color=randomColor()
this.move=function(){
this.x+=this.xmove.step()
if(this.y>this.height)this.y-=1;
elsethis.burst()
}
this.draw=function(){
drawCircle(this.x,this.y,1,this.color)
}
this.burst=function(){
this.dead=true
vari=100;
while(i--)sparks.push(newSpark(this.x,this.y,this.color))
}
}
functiondrawCircle(x,y,radius,color){
color=color||'#FFF'
ctx.fillStyle=color
ctx.fillRect(x-radius/2,y-radius/2,radius,radius)
}
functionrandomColor(){
return['#6ae5ab','#88e3b2','#36b89b','#7bd7ec','#66cbe1'][Math.floor(Math.random()*5)];
}
functionWalker(options){
this.step=function(){
this.direction=Math.sign(this.target)*this.speed
this.value+=this.direction
this.target?
this.target-=this.direction:
(this.value)?
(this.wander)?
this.target=this.newTarget():
this.target=-this.value:
this.target=this.newTarget()
returnthis.direction
}
this.newTarget=function(){
returnMath.round(Math.random()*(this.radius*2)-this.radius)
}
this.start=0
this.value=0
this.radius=options.radius
this.target=this.newTarget()
this.direction=Math.sign(this.target)
this.wander=options.wander
this.speed=options.speed||1
}
实现三
html
浏览器不支持canvas