zoukankan      html  css  js  c++  java
  • HTML5 Canvas 超炫酷烟花绽放动画教程

    这是一个很酷的HTML5 Canvas动画,它将模拟的是我们现实生活中烟花绽放的动画特效,效果非常逼真,但是毕竟是电脑模拟,带女朋友看就算了,效果还是差了点,呵呵。这个HTML5 Canvas动画有一点比较出色,就是其性能,Chrome上基本没有卡的感觉,就算你放出很多烟花也一样。

    html5-canvas-fireworks

    你可以在这里看在线演示

    下面我们来简单分析一下实现这款HTML5烟花特效的过程及代码,主要由HTML代码、CSS代码以及Javascript代码组成,当然javascript代码是最重要的。

    HTML代码:

    <div id=”gui”></div>
    <div id=”canvas-container”>
    <div id=”mountains2″></div>
    <div id=”mountains1″></div>
    <div id=”skyline”></div>
    </div>

    HTML的结构非常简单,即构造了一个canvas容器,我们会利用JS在这个容器中生成一个Canvas对象。看最后的JS代码你就会知道了。

    CSS代码:

    #canvas-container {
        background: #000 url(bg.jpg);
      height: 400px;
        left: 50%;
        margin: -200px 0 0 -300px;
        position: absolute;
        top: 50%;
      width: 600px;
        z-index: 2;
    }
    
    canvas {
        cursor: crosshair;
        display: block;
        position: relative;
        z-index: 3;
    }
    
    canvas:active {
        cursor: crosshair;
    }
    
    #skyline {
        background: url(skyline.png) repeat-x 50% 0;
        bottom: 0;
        height: 135px;
        left: 0;
        position: absolute;
        width: 100%;
        z-index: 1;    
    }
    
    #mountains1 {
        background: url(mountains1.png) repeat-x 40% 0;
        bottom: 0;
        height: 200px;
        left: 0;
        position: absolute;
        width: 100%;
        z-index: 1;    
    }
    
    #mountains2 {
        background: url(mountains2.png) repeat-x 30% 0;
        bottom: 0;
        height: 250px;
        left: 0;
        position: absolute;
        width: 100%;
        z-index: 1;    
    }
    
    #gui {
        right: 0;
        position: fixed;
        top: 0;
        z-index: 3;
    }

    CSS代码没什么特别,主要也就定义一下背景色和边框之类的。

    接下来是最重要的Javascript代码。

    Javascript代码:

    self.init = function(){    
        self.dt = 0;
            self.oldTime = Date.now();
            self.canvas = document.createElement('canvas');                
            self.canvasContainer = $('#canvas-container');
    
            var canvasContainerDisabled = document.getElementById('canvas-container');
            self.canvas.onselectstart = function() {
                return false;
            };
    
            self.canvas.width = self.cw = 600;
            self.canvas.height = self.ch = 400;    
    
            self.particles = [];    
            self.partCount = 30;
            self.fireworks = [];    
            self.mx = self.cw/2;
            self.my = self.ch/2;
            self.currentHue = 170;
            self.partSpeed = 5;
            self.partSpeedVariance = 10;
            self.partWind = 50;
            self.partFriction = 5;
            self.partGravity = 1;
            self.hueMin = 150;
            self.hueMax = 200;
            self.fworkSpeed = 2;
            self.fworkAccel = 4;
            self.hueVariance = 30;
            self.flickerDensity = 20;
            self.showShockwave = false;
            self.showTarget = true;
            self.clearAlpha = 25;
    
            self.canvasContainer.append(self.canvas);
            self.ctx = self.canvas.getContext('2d');
            self.ctx.lineCap = 'round';
            self.ctx.lineJoin = 'round';
            self.lineWidth = 1;
            self.bindEvents();            
            self.canvasLoop();
    
            self.canvas.onselectstart = function() {
                return false;
            };
    
        };

    这段JS代码主要是往canvas容器中构造一个Canvas对象,并且对这个canvas对象的外观以及动画属性作了初始化。

    var Particle = function(x, y, hue){
            this.x = x;
            this.y = y;
            this.coordLast = [
                {x: x, y: y},
                {x: x, y: y},
                {x: x, y: y}
            ];
            this.angle = rand(0, 360);
            this.speed = rand(((self.partSpeed - self.partSpeedVariance) <= 0) ? 1 : self.partSpeed - self.partSpeedVariance, (self.partSpeed + self.partSpeedVariance));
            this.friction = 1 - self.partFriction/100;
            this.gravity = self.partGravity/2;
            this.hue = rand(hue-self.hueVariance, hue+self.hueVariance);
            this.brightness = rand(50, 80);
            this.alpha = rand(40,100)/100;
            this.decay = rand(10, 50)/1000;
            this.wind = (rand(0, self.partWind) - (self.partWind/2))/25;
            this.lineWidth = self.lineWidth;
        };
    
        Particle.prototype.update = function(index){
            var radians = this.angle * Math.PI / 180;
            var vx = Math.cos(radians) * this.speed;
            var vy = Math.sin(radians) * this.speed + this.gravity;
            this.speed *= this.friction;
    
            this.coordLast[2].x = this.coordLast[1].x;
            this.coordLast[2].y = this.coordLast[1].y;
            this.coordLast[1].x = this.coordLast[0].x;
            this.coordLast[1].y = this.coordLast[0].y;
            this.coordLast[0].x = this.x;
            this.coordLast[0].y = this.y;
    
            this.x += vx * self.dt;
            this.y += vy * self.dt;
    
            this.angle += this.wind;                
            this.alpha -= this.decay;
    
            if(!hitTest(0,0,self.cw,self.ch,this.x-this.radius, this.y-this.radius, this.radius*2, this.radius*2) || this.alpha < .05){                    
                self.particles.splice(index, 1);    
            }            
        };
    
        Particle.prototype.draw = function(){
            var coordRand = (rand(1,3)-1);
            self.ctx.beginPath();                                
            self.ctx.moveTo(Math.round(this.coordLast[coordRand].x), Math.round(this.coordLast[coordRand].y));
            self.ctx.lineTo(Math.round(this.x), Math.round(this.y));
            self.ctx.closePath();                
            self.ctx.strokeStyle = 'hsla('+this.hue+', 100%, '+this.brightness+'%, '+this.alpha+')';
            self.ctx.stroke();                
    
            if(self.flickerDensity > 0){
                var inverseDensity = 50 - self.flickerDensity;                    
                if(rand(0, inverseDensity) === inverseDensity){
                    self.ctx.beginPath();
                    self.ctx.arc(Math.round(this.x), Math.round(this.y), rand(this.lineWidth,this.lineWidth+3)/2, 0, Math.PI*2, false)
                    self.ctx.closePath();
                    var randAlpha = rand(50,100)/100;
                    self.ctx.fillStyle = 'hsla('+this.hue+', 100%, '+this.brightness+'%, '+randAlpha+')';
                    self.ctx.fill();
                }    
            }
        };

    这段JS代码的功能是实现烟花爆炸后的小颗粒的绘制,从draw方法中可以看出,创建几个随机点,烟花颗粒即可在这个范围的随机点中散落。

    var Firework = function(startX, startY, targetX, targetY){
            this.x = startX;
            this.y = startY;
            this.startX = startX;
            this.startY = startY;
            this.hitX = false;
            this.hitY = false;
            this.coordLast = [
                {x: startX, y: startY},
                {x: startX, y: startY},
                {x: startX, y: startY}
            ];
            this.targetX = targetX;
            this.targetY = targetY;
            this.speed = self.fworkSpeed;
            this.angle = Math.atan2(targetY - startY, targetX - startX);
            this.shockwaveAngle = Math.atan2(targetY - startY, targetX - startX)+(90*(Math.PI/180));
            this.acceleration = self.fworkAccel/100;
            this.hue = self.currentHue;
            this.brightness = rand(50, 80);
            this.alpha = rand(50,100)/100;
            this.lineWidth = self.lineWidth;
            this.targetRadius = 1;
        };
    
        Firework.prototype.update = function(index){
            self.ctx.lineWidth = this.lineWidth;
    
            vx = Math.cos(this.angle) * this.speed,
            vy = Math.sin(this.angle) * this.speed;
            this.speed *= 1 + this.acceleration;                
            this.coordLast[2].x = this.coordLast[1].x;
            this.coordLast[2].y = this.coordLast[1].y;
            this.coordLast[1].x = this.coordLast[0].x;
            this.coordLast[1].y = this.coordLast[0].y;
            this.coordLast[0].x = this.x;
            this.coordLast[0].y = this.y;
    
            if(self.showTarget){
                if(this.targetRadius < 8){
                    this.targetRadius += .25 * self.dt;
                } else {
                    this.targetRadius = 1 * self.dt;    
                }
            }
    
            if(this.startX >= this.targetX){
                if(this.x + vx <= this.targetX){
                    this.x = this.targetX;
                    this.hitX = true;
                } else {
                    this.x += vx * self.dt;
                }
            } else {
                if(this.x + vx >= this.targetX){
                    this.x = this.targetX;
                    this.hitX = true;
                } else {
                    this.x += vx * self.dt;
                }
            }
    
            if(this.startY >= this.targetY){
                if(this.y + vy <= this.targetY){
                    this.y = this.targetY;
                    this.hitY = true;
                } else {
                    this.y += vy * self.dt;
                }
            } else {
                if(this.y + vy >= this.targetY){
                    this.y = this.targetY;
                    this.hitY = true;
                } else {
                    this.y += vy * self.dt;
                }
            }                
    
            if(this.hitX && this.hitY){
                var randExplosion = rand(0, 9);
                self.createParticles(this.targetX, this.targetY, this.hue);
                self.fireworks.splice(index, 1);                    
            }
        };
    
        Firework.prototype.draw = function(){
            self.ctx.lineWidth = this.lineWidth;
    
            var coordRand = (rand(1,3)-1);                    
            self.ctx.beginPath();                            
            self.ctx.moveTo(Math.round(this.coordLast[coordRand].x), Math.round(this.coordLast[coordRand].y));
            self.ctx.lineTo(Math.round(this.x), Math.round(this.y));
            self.ctx.closePath();
            self.ctx.strokeStyle = 'hsla('+this.hue+', 100%, '+this.brightness+'%, '+this.alpha+')';
            self.ctx.stroke();    
    
            if(self.showTarget){
                self.ctx.save();
                self.ctx.beginPath();
                self.ctx.arc(Math.round(this.targetX), Math.round(this.targetY), this.targetRadius, 0, Math.PI*2, false)
                self.ctx.closePath();
                self.ctx.lineWidth = 1;
                self.ctx.stroke();
                self.ctx.restore();
            }
    
            if(self.showShockwave){
                self.ctx.save();
                self.ctx.translate(Math.round(this.x), Math.round(this.y));
                self.ctx.rotate(this.shockwaveAngle);
                self.ctx.beginPath();
                self.ctx.arc(0, 0, 1*(this.speed/5), 0, Math.PI, true);
                self.ctx.strokeStyle = 'hsla('+this.hue+', 100%, '+this.brightness+'%, '+rand(25, 60)/100+')';
                self.ctx.lineWidth = this.lineWidth;
                self.ctx.stroke();
                self.ctx.restore();
            }                                 
        };

    这段JS代码是创建烟花实例的,我们也可以从draw方法中看出,当我们鼠标点击画布中的某点时,烟花发射的目的地就在那个点上。

    这款HTML5 Canvas烟花效果的核心代码就是这样,全部的代码还请各位下载源代码研究。源代码下载>>

  • 相关阅读:
    define的用法
    MySQL索引使用方法和性能优化
    自己写的一个Js小插件
    .net处理JSON简明教程
    史上最全的ASP.NET MVC路由配置,以后RouteConfig再弄不懂神仙都难救你啦~
    Python面向对象之-反射
    Python内置函数之classmetho staticmethod
    Python内置函数之-property
    python面向对象三大特性-多态
    python面向对象三大特性之封装
  • 原文地址:https://www.cnblogs.com/html5tricks/p/3893275.html
Copyright © 2011-2022 走看看