烟花效果
随机位置创建烟火,烟火作为烟花的容器,每个烟火会包含多个烟花。
代码里都有注释。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" /> <title>烟花</title> <style type="text/css"> body { height: 1000px; } #lotteryContainer { position: relative; width: 300px; height: 100px; } #drawPercent { color: #F60; } </style> </head> <body> <!-- andrew.stz 转载请注明出处,尊重他人劳动成果,是每个地球人应有的品质 --> <canvas style='background-color:#000;position:absolute;left:0px;top:0px;'></canvas> <script> var c = document.getElementsByTagName('canvas')[0]; //随着窗口调整画布大小 (onresize = function() { c.width = window.innerWidth; c.height = window.innerHeight; })(); new FireWork({ canvas:c, singleColor:false }); function FireWork(option){ /** * 一个烟花包括多个烟火 */ var canvas = option.canvas; if(!canvas||!canvas.nodeType||canvas.nodeType!=1){ alert('请传入canvas元素'); return; } //canvas,singleColor if(!canvas.getContext){ alert('你的浏览器out了!请更新到支持html5的现代浏览器'); return; } this.FPS = option.FPS||40; //期望的帧率,实际不一定能达到 this.singleColor = option.singleColor; this.intervalBase = option.intervalBase||150; //烟花产生间隔调长点以增加性能 this.fireBaseNum = option.fireBaseNum||5; //烟火基本数目(最少多少个) this.fireSeedNum = option.fireSeedNum||8; //烟火种子数目,会在0到这个数之间取随机值 this.fireMaxWidth = option.fireMaxWidth||4; //烟火轨迹的最大宽度,值越大头越大 this.traceLength = option.traceLength||8; //烟火轨迹长度 var self = this; var up = 0; var cvs = canvas.getContext('2d'); var W, H; W = c.width||window.innerWidth; H = c.height||window.innerHeight; //总烟火数组 var fireworks = []; setInterval(function() { cvs.clearRect(0, 0, W, H); //依次绘制烟火 for(var n = 0,len=fireworks.length; n < len; n++) { var firework = fireworks[n]; for(var i = 0,qLen=firework.length; i < qLen; i++) { var pt = firework[i]; //计算路径 pt.move(); //绘制 drawPt(pt.track, pt.life / 30, pt.r, pt.g, pt.b); //超过生存周期就消失 if(pt.life <= 0){ qLen--; firework.splice(i, 1); } } //当一个烟火包含的烟花个数为零,则消灭这个烟火 if(!fireworks[n].length){ len--; fireworks.splice(n, 1); } } //每隔一段时间添加一个新烟火 if(new Date - up < rnd(2000)+self.intervalBase) return; up = new Date; createBoom(rnd(W / 2) + W / 4, rnd(50) + 20); }, 1000/this.FPS); //生成一个烟花 function createPT(x, y, r, g, b) { return { x : x, y : y, r : r, g : g, b : b, //轨迹序列 track : [], dx : rnd(20) - 10, dy : rnd(10) - 7, life : 30 + rnd(30), //移动函数,修改加速度和坐标 move : function() { this.dx *= .98; this.dy *= .98; this.dy += .42; //模拟重力加速度的偏移 dy=y+y*0.98 dx=x*0.98 this.x += this.dx; this.y += this.dy; this.track.push([this.x, this.y]); //保持轨迹长度 if(this.track.length > self.traceLength) this.track.shift(); this.life--; } }; } //在x,y位置创建一个烟火 function createBoom(x, y) { var firework = [], r = rnd(255) | 0, g = rnd(255) | 0, b = rnd(255) | 0; //烟火中的烟花 if(self.singleColor){ for(var i = 0,len=rnd(self.fireSeedNum) + self.fireBaseNum; i < len; i++){ firework.push(createPT(x, y, r, g, b)); } }else{ for(var i = 0,len=rnd(self.fireSeedNum) + self.fireBaseNum; i < len; i++){ firework.push(createPT(x, y, rnd(255) | 0, rnd(255) | 0, rnd(255) | 0)); } } fireworks.push(firework); } function rnd(n) { return (n || 1) * Math.random(); } function drawPt(ar, life, r, g, b) { cvs.save(); //绘制轨迹。思路是每次都绘制一条透明的轨迹,叠加起来形成一条渐变的样子 for(var i = 0,len=ar.length; i < len; i++) { cvs.strokeStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + Math.abs(.2 * life) + ')'; cvs.lineWidth = Math.min(i + 1, self.fireMaxWidth); // * 2 cvs.beginPath(); cvs.moveTo(ar[i][0], ar[i][1]); for(var j = i + 1; j < len; j++){ cvs.lineTo(ar[j][0], ar[j][1]); } cvs.stroke(); } cvs.restore(); } } </script> </body> </html>