烟花效果
随机位置创建烟火,烟火作为烟花的容器,每个烟火会包含多个烟花。
代码里都有注释。
<!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>