想必有不少人喜歡看煙花吧!絢麗的煙花在黑空中迸發(fā)出完美的粒子光芒,并最終無限暗淡至隕落。煙花雖美但易逝,自然是不能經(jīng)??吹綗熁ǖ?,那么如果編寫一段代碼,讓它實(shí)現(xiàn)煙花綻放效果不就可以了。其實(shí)煙花效果并不難實(shí)現(xiàn),僅需用到 JavaScript 即可。
先讓我們來看下實(shí)現(xiàn)效果:
源碼:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>JS實(shí)現(xiàn)煙花特效-W3C技術(shù)頭條</title>
<style>
body{
margin: 0;
padding: 0;
background: url("./images/background-image.png") no-repeat center center fixed;
/*兼容瀏覽器版本*/
-webkit-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
</style>
</head>
<body>
<canvas id="mycanvas"></canvas>
<script>
//window.requestAnimationFrame()這個(gè)API是瀏覽器提供的js全局方法,針對動畫效果。
window.requestAnimationFrame=(function(){
return window.requestAnimationFrame||
window.webkitRequestAnimationFrame||
window.mozRequestAnimationFrame||
function (callback){
window.setTimeout(callback,1000)
//每間隔10秒執(zhí)行一次動畫
}
})();
//獲取canvas區(qū)域.并設(shè)置寬和高
var area=document.getElementById("mycanvas");
area.width=document.documentElement.clientWidth;
area.height=document.documentElement.clientHeight;
//轉(zhuǎn)換成2d模型
var ctx=area.getContext("2d");
//煙花數(shù)組
hue=120;//設(shè)置顏色范圍
timerTick = 0;//計(jì)時(shí)器
timerTotal=5;//每間隔5秒煙花綻放一次
fireworks=[];//存放煙花數(shù)組
particles=[];//存放碎屑數(shù)組
//隨機(jī)min和max之間的值
function random(min,max){
return Math.random()*(max-min)+min;
}
//計(jì)算兩點(diǎn)之間的距離
function distans(sx,sy,tx,ty){
var xdistan=sx-tx;
var ydistan=sy-ty;
return Math.sqrt((Math.pow(xdistan,2)+Math.pow(ydistan,2)));
}
//定義煙花對象
function Firework(sx,sy,tx,ty){
this.x=sx;
this.y=sy;
this.sx=sx;
this.sy=sy;
this.tx=tx;
this.ty=ty;
//計(jì)算兩點(diǎn)之間的距離
this.targetDistances=distans(sx,sy,tx,ty);
//運(yùn)行距離
this.distancesc=0;
//定義變量生成的運(yùn)動軌跡
this.guiji=[];
this.guijicount=3;
while(this.guijicount--){
this.guiji.push([this.x,this.y]);
}
//計(jì)算角度
this.angle=Math.atan2(ty-sy,tx-sx);
this.speed=2;
this.jiasudu=1.05;
this.brightness=random(50,70);//煙花的明度
this.targetRad=5;//煙花小圈的半徑
}
//更新煙花的位置
Firework.prototype.update=function(index){
this.guiji.pop();
this.guiji.push([this.x,this.y]);
//目標(biāo)圓運(yùn)動
if(this.targetRad<8){
this.targetRad+=0.3;
}else{
this.targetRad=1;
}
//根據(jù)加速度計(jì)算速度并且計(jì)算出煙花運(yùn)行過程中x軸和y軸的速度
this.speed*=this.jiasudu;
var vx=Math.cos(this.angle)*this.speed;
var vy=Math.sin(this.angle)*this.speed;
//重新計(jì)算兩點(diǎn)之間的距離
this.distancesc=distans(this.sx,this.sy,this.x+vx,this.y+vy);
//如果煙花運(yùn)行距離大于或等于初始位置到目標(biāo)位置之間的距離,生成新煙花并移除當(dāng)前煙花,否則更新煙花位置
if(this.distancesc>=this.targetDistances){
//生成煙花碎屑
createparticals(this.tx,this.ty);
//銷毀煙花小圈
fireworks.splice(index,1)
}else{
this.x+=vx;
this.y+=vy;
}
}
//開始畫運(yùn)行軌跡
Firework.prototype.draw=function(){
ctx.beginPath();
//軌跡的起點(diǎn)
ctx.moveTo(this.guiji[this.guiji.length-1][0],this.guiji[this.guiji.length-1][1]);
//繪制線條到目標(biāo)點(diǎn)
ctx.lineTo(this.x,this.y);
//畫出不同顏色的煙花
ctx.strokeStyle='hsl('+hue+',100%,'+this.brightness+'%)';
ctx.stroke();//繪制煙花軌跡
//畫出目標(biāo)小圓
ctx.beginPath();
ctx.arc(this.tx,this.ty,this.targetRad,0,Math.PI*2);
ctx.stroke();
}
//定義煙花碎屑方法
function Particle(x, y) {
this.x = x;
this.y = y;
this.guiji = [];
this.guijicount = 10;
while(this.guijicount--){
this.guiji.push([this.x,this.y]);
}
//生成任意方向的碎屑
this.angle=random(0 , 2*Math.PI);
this.speed=random(1,10);//隨機(jī)的速度
this.mocal=0.95;//摩擦力
this.gravity=0.98;//重力
this.hue=random(hue-20,hue+20);//碎屑顏色變化范圍
this.brightness=random(50,80);
this.alpha=1;//定義碎屑初始不透明
this.decay=random(0.015,0.03);//碎屑消失的時(shí)間
}
//更新碎屑
Particle.prototype.update=function(index){
this.guiji.pop();
//unshift() 方法可向數(shù)組的開頭添加一個(gè)或更多元素,并返回新的長度。
this.guiji.unshift([this.x,this.y]);
//下面是煙花碎屑的運(yùn)動
this.speed*=this.mocal;
this.x+=Math.cos(this.angle)*this.speed;
this.y+=Math.sin(this.angle)*this.speed+this.gravity;
this.alpha-=this.decay;//不透明度一直隨時(shí)間變?yōu)?;即煙花碎屑消失
if(this.alpha<=this.decay){
particles.splice(index,1)//銷毀煙花碎屑
}
}
//畫煙花碎屑軌跡
Particle.prototype.draw=function(){
ctx.beginPath();
ctx.moveTo(this.guiji[this.guiji.length-1][0],this.guiji[this.guiji.length-1][1]);
ctx.lineTo(this.x,this.y);
//畫出不同顏色的煙花利用HSL
ctx.strokeStyle='hsl('+hue+',100%,'+this.brightness+'%)';
ctx.stroke();
}
//創(chuàng)建碎屑
function createparticals(x,y){
//設(shè)定碎屑數(shù)目
var particalcount=500;
while(particalcount--){
//隨著碎屑數(shù)目的減少為0,又重新調(diào)用碎屑方法
particles.push(new Particle(x,y))
}
}
//獲取屏幕的寬和高
var clientw=document.documentElement.clientWidth;
var clienth=document.documentElement.clientHeight;
function loop(){
//requestAnimationFrame() 方法來告訴瀏覽器需要執(zhí)行的動畫,
// 并讓瀏覽器在下一次重繪之前調(diào)用指定的函數(shù)來更新動畫。
requestAnimationFrame(loop);
hue+=0.5;
//在源圖像外顯示目標(biāo)圖像。只有源圖像外的目標(biāo)圖像部分會被顯示,源圖像是透明的。
ctx.globalCompositeOperation = 'destination-out';
ctx.fillRect(0,0,clientw,clienth);
ctx.fillStyle='rgb(0,0,0,0.5)';
//顯示源圖像和目標(biāo)圖像。
ctx.globalCompositeOperation='lighter';
var i=fireworks.length;
while(i--){
fireworks[i].draw();
fireworks[i].update(i);
}
var i=particles.length;
while(i--){
particles[i].draw();
particles[i].update(i);
}
//此時(shí),我們還沒有創(chuàng)建任何的煙花。我們希望設(shè)置一個(gè)定時(shí)時(shí)間timerTotal,周期性的
// 產(chǎn)生一個(gè)煙花,我們也需要一個(gè)時(shí)間計(jì)數(shù)timerTick,在每次幀更新的時(shí)候加1,記下幀更新的次數(shù)。
if(timerTick>=timerTotal)
{
fireworks.push(new Firework(clientw/2,clienth,random(0,clientw),random(0,clienth)));
timerTick=0;
}
else{
timerTick++;
}
}
window.οnlοad=loop();
</script>
</body>
</html>
如果沒有黑夜背景圖,可以直接把背景顏色設(shè)置為黑色。
background-color: black;
以上就是用 JS 實(shí)現(xiàn)煙花效果的全部代碼??禳c(diǎn)動手操作這個(gè)有趣的代碼吧??!
推薦課程:JavaScript 實(shí)戰(zhàn):動態(tài)網(wǎng)站開發(fā)