HTML5 Canvas超炫酷烟花动画!

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

HTML5 Canvas超炫酷烟花动画!_第1张图片

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


HTML代码:







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


CSS代码:



  1. #canvas-container {
  2.     background: #000 url(bg.jpg);
  3.   height: 400px;
  4.     left: 50%;
  5.     margin: -200px 0 0 -300px;
  6.     position: absolute;
  7.     top: 50%;
  8.   width: 600px;
  9.     z-index: 2;
  10. }

  11. canvas {
  12.     cursor: crosshair;
  13.     display: block;
  14.     position: relative;
  15.     z-index: 3;
  16. }

  17. canvas:active {
  18.     cursor: crosshair;
  19. }

  20. #skyline {
  21.     background: url(skyline.png) repeat-x 50% 0;
  22.     bottom: 0;
  23.     height: 135px;
  24.     left: 0;
  25.     position: absolute;
  26.     width: 100%;
  27.     z-index: 1;    
  28. }

  29. #mountains1 {
  30.     background: url(mountains1.png) repeat-x 40% 0;
  31.     bottom: 0;
  32.     height: 200px;
  33.     left: 0;
  34.     position: absolute;
  35.     width: 100%;
  36.     z-index: 1;    
  37. }

  38. #mountains2 {
  39.     background: url(mountains2.png) repeat-x 30% 0;
  40.     bottom: 0;
  41.     height: 250px;
  42.     left: 0;
  43.     position: absolute;
  44.     width: 100%;
  45.     z-index: 1;    
  46. }

  47. #gui {
  48.     right: 0;
  49.     position: fixed;
  50.     top: 0;
  51.     z-index: 3;
  52. }
复制代码
CSS代码没什么特别,主要也就定义一下背景色和边框之类的。


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


Javascript代码:



  1. self.init = function(){    
  2.     self.dt = 0;
  3.         self.oldTime = Date.now();
  4.         self.canvas = document.createElement('canvas');                
  5.         self.canvasContainer = $('#canvas-container');

  6.         var canvasContainerDisabled = document.getElementById('canvas-container');
  7.         self.canvas.onselectstart = function() {
  8.             return false;
  9.         };

  10.         self.canvas.width = self.cw = 600;
  11.         self.canvas.height = self.ch = 400;    

  12.         self.particles = [];    
  13.         self.partCount = 30;
  14.         self.fireworks = [];    
  15.         self.mx = self.cw/2;
  16.         self.my = self.ch/2;
  17.         self.currentHue = 170;
  18.         self.partSpeed = 5;
  19.         self.partSpeedVariance = 10;
  20.         self.partWind = 50;
  21.         self.partFriction = 5;
  22.         self.partGravity = 1;
  23.         self.hueMin = 150;
  24.         self.hueMax = 200;
  25.         self.fworkSpeed = 2;
  26.         self.fworkAccel = 4;
  27.         self.hueVariance = 30;
  28.         self.flickerDensity = 20;
  29.         self.showShockwave = false;
  30.         self.showTarget = true;
  31.         self.clearAlpha = 25;

  32.         self.canvasContainer.append(self.canvas);
  33.         self.ctx = self.canvas.getContext('2d');
  34.         self.ctx.lineCap = 'round';
  35.         self.ctx.lineJoin = 'round';
  36.         self.lineWidth = 1;
  37.         self.bindEvents();            
  38.         self.canvasLoop();

  39.         self.canvas.onselectstart = function() {
  40.             return false;
  41.         };

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


  1. var Particle = function(x, y, hue){
  2.         this.x = x;
  3.         this.y = y;
  4.         this.coordLast = [
  5.             {x: x, y: y},
  6.             {x: x, y: y},
  7.             {x: x, y: y}
  8.         ];
  9.         this.angle = rand(0, 360);
  10.         this.speed = rand(((self.partSpeed - self.partSpeedVariance) <= 0) ? 1 : self.partSpeed - self.partSpeedVariance, (self.partSpeed + self.partSpeedVariance));
  11.         this.friction = 1 - self.partFriction/100;
  12.         this.gravity = self.partGravity/2;
  13.         this.hue = rand(hue-self.hueVariance, hue+self.hueVariance);
  14.         this.brightness = rand(50, 80);
  15.         this.alpha = rand(40,100)/100;
  16.         this.decay = rand(10, 50)/1000;
  17.         this.wind = (rand(0, self.partWind) - (self.partWind/2))/25;
  18.         this.lineWidth = self.lineWidth;
  19.     };

  20.     Particle.prototype.update = function(index){
  21.         var radians = this.angle * Math.PI / 180;
  22.         var vx = Math.cos(radians) * this.speed;
  23.         var vy = Math.sin(radians) * this.speed + this.gravity;
  24.         this.speed *= this.friction;

  25.         this.coordLast[2].x = this.coordLast[1].x;
  26.         this.coordLast[2].y = this.coordLast[1].y;
  27.         this.coordLast[1].x = this.coordLast[0].x;
  28.         this.coordLast[1].y = this.coordLast[0].y;
  29.         this.coordLast[0].x = this.x;
  30.         this.coordLast[0].y = this.y;

  31.         this.x += vx * self.dt;
  32.         this.y += vy * self.dt;

  33.         this.angle += this.wind;                
  34.         this.alpha -= this.decay;

  35.         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){                    
  36.             self.particles.splice(index, 1);    
  37.         }            
  38.     };

  39.     Particle.prototype.draw = function(){
  40.         var coordRand = (rand(1,3)-1);
  41.         self.ctx.beginPath();                                
  42.         self.ctx.moveTo(Math.round(this.coordLast[coordRand].x), Math.round(this.coordLast[coordRand].y));
  43.         self.ctx.lineTo(Math.round(this.x), Math.round(this.y));
  44.         self.ctx.closePath();                
  45.         self.ctx.strokeStyle = 'hsla('+this.hue+', 100%, '+this.brightness+'%, '+this.alpha+')';
  46.         self.ctx.stroke();                

  47.         if(self.flickerDensity > 0){
  48.             var inverseDensity = 50 - self.flickerDensity;                    
  49.             if(rand(0, inverseDensity) === inverseDensity){
  50.                 self.ctx.beginPath();
  51.                 self.ctx.arc(Math.round(this.x), Math.round(this.y), rand(this.lineWidth,this.lineWidth+3)/2, 0, Math.PI*2, false)
  52.                 self.ctx.closePath();
  53.                 var randAlpha = rand(50,100)/100;
  54.                 self.ctx.fillStyle = 'hsla('+this.hue+', 100%, '+this.brightness+'%, '+randAlpha+')';
  55.                 self.ctx.fill();
  56.             }    
  57.         }
  58.     };
复制代码
这段JS代码的功能是实现**爆炸后的小颗粒的绘制,从draw方法中可以看出,创建几个随机点,**颗粒即可在这个范围的随机点中散落。
  1. var Firework = function(startX, startY, targetX, targetY){
  2.         this.x = startX;
  3.         this.y = startY;
  4.         this.startX = startX;
  5.         this.startY = startY;
  6.         this.hitX = false;
  7.         this.hitY = false;
  8.         this.coordLast = [
  9.             {x: startX, y: startY},
  10.             {x: startX, y: startY},
  11.             {x: startX, y: startY}
  12.         ];
  13.         this.targetX = targetX;
  14.         this.targetY = targetY;
  15.         this.speed = self.fworkSpeed;
  16.         this.angle = Math.atan2(targetY - startY, targetX - startX);
  17.         this.shockwaveAngle = Math.atan2(targetY - startY, targetX - startX)+(90*(Math.PI/180));
  18.         this.acceleration = self.fworkAccel/100;
  19.         this.hue = self.currentHue;
  20.         this.brightness = rand(50, 80);
  21.         this.alpha = rand(50,100)/100;
  22.         this.lineWidth = self.lineWidth;
  23.         this.targetRadius = 1;
  24.     };

  25.     Firework.prototype.update = function(index){
  26.         self.ctx.lineWidth = this.lineWidth;

  27.         vx = Math.cos(this.angle) * this.speed,
  28.         vy = Math.sin(this.angle) * this.speed;
  29.         this.speed *= 1 + this.acceleration;                
  30.         this.coordLast[2].x = this.coordLast[1].x;
  31.         this.coordLast[2].y = this.coordLast[1].y;
  32.         this.coordLast[1].x = this.coordLast[0].x;
  33.         this.coordLast[1].y = this.coordLast[0].y;
  34.         this.coordLast[0].x = this.x;
  35.         this.coordLast[0].y = this.y;

  36.         if(self.showTarget){
  37.             if(this.targetRadius < 8){
  38.                 this.targetRadius += .25 * self.dt;
  39.             } else {
  40.                 this.targetRadius = 1 * self.dt;    
  41.             }
  42.         }

  43.         if(this.startX >= this.targetX){
  44.             if(this.x + vx <= this.targetX){
  45.                 this.x = this.targetX;
  46.                 this.hitX = true;
  47.             } else {
  48.                 this.x += vx * self.dt;
  49.             }
  50.         } else {
  51.             if(this.x + vx >= this.targetX){
  52.                 this.x = this.targetX;
  53.                 this.hitX = true;
  54.             } else {
  55.                 this.x += vx * self.dt;
  56.             }
  57.         }

  58.         if(this.startY >= this.targetY){
  59.             if(this.y + vy <= this.targetY){
  60.                 this.y = this.targetY;
  61.                 this.hitY = true;
  62.             } else {
  63.                 this.y += vy * self.dt;
  64.             }
  65.         } else {
  66.             if(this.y + vy >= this.targetY){
  67.                 this.y = this.targetY;
  68.                 this.hitY = true;
  69.             } else {
  70.                 this.y += vy * self.dt;
  71.             }
  72.         }                

  73.         if(this.hitX && this.hitY){
  74.             var randExplosion = rand(0, 9);
  75.             self.createParticles(this.targetX, this.targetY, this.hue);
  76.             self.fireworks.splice(index, 1);                    
  77.         }
  78.     };

  79.     Firework.prototype.draw = function(){
  80.         self.ctx.lineWidth = this.lineWidth;

  81.         var coordRand = (rand(1,3)-1);                    
  82.         self.ctx.beginPath();                            
  83.         self.ctx.moveTo(Math.round(this.coordLast[coordRand].x), Math.round(this.coordLast[coordRand].y));
  84.         self.ctx.lineTo(Math.round(this.x), Math.round(this.y));
  85.         self.ctx.closePath();
  86.         self.ctx.strokeStyle = 'hsla('+this.hue+', 100%, '+this.brightness+'%, '+this.alpha+')';
  87.         self.ctx.stroke();    

  88.         if(self.showTarget){
  89.             self.ctx.save();
  90.             self.ctx.beginPath();
  91.             self.ctx.arc(Math.round(this.targetX), Math.round(this.targetY), this.targetRadius, 0, Math.PI*2, false)
  92.             self.ctx.closePath();
  93.             self.ctx.lineWidth = 1;
  94.             self.ctx.stroke();
  95.             self.ctx.restore();
  96.         }

  97.         if(self.showShockwave){
  98.             self.ctx.save();
  99.             self.ctx.translate(Math.round(this.x), Math.round(this.y));
  100.             self.ctx.rotate(this.shockwaveAngle);
  101.             self.ctx.beginPath();
  102.             self.ctx.arc(0, 0, 1*(this.speed/5), 0, Math.PI, true);
  103.             self.ctx.strokeStyle = 'hsla('+this.hue+', 100%, '+this.brightness+'%, '+rand(25, 60)/100+')';
  104.             self.ctx.lineWidth = this.lineWidth;
  105.             self.ctx.stroke();
  106.             self.ctx.restore();
  107.         }                                 
  108.     };
复制代码
这段JS代码是创建**实例的,我们也可以从draw方法中看出,当我们鼠标点击画布中的某点时,**发射的目的地就在那个点上。


你可能感兴趣的:(HTML5)