canvas烟花实现
2 分钟阅读
闲来无事的时候想起了一个文章里看的canvas制作烟花,今天暂且贴上,改日给大家做进一步的剖析
HTML部分
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
canvas {
position: absolute;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="1913" height="796"></canvas>
<canvas id="firework" width="1913" height="796"></canvas>
<script src="./main.js"></script>
</body>
</html>JS部分
PS:由于是一个小demo 并没有做模块拆分 都写在一个里了 希望大家自己做的时候可以分解一下 有助于自己对模块化的理解
javascript
const Config = {
width: window.innerWidth,
height: window.innerHeight,
skyColor: 'hsla(hue, 60%, light%, 0.2)',
fireworkTime: {min: 30, max: 150},
fireworkOpt: {
x: undefined,
y: undefined,
xEnd: undefined,
yEnd: undefined,
count: 500,
wait: 10
}
}
class Firework {
constructor ({x, y = Config.height, xEnd, yEnd, count = Config.fireworkOpt.count, wait} = {}) {
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.wait = wait || 30 + Math.random() * 30
this.count = count
this.particles = []
this.createParticles()
this.status = 1
this.hue = 360 * Math.random() | 0
this.color = `hsla(${this.hue},80%,60%,1)`
}
getSkyColor () {
const skyColor = {
lightness: this.status === 3 ? this.opacity : 0,
hue: this.hue
}
return skyColor
}
createParticles () {
for (let i = 0; i < this.count; ++i) {
this.particles.push(new Particle({x: this.xEnd, y: this.yEnd}))
}
}
rise () {
this.y += this.velocity
this.velocity += 0.005
if (this.y - this.yEnd <= 50) {
this.opacity = (this.y - this.yEnd) / 50
}
if (this.y <= this.yEnd) {
this.status = 2
}
}
draw (ctx) {
switch (this.status) {
case 1:
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:
if (--this.wait <= 0) {
this.opacity = 1
this.status = 3
}
return true
break
case 3:
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].draw(ctx)
}
ctx.restore()
this.opacity -= 0.005
return this.opacity >= 0
break
default:
return false
}
}
}
class Particle {
constructor ({x, y, size = 1, radius = 6} = {}) {
this.x = x
this.y = y
this.size = size
this.rate = Math.random()
this.angle = Math.PI * 2 * Math.random()
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
this.vx *= 0.98
this.vy *= 0.98
}
draw (ctx) {
this.go()
ctx.beginPath()
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false)
ctx.fill()
}
}
const canvas = {
init () {
this.skyColor = {
lightness: 0,
hue: 210
}
this.setProperty()
this.drawBg()
this.loop()
},
setProperty () {
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('#myCanvas').getContext('2d')
this.fireworkCtx = document.querySelector('#firework').getContext('2d')
},
drawBg () {
this.bgCtx.fillStyle = 'hsla(210, 60%, 5%, 0.9)'
this.bgCtx.fillRect(0, 0, this.width, this.height)
},
loop () {
// this.fireworkCtx.clearRect(0, 0, this.width, this.height)
requestAnimationFrame(this.loop.bind(this))
this.fireworkCtx.fillStyle = Config.skyColor.replace('light', 5 + this.skyColor.lightness * 15).replace('hue', this.skyColor.hue)
this.fireworkCtx.fillRect(0, 0, this.width, this.height)
if (--this.fireworkTime <= 0) {
this.fireworks.push(new Firework(Config.fireworkOpt))
this.fireworkTime = (Config.fireworkTime.min + (Config.fireworkTime.max - Config.fireworkTime.min) * Math.random()) | 0
}
for (let i = this.fireworks.length - 1; i >= 0; --i) {
!this.fireworks[i].draw(this.fireworkCtx) && this.fireworks.splice(i, 1)
}
for (let i = this.fireworks.length - 1; i >= 0; --i) {
this.skyColor = this.skyColor.lightness >= (this.fireworks[i].getSkyColor().lightness + 50) ? this.skyColor : this.fireworks[i].getSkyColor()
!this.fireworks[i].draw(this.fireworkCtx) && this.fireworks.splice(i, 1)
console.log(this.fireworks.length)
}
}
}
canvas.init()
大家可以自行观察一下效果 并对此做一些理解 希望对大家有所帮助