烟花效果

随机位置创建烟火,烟火作为烟花的容器,每个烟火会包含多个烟花。

代码里都有注释。

<!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>

相关推荐