Hiệu ứng đài phun nước chiếu sáng nhiều màu sắc

Nhiều khi nhân dịp các sự kiện trọng đại nào đó bạn cần trang trí cho blogspot của mình cho có phần không khí bằng các hiệu ứng như mưa rơi, tuyết rơi, pháo hoa, chuông giáng sinh....hiệu ứng đài phun nước chiếu sáng nhiều màu sắc cũng là lựa chọn không tồi.

Dưới đây là phần hướng dẫn các bạn cài đặt hiệu ứng đài phun nước chiếu sáng nhiều màu sắc cho blogspot


DEMO



Bạn có thể gộp cả 3 phần:
- css
- Javascript
- HTML
Bằng cách thêm 1 tiện ích tại phần footer(footer có chiều rộng là cả trang blogspot).

Hoặc bạn cài từng phần vào trong mẫu như:
- css trước thẻ ]]></b:skin>
- Javascript trước thẻ </body>
- HTML vào nơi bạn muốn hiệu ứng hiển thị.

Sau đây là các thành phần:

+ CSS.

.container{
   width: 100%;
   height: 100%;
   margin: 0;
   padding: 0;
   background-color: #000000;
  }

+ Javascript.

var RENDERER = {
 GRAVITY : 0.08,
 BASE_RATE : 0.6,
 OFFSET_RATE : 1 / 50,
 PARTICLE_COUNT : 30,
 
 init : function(){
  this.setParameters();
  this.setup();
  this.reconstructMethods();
  this.bindEvent();
  this.render();
 },
 setParameters : function(){
  this.$window = $(window);
  this.$container = $('#jsi-fountain-container');
  this.$canvas = $('<canvas />');
  this.context = this.$canvas.appendTo(this.$container).get(0).getContext('2d');
  this.particles = [];
  this.fountains = [];
  this.resizeIds = [];
 },
 setup : function(){
  this.particles.length = 0;
  this.fountains.length = 0;
  this.resizeIds.length = 0;
  this.width = this.$container.width();
  this.height = this.$container.height();
  this.$canvas.attr({width : this.width, height : this.height});
  this.velocity = 1;
  
  while(true){
   var distance = 0,
    velocity = this.velocity;
    
   while(velocity >= 0){
    velocity -= this.GRAVITY;
    distance += velocity;
   }
   if(distance > Math.min(this.height * (this.BASE_RATE - this.OFFSET_RATE), 500)){
    this.velocity -= 0.2;
    break;
   }
   this.velocity += 0.2;
  }
  this.gradient = this.context.createLinearGradient(0, this.height * this.BASE_RATE, 0, this.height);
  this.gradient.addColorStop(0, 'hsla(210, 80%, 5%, 0.5)');
  this.gradient.addColorStop(0.1, 'hsla(210, 80%, 5%, 0.8)');
  this.gradient.addColorStop(1, 'hsla(210, 80%, 5%, 0.9)');
  this.createElements();
 },
 createElements : function(){
  for(var i = 0, count = this.PARTICLE_COUNT * this.width / 500  * this.height / 500; i < count; i++){
   this.particles.push(new PARTICLE(this));
  }
  for(var i = -2; i <= 2; i++){
   this.fountains.push(new FOUNTAIN(this, this.width / 2 + i * Math.max(250, this.width / 5), this.height * (this.BASE_RATE - this.OFFSET_RATE), i));
  }
 },
 watchWindowSize : function(){
  while(this.resizeIds.length > 0){
   clearTimeout(this.resizeIds.pop());
  }
  this.tmpWidth = this.$window.width();
  this.tmpHeight = this.$window.height();
  this.resizeIds.push(setTimeout(this.jdugeToStopResize, this.RESIZE_INTERVAL));
 },
 jdugeToStopResize : function(){
  var width = this.$window.width(),
   height = this.$window.height(),
   stopped = (width == this.tmpWidth && height == this.tmpHeight);
   
  this.tmpWidth = width;
  this.tmpHeight = height;
  
  if(stopped){
   this.setup();
  }
 },
 reconstructMethods : function(){
  this.watchWindowSize = this.watchWindowSize.bind(this);
  this.jdugeToStopResize = this.jdugeToStopResize.bind(this);
  this.render = this.render.bind(this);
 },
 bindEvent : function(){
  this.$window.on('resize', this.watchWindowSize);
 },
 getRandomValue : function(min, max){
  return min + (max - min) * Math.random();
 },
 render : function(){
  requestAnimationFrame(this.render);
  this.context.fillStyle = 'hsla(0, 0%, 0%, 0.3)';
  this.context.fillRect(0, 0, this.width, this.height);
  this.context.save();
  this.context.globalCompositeOperation = 'lighter';
  
  for(var i = 0, count = this.particles.length; i < count; i++){
   this.particles[i].render(this.context);
  }
  for(var i = 0, count = this.fountains.length; i < count; i++){
   this.fountains[i].render(this.context);
  }
  this.context.restore();
  this.context.save();
  this.context.translate(0, this.height * this.BASE_RATE);
  this.context.scale(1, -(1 - this.BASE_RATE) / this.BASE_RATE);
  this.context.drawImage(this.$canvas.get(0), 0, 0, this.width, this.height * this.BASE_RATE, 0,  -this.height * this.BASE_RATE, this.width, this.height * this.BASE_RATE);
  this.context.restore();
  this.context.fillStyle = this.gradient;
  this.context.fillRect(0, this.height * this.BASE_RATE, this.width, this.height * (1 - this.BASE_RATE));
 }
};
var PARTICLE = function(renderer){
 this.renderer = renderer;
 this.init();
};
PARTICLE.prototype = {
 THRESHOLD : 10,
 
 init : function(){
  this.x = this.renderer.getRandomValue(-this.THRESHOLD, this.renderer.width + this.THRESHOLD);
  this.y = this.renderer.getRandomValue(-this.THRESHOLD, this.renderer.height * this.renderer.BASE_RATE + this.THRESHOLD);
  this.vx = this.renderer.getRandomValue(-0.3, 0.3);
  this.vy = this.renderer.getRandomValue(-0.3, 0.3);
  this.theta = this.renderer.getRandomValue(0, Math.PI * 2);
  this.deltaTheta = this.renderer.getRandomValue(Math.PI / 300, Math.PI / 100);
 },
 getColor : function(){
  var baseIndex = -1,
   fountains = this.renderer.fountains,
   hue = 0;
   
  for(var i = 0, count = fountains.length; i < count; i++){
   if(this.x < fountains[i].x){
    break;
   }
   baseIndex = i;
  }
  if(baseIndex == -1){
   hue = fountains[0].hue;
  }else if(baseIndex == fountains.length - 1){
   hue = fountains[fountains.length - 1].hue;
  }else{
   var dx1 = this.x - fountains[baseIndex].x,
    dx2 = fountains[baseIndex + 1].x - this.x;
   hue = fountains[baseIndex].hue * (dx2 / (dx1 + dx2)) + fountains[baseIndex + 1].hue * (dx1 / (dx1 + dx2));
  }
  return 'hsl(' + hue + ', 60%, ' + (15 * (1 + Math.sin(this.theta))) + '%)';
 },
 render : function(context){
  context.save();
  context.fillStyle = this.getColor();
  context.beginPath();
  context.arc(this.x, this.y, 1, 0, Math.PI * 2, false);
  context.fill();
  context.restore();
  
  this.x += this.vx;
  this.y += this.vy;
  this.theta += this.deltaTheta;
  this.theta %= Math.PI * 2;
  
  if(this.x < -this.THRESHOLD && this.vx < 0 || this.x > this.renderer.width + this.THRESHOLD && this.vx > 0){
   this.vx *= -1;
  }
  if(this.y < -this.THRESHOLD && this.vy < 0 || this.y > this.renderer.height * this.renderer.BASE_RATE + this.THRESHOLD && this.vy > 0){
   this.vy *= -1;
  }
 }
};
var FOUNTAIN = function(renderer, x, y, index){
 this.renderer = renderer;
 this.x = x;
 this.y = y;
 this.index = index;
 this.init();
};
FOUNTAIN.prototype = {
 init : function(){
  this.waterLines = [];
  this.hue = 60;
  this.destinationHue = this.hue + 72 * this.index;
  this.waitCount = Math.abs(this.index) * 100;
  this.count = 0;
  this.theta = 0;
  this.status = 0;
 },
 controlStatus : function(){
  switch(this.status){
  case 0:
   if(++this.count >= this.waitCount){
    this.status = 1;
   }
   break;
  case 1:
   if(++this.count >= 300){
    this.status = 2;
    this.count = 0;
   }
   break;
  case 2:
   this.hue += this.index;
   
   if(this.hue == this.destinationHue){
    this.status = 3;
   }
   break;
  case 3:
   if(++this.count == 300){
    this.status = 4;
    this.count = 0;
   }
   break;
  case 4:
   this.theta += Math.PI / 50;
   this.theta %= Math.PI * 2;
   
   if(this.count++ == 25){
    this.status = 3;
   }
  }
  return this.status > 0;
 },
 render : function(context){
  var hue = this.hue + Math.sin(this.theta) * 36;
  context.save();
  context.fillStyle = 'hsl(' + hue + ', 70%, 30%)';
  context.translate(this.x, this.y);
  context.scale(1, 0.3);
  context.beginPath();
  context.arc(0, 0, 10, 0, Math.PI * 2, false);
  context.fill();
  context.restore();
  
  if(!this.controlStatus()){
   return;
  }
  context.save();
  context.translate(this.x, this.y);
  
  for(var i = this.waterLines.length - 1; i >= 0; i--){
   if(!this.waterLines[i].render(context, hue)){
    this.waterLines.splice(i, 1);
   }
  }
  context.restore();
  this.waterLines.push(new WATER_LINE(this.renderer));
 }
};
var WATER_LINE = function(renderer){
 this.renderer = renderer;
 this.init();
};
WATER_LINE.prototype = {
 MAX_TRACES : 80,
 
 init : function(){
  var theta = this.renderer.getRandomValue(-Math.PI / 20, Math.PI / 20),
   rate = this.renderer.getRandomValue(0.8, 1);
  this.x = this.renderer.getRandomValue(-2, 2);
  this.y = 0;
  this.vx = this.renderer.velocity * Math.sin(theta) * rate;
  this.vy = -this.renderer.velocity * Math.cos(theta * this.renderer.getRandomValue(3, 6)) * rate;
  this.opacity = 1;
  this.luminance = 0;
  this.traces = [];
 },
 render : function(context, hue){
  this.traces.push({x : this.x, y : this.y});
  
  if(this.traces.length > this.MAX_TRACES){
   this.traces.shift();
  }
  context.save();
  context.strokeStyle = 'hsla(' + hue + ', 70%, ' + this.luminance + '%, ' + this.opacity + ')';
  context.beginPath();
  context.moveTo(this.traces[0].x, this.traces[0].y);
  
  for(var i = 1, count = this.traces.length; i < count; i++){
   context.lineTo(this.traces[i].x, this.traces[i].y);
  }
  context.stroke();
  context.restore();
  this.x += this.vx;
  this.y += this.vy;
  this.vy += this.renderer.GRAVITY;
  
  if(this.vy > 0){
   this.opacity -= 0.02;
  }
  if(this.luminance < 10){
   this.luminance += 0.1;
  }
  return this.opacity > 0;
 }
};
$(function(){
 RENDERER.init();
});

+ HTML.

<div id="jsi-fountain-container" class="container"></div>

Nếu gộp và thêm một tiện ích thì dùng code sau.

<style>
.container{
   width: 100%;
   height: 100%;
   margin: 0;
   padding: 0;
   background-color: #000000;
  }
</style>
<script type='text/javascript'>
//<![CDATA[
var RENDERER = {
 GRAVITY : 0.08,
 BASE_RATE : 0.6,
 OFFSET_RATE : 1 / 50,
 PARTICLE_COUNT : 30,
 
 init : function(){
  this.setParameters();
  this.setup();
  this.reconstructMethods();
  this.bindEvent();
  this.render();
 },
 setParameters : function(){
  this.$window = $(window);
  this.$container = $('#jsi-fountain-container');
  this.$canvas = $('<canvas />');
  this.context = this.$canvas.appendTo(this.$container).get(0).getContext('2d');
  this.particles = [];
  this.fountains = [];
  this.resizeIds = [];
 },
 setup : function(){
  this.particles.length = 0;
  this.fountains.length = 0;
  this.resizeIds.length = 0;
  this.width = this.$container.width();
  this.height = this.$container.height();
  this.$canvas.attr({width : this.width, height : this.height});
  this.velocity = 1;
  
  while(true){
   var distance = 0,
    velocity = this.velocity;
    
   while(velocity >= 0){
    velocity -= this.GRAVITY;
    distance += velocity;
   }
   if(distance > Math.min(this.height * (this.BASE_RATE - this.OFFSET_RATE), 500)){
    this.velocity -= 0.2;
    break;
   }
   this.velocity += 0.2;
  }
  this.gradient = this.context.createLinearGradient(0, this.height * this.BASE_RATE, 0, this.height);
  this.gradient.addColorStop(0, 'hsla(210, 80%, 5%, 0.5)');
  this.gradient.addColorStop(0.1, 'hsla(210, 80%, 5%, 0.8)');
  this.gradient.addColorStop(1, 'hsla(210, 80%, 5%, 0.9)');
  this.createElements();
 },
 createElements : function(){
  for(var i = 0, count = this.PARTICLE_COUNT * this.width / 500  * this.height / 500; i < count; i++){
   this.particles.push(new PARTICLE(this));
  }
  for(var i = -2; i <= 2; i++){
   this.fountains.push(new FOUNTAIN(this, this.width / 2 + i * Math.max(250, this.width / 5), this.height * (this.BASE_RATE - this.OFFSET_RATE), i));
  }
 },
 watchWindowSize : function(){
  while(this.resizeIds.length > 0){
   clearTimeout(this.resizeIds.pop());
  }
  this.tmpWidth = this.$window.width();
  this.tmpHeight = this.$window.height();
  this.resizeIds.push(setTimeout(this.jdugeToStopResize, this.RESIZE_INTERVAL));
 },
 jdugeToStopResize : function(){
  var width = this.$window.width(),
   height = this.$window.height(),
   stopped = (width == this.tmpWidth && height == this.tmpHeight);
   
  this.tmpWidth = width;
  this.tmpHeight = height;
  
  if(stopped){
   this.setup();
  }
 },
 reconstructMethods : function(){
  this.watchWindowSize = this.watchWindowSize.bind(this);
  this.jdugeToStopResize = this.jdugeToStopResize.bind(this);
  this.render = this.render.bind(this);
 },
 bindEvent : function(){
  this.$window.on('resize', this.watchWindowSize);
 },
 getRandomValue : function(min, max){
  return min + (max - min) * Math.random();
 },
 render : function(){
  requestAnimationFrame(this.render);
  this.context.fillStyle = 'hsla(0, 0%, 0%, 0.3)';
  this.context.fillRect(0, 0, this.width, this.height);
  this.context.save();
  this.context.globalCompositeOperation = 'lighter';
  
  for(var i = 0, count = this.particles.length; i < count; i++){
   this.particles[i].render(this.context);
  }
  for(var i = 0, count = this.fountains.length; i < count; i++){
   this.fountains[i].render(this.context);
  }
  this.context.restore();
  this.context.save();
  this.context.translate(0, this.height * this.BASE_RATE);
  this.context.scale(1, -(1 - this.BASE_RATE) / this.BASE_RATE);
  this.context.drawImage(this.$canvas.get(0), 0, 0, this.width, this.height * this.BASE_RATE, 0,  -this.height * this.BASE_RATE, this.width, this.height * this.BASE_RATE);
  this.context.restore();
  this.context.fillStyle = this.gradient;
  this.context.fillRect(0, this.height * this.BASE_RATE, this.width, this.height * (1 - this.BASE_RATE));
 }
};
var PARTICLE = function(renderer){
 this.renderer = renderer;
 this.init();
};
PARTICLE.prototype = {
 THRESHOLD : 10,
 
 init : function(){
  this.x = this.renderer.getRandomValue(-this.THRESHOLD, this.renderer.width + this.THRESHOLD);
  this.y = this.renderer.getRandomValue(-this.THRESHOLD, this.renderer.height * this.renderer.BASE_RATE + this.THRESHOLD);
  this.vx = this.renderer.getRandomValue(-0.3, 0.3);
  this.vy = this.renderer.getRandomValue(-0.3, 0.3);
  this.theta = this.renderer.getRandomValue(0, Math.PI * 2);
  this.deltaTheta = this.renderer.getRandomValue(Math.PI / 300, Math.PI / 100);
 },
 getColor : function(){
  var baseIndex = -1,
   fountains = this.renderer.fountains,
   hue = 0;
   
  for(var i = 0, count = fountains.length; i < count; i++){
   if(this.x < fountains[i].x){
    break;
   }
   baseIndex = i;
  }
  if(baseIndex == -1){
   hue = fountains[0].hue;
  }else if(baseIndex == fountains.length - 1){
   hue = fountains[fountains.length - 1].hue;
  }else{
   var dx1 = this.x - fountains[baseIndex].x,
    dx2 = fountains[baseIndex + 1].x - this.x;
   hue = fountains[baseIndex].hue * (dx2 / (dx1 + dx2)) + fountains[baseIndex + 1].hue * (dx1 / (dx1 + dx2));
  }
  return 'hsl(' + hue + ', 60%, ' + (15 * (1 + Math.sin(this.theta))) + '%)';
 },
 render : function(context){
  context.save();
  context.fillStyle = this.getColor();
  context.beginPath();
  context.arc(this.x, this.y, 1, 0, Math.PI * 2, false);
  context.fill();
  context.restore();
  
  this.x += this.vx;
  this.y += this.vy;
  this.theta += this.deltaTheta;
  this.theta %= Math.PI * 2;
  
  if(this.x < -this.THRESHOLD && this.vx < 0 || this.x > this.renderer.width + this.THRESHOLD && this.vx > 0){
   this.vx *= -1;
  }
  if(this.y < -this.THRESHOLD && this.vy < 0 || this.y > this.renderer.height * this.renderer.BASE_RATE + this.THRESHOLD && this.vy > 0){
   this.vy *= -1;
  }
 }
};
var FOUNTAIN = function(renderer, x, y, index){
 this.renderer = renderer;
 this.x = x;
 this.y = y;
 this.index = index;
 this.init();
};
FOUNTAIN.prototype = {
 init : function(){
  this.waterLines = [];
  this.hue = 60;
  this.destinationHue = this.hue + 72 * this.index;
  this.waitCount = Math.abs(this.index) * 100;
  this.count = 0;
  this.theta = 0;
  this.status = 0;
 },
 controlStatus : function(){
  switch(this.status){
  case 0:
   if(++this.count >= this.waitCount){
    this.status = 1;
   }
   break;
  case 1:
   if(++this.count >= 300){
    this.status = 2;
    this.count = 0;
   }
   break;
  case 2:
   this.hue += this.index;
   
   if(this.hue == this.destinationHue){
    this.status = 3;
   }
   break;
  case 3:
   if(++this.count == 300){
    this.status = 4;
    this.count = 0;
   }
   break;
  case 4:
   this.theta += Math.PI / 50;
   this.theta %= Math.PI * 2;
   
   if(this.count++ == 25){
    this.status = 3;
   }
  }
  return this.status > 0;
 },
 render : function(context){
  var hue = this.hue + Math.sin(this.theta) * 36;
  context.save();
  context.fillStyle = 'hsl(' + hue + ', 70%, 30%)';
  context.translate(this.x, this.y);
  context.scale(1, 0.3);
  context.beginPath();
  context.arc(0, 0, 10, 0, Math.PI * 2, false);
  context.fill();
  context.restore();
  
  if(!this.controlStatus()){
   return;
  }
  context.save();
  context.translate(this.x, this.y);
  
  for(var i = this.waterLines.length - 1; i >= 0; i--){
   if(!this.waterLines[i].render(context, hue)){
    this.waterLines.splice(i, 1);
   }
  }
  context.restore();
  this.waterLines.push(new WATER_LINE(this.renderer));
 }
};
var WATER_LINE = function(renderer){
 this.renderer = renderer;
 this.init();
};
WATER_LINE.prototype = {
 MAX_TRACES : 80,
 
 init : function(){
  var theta = this.renderer.getRandomValue(-Math.PI / 20, Math.PI / 20),
   rate = this.renderer.getRandomValue(0.8, 1);
  this.x = this.renderer.getRandomValue(-2, 2);
  this.y = 0;
  this.vx = this.renderer.velocity * Math.sin(theta) * rate;
  this.vy = -this.renderer.velocity * Math.cos(theta * this.renderer.getRandomValue(3, 6)) * rate;
  this.opacity = 1;
  this.luminance = 0;
  this.traces = [];
 },
 render : function(context, hue){
  this.traces.push({x : this.x, y : this.y});
  
  if(this.traces.length > this.MAX_TRACES){
   this.traces.shift();
  }
  context.save();
  context.strokeStyle = 'hsla(' + hue + ', 70%, ' + this.luminance + '%, ' + this.opacity + ')';
  context.beginPath();
  context.moveTo(this.traces[0].x, this.traces[0].y);
  
  for(var i = 1, count = this.traces.length; i < count; i++){
   context.lineTo(this.traces[i].x, this.traces[i].y);
  }
  context.stroke();
  context.restore();
  this.x += this.vx;
  this.y += this.vy;
  this.vy += this.renderer.GRAVITY;
  
  if(this.vy > 0){
   this.opacity -= 0.02;
  }
  if(this.luminance < 10){
   this.luminance += 0.1;
  }
  return this.opacity > 0;
 }
};
$(function(){
 RENDERER.init();
});
//]]>
</script>
<div id="jsi-fountain-container" class="container">
</div>

Hiệu ứng này yêu cầu có thư viện jquery hỗ trợ ví dụ:
<script src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js' type='text/javascript'></script>
Tổng hợp.


Publis: 

Post a Comment

🙂😬😀😂🤣😍💖
Windows + . hoặc Windows + ; để chèn emoji