More code, read carefully!!
preview
Full project preview —- preview address;
Properties design
Fireworks state: Fireworks should have three states:
- launch
- Waiting for the crack
- After the burst
Fireworks: launch point (X, Y), explosion point (xEnd, yEnd), wait time after lift-off (wait), number of particles after blasting (count), fireworks radius (RADIUS)
The particle after fireworks burst: its position (X, Y), its size (size), its speed (rate), maximum fireworks radius (RADIUS).
Config: global variables and control parameters, including canvas width and height, setting fireworks properties, etc.
Setting global variables
const config = {
width: 360.height: 600.canvases: ['bg'.'firework'].skyColor: '210, 60%, 5% and 0.2)'.fireworkTime: {min:30.max:60},
// The fireworks parameter itself has a default value
fireworkOpt:{
x: undefined.y: undefined.xEnd: undefined.yEnd: undefined.count: 300.// Number of particles after blasting
wait: undefined.// After disappearing => Burst wait time}}Copy the code
Construction of microparticles
class Particle{
// The default value
constructor({x, y, size = 1, radius = 1.2{} = {})this.x = x;
this.y = y;
this.size = size;
this.rate = Math.random(); // Each particle moves at a randomly different speed
this.angle = Math.PI * 2 * Math.random(); // The offset Angle of each particle
// Each particle movement is decomposed into a horizontal and vertical movement.
this.vx = radius * Math.cos(this.angle) * this.rate;
this.vy = radius * Math.sin(this.angle) * this.rate;
}
go(){
this.x += this.vx;
this.y += this.vy;
this.vy += 0.02; // The greater the gravity effect y, the lower it actually is
// Air resistance
this.vx *= 0.98;
this.vy *= 0.98;
}
// Draw the positions of the particles
render(ctx){
this.go();
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0.Math.PI * 2.false); ctx.fill(); }}Copy the code
Building fireworks class
class Firework{
constructor({x, y = config.height, xEnd, yEnd, count = 300, wait} = {}){
// Fireworks themselves
this.x = x || config.width / 8 + Math.random() * config.width * 3 / 4;
this.y = y;
this.xEnd = xEnd || this.x;
this.yEnd = yEnd || config.width / 8 + Math.random() * config.width * 3 / 8;
this.size = 2;
this.velocity = - 3;
this.opacity = 0.8;
this.color = `hsla(The ${360 * Math.random() | 0}`, 80%, 60%, 1);
this.wait = wait || 30 + Math.random() * 30;
// Number of particles, etc
this.count = count;
this.particles = [];
this.createParticles();
this.status = 1;
}
// Create a particle
createParticles(){
for(let i = 0; i <this.count; ++i){
this.particles.push(new Particle({x:this.xEnd, y:this.yEnd})); }}/ / launch
rise(){
this.y += this.velocity * 1;
this.velocity += 0.005; // Drag during liftoff
// The fireworks begin to fade away when they reach their target
if(this.y - this.yEnd <= 50) {this.opacity = (this.y - this.yEnd) / 50;
}
// If you reach the target position, start the second state
if(this.y <= this.yEnd){
this.status = 2; }}// Render fireworks returns false when all actions are complete
render(ctx){
switch(this.status){
case 1: / / launch
ctx.save();
ctx.beginPath();
ctx.globalCompositeOperation = 'lighter';
ctx.globalAlpha = this.opacity;
ctx.translate(this.x, this.y);
ctx.scale(0.8.2.3);
ctx.translate(-this.x, -this.y);
ctx.fillStyle = this.color;
ctx.arc(this.x + Math.sin(Math.PI * 2 * Math.random()) / 1.2.this.y, this.size, 0.Math.PI * 2.false);
ctx.fill();
ctx.restore();
this.rise();
return true;
break;
case 2: // The fireworks disappear stage, waiting to explode
if(--this.wait <= 0) {this.opacity = 1;
this.status = 3;
}
return true;
break;
case 3: // Render firework particles after blasting
ctx.save();
ctx.globalCompositeOperation = 'lighter';
ctx.globalAlpha = this.opacity;
ctx.fillStyle = this.color;
for(let i = 0; i <this.particles.length; ++i){this.particles[i].render(ctx);
}
ctx.restore();
this.opacity -= 0.01;
return this.opacity > 0;
break;
default:
return false; }}}Copy the code
set off fireworks
const canvas = {
init: function(){
// Some attribute Settings can be ignored
this.setProperty();
this.renderBg();
// Loop body ** main
this.loop();
},
setProperty: function(){
this.fireworks = [];
this.width = config.width;
this.height = config.height;
this.fireworkTime = (config.fireworkTime.min + (config.fireworkTime.max - config.fireworkTime.min) * Math.random()) | 0;
this.bgCtx = document.querySelector('#bg').getContext('2d');
this.fireworkCtx = document.querySelector('#firework').getContext('2d');
},
renderBg(){
this.bgCtx.fillStyle = 'hsla (210, 60%, 5% and 0.9)'
this.bgCtx.fillRect(0.0.this.width, this.height);
},
loop(){
requestAnimationFrame(this.loop.bind(this));
this.fireworkCtx.clearRect(0.0.this.width, this.height);
// Randomly create fireworks
if(--this.fireworkTime <= 0) {this.fireworks.push(new Firework(config.fireworkOpt));
/ / every time point after resetting the fireworks produce time (| 0 into integer)
this.fireworkTime = (config.fireworkTime.min + (config.fireworkTime.max - config.fireworkTime.min) * Math.random()) | 0;
}
for(let i = this.fireworks.length - 1; i >= 0; --i){
// Render fireworks (remove fireworks if return value is false)
!this.fireworks[i].render(this.fireworkCtx) && this.fireworks.splice(i,1);
}
}
}
canvas.init();
Copy the code
perfect
Now the fireworks are like this, it feels like a little tail is missing.
Now we are clearing the canvas for each frame. It is easy to add the tail. Instead of clearing the canvas for each frame, we will cover it with a new layer of transparent sky.
/ / canvas. Loop method
// this.fireworkCtx.clearRect(0, 0, this.width, this.height);
this.fireworkCtx.fillStyle = config.skyColor;
this.fireworkCtx.fillRect(0.0.this.width,this.height);
Copy the code
And then it looks like this.
However, the scene where the sky lightens up at the moment of the explosion is still missing.
So when painting fireworks, the first will get the color and transparency of fireworks.
// *****Firework constructor
// this.color = `hsla(${360 * Math.random() | 0},80%,60%,1)`;
this.hue = 360 * Math.random() | 0;
this.color = `hsla(The ${this.hue}`, 80%, 60%, 1);
Copy the code
// *****Firework adds instance methods
getSkyColor(){
const skyColor = {
// Only the burst phase can return brightness
lightness: this.status == 3 ? this.opacity : 0 ,
hue: this.hue
};
return skyColor;
}
Copy the code
// *****config Modify the skyColor of config
// skyColor: 'hSLA (210, 60%, 5%, 0.2)',
skyColor: 'hsla ({hue}, 60%, {lightness} %, 0.2)'.Copy the code
/ / canvas. Loop method
//this.fireworkCtx.fillStyle = config.skyColor;
// Replace hue and brightness values each time.
this.fireworkCtx.fillStyle = config.skyColor.replace('{lightness}'.5 + this.skyColor.lightness * 15).replace('{hue}' , this.skyColor.hue);
this.skyColor = { / / new
lightness: 0.hue: 210
};
for(let i = this.fireworks.length - 1; i >= 0; --i){
// Add the sky color to the brightest fireworks color
this.skyColor = this.skyColor.lightness >= this.fireworks[i].getSkyColor().lightness ? this.skyColor : this.fireworks[i].getSkyColor();
!this.fireworks[i].render(this.fireworkCtx) && this.fireworks.splice(i,1);
}
Copy the code
And now we’re done.
Complete the project
Github project address
If you think so, please star one.
Fireworks making reference links
I refer to many works on codepen. IO.
Fireworks seen in the countryside
fireworks seen in the countryside