源码介绍

炫酷烟花源码 - 在你的网页上来场烟花秀吧!-Bccfxs - 北城分享社

技术揭秘

在HTML5中,<canvas>元素为我们提供了一个强大的绘图平台,允许我们通过JavaScript进行绘画。烟花表演,本质上就是这种绘图技术的运用。以下是实现烟花效果的简要步骤:

初始化画布:设置画布尺寸,确保画布能够适应不同的屏幕大小。

定义烟花行为:通过编写JavaScript函数来定义烟花的运动轨迹、颜色和消失方式。

绘制烟花:使用路径(Path)和填充(fill)命令在画布上绘制圆形,模拟烟花的爆炸效果。

动画循环:通过requestAnimationFrame实现动画循环,不断地更新和重绘烟花的位置和状态。

1、创建一个 index.html 复制以下代码

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>烟花</title>

</head>

<style>

body {

margin: 0;

padding: 0;

overflow: hidden;

}

.canvasBox {

width: 100%;

height: 100%;

display: flex;

justify-content: center;

align-items: center;

}

canvas {

border: 1px solid;

background-color: #000;

}

</style>

<body>

<div class="canvasBox">

<canvas id="canvas"></canvas>

</div>

</body>

</html>

<script src="https://www.xkwo.com/article/index.js"></script>

<script>

const canvas = document.getElementById('canvas')

const canvasWidth = document.documentElement.clientWidth || document.body.clientWidth

const canvasHeight = document.documentElement.clientHeight || document.body.clientHeight

const ratio = Math.max(window.devicePixelRatio, 2)

canvas.width = canvasWidth * ratio

canvas.height = canvasHeight * ratio

canvas.style.width = canvasWidth + 'px'

canvas.style.height = canvasHeight + 'px'

const ctx = canvas.getContext('2d')

ctx.scale(ratio, ratio)

const getRandom = (min, max) => {

return Math.random() * (max - min) + min

}

const drawCircle = ({ opacity = 1, x, y, radius, color }) => {

ctx.save()

ctx.globalAlpha = opacity

ctx.beginPath()

ctx.arc(x, y, radius, 0, Math.PI * 2)

ctx.fillStyle = color

ctx.fill()

ctx.restore()

}

const deleteFromList = (list, target) => {

const index = list.findIndex(item => {

return item === target

})

list.splice(index, 1)

}

// 动画循环

// 烟花列表

const fireworkList = []

const draw = () => {

// 使用半透明清空画布,形成拖尾效果

ctx.fillStyle = 'rgba(0,0,0,0.3)'

ctx.fillRect(0, 0, canvasWidth, canvasHeight)

ctx.save()

// 修改坐标系

ctx.translate(0, canvasHeight)

ctx.scale(1, -1)

const list = [...fireworkList]

list.forEach(firework => {

firework.update()

if (firework.isEnd()) {

deleteFromList(fireworkList, firework)

}

})

ctx.restore()

requestAnimationFrame(draw)

}

draw()

// 烟花颜色列表

const createFireworkColor = () => {

const colorList = [

'#ff0043',

'#14fc56',

'#1e7fff',

'#e60aff',

'#ffbf36',

'#ffffff'

]

return colorList[Math.floor(Math.random() * colorList.length)]

}

// 发射烟花

canvas.addEventListener('click', () => {

const firework = new Firework(

{

color: createFireworkColor()

})

fireworkList.push(firework)

firework.launch()

})

</script>

2、创建一个 index.js 复制以下代码

// 爆炸碎片类

class ExplosiveDebris {

constructor(opt) {

this.firework = opt.firework

this.x = opt.x

this.y = opt.y

this.color = Math.random() > 0.2 ? opt.color : '#fff'

this.radius = opt.radius || 2

this.angle = getRandom(0, 2 * Math.PI)

this.speed = opt.speed || getRandom(0.1, 4)

this.vx = Math.cos(this.angle) * this.speed

this.vy = Math.sin(this.angle) * this.speed

this.g = opt.g || 0.98

this.time = getRandom(0.5, 1)

this.startTime = 0

// 痕迹碎片数量

this.debrisCount = opt.debrisCount || 3

// 是否要进行二次爆炸

this.secondBurst = opt.secondBurst || false

}

start() {

this.startTime = Date.now()

}

update() {

const duration = (Date.now() - this.startTime) / 1000

const vy = this.vy - this.g * duration

this.x += this.vx

this.y += vy

const progress = duration / this.time

let opacity = progress > 0.7 ? 1 - 1 * progress : 1

if (opacity < 0) opacity = 0

drawCircle({

x: this.x,

y: this.y,

color: this.color,

radius: this.radius,

opacity: opacity

})

// 添加痕迹碎片

if (this.debrisCount > 0 && Math.random() > 0.8) {

this.debrisCount--

this.firework.addDebris({

x: this.x + getRandom(-2, 2),

y: this.y + getRandom(-2, 2),

color: this.color,

radius: 0.5,

g: 0.1

})

}

return {

x: this.x,

y: this.y,

isEnd: progress >= 1

}

}

}

// 爆炸器类

class Explosive {

constructor(opt) {

this.firework = opt.firework

this.x = opt.x

this.y = opt.y

this.color = opt.color

// 爆炸碎片列表

this.debrisList = []

// 爆炸碎片数量

this.debrisNum = opt.debrisNum || getRandom(50, 400)

// 是否要二次爆炸

this.secondBurst = opt.secondBurst || this.debrisNum <= 100

//是否是第一次爆炸

this.isFirstBurst = true

}

start(debrisNum, opt = {}) {

const num = debrisNum || this.debrisNum

opt.x = opt.x || this.x

opt.y = opt.y || this.y

opt.secondBurst = this.secondBurst && this.isFirstBurst

for (let i = 0; i < num; i++) {

const explosiveDebris = new ExplosiveDebris({

firework: this.firework,

color: this.color,

...opt

})

explosiveDebris.start()

this.debrisList.push(explosiveDebris)

}

this.isFirstBurst = false

}

update() {

const list = [...this.debrisList]

list.forEach(debris => {

const res = debris.update()

if (res.isEnd) {

deleteFromList(this.debrisList, debris)

// 二次爆炸

if (debris.secondBurst) {

this.start(5, {

x: res.x,

y: res.y,

speed: 1

})

}

}

})

return {

isEnd: list.length <= 0

}

}

}

// 痕迹碎片类

class Debris {

constructor(opt = {}) {

// 颜色

this.color = opt.color || '#fff'

// 透明度

this.opacity = getRandom(0.1, 0.5)

// 半径

this.radius = opt.radius || 1

// 存在时间

this.time = getRandom(0.5, 1)

// 重力,px/s2

this.g = opt.g || 0.98

// 位置

this.x = opt.x

this.y = opt.y

// 创建的时间

this.startTime = 0

}

start() {

this.startTime = Date.now()

}

update() {

const duration = (Date.now() - this.startTime) / 1000

this.y -= this.g * duration

drawCircle({

opacity: this.opacity,

x: this.x,

y: this.y,

radius: this.radius,

color: this.color

})

return {

x: this.x,

y: this.y,

isEnd: duration > this.time

}

}

}

// 发射器类

class Launcher {

constructor(opt = {}) {

// 烟花实例

this.firework = opt.firework

// 颜色

this.color = opt.color

// 初始位置

this.x = opt.x || canvasWidth * getRandom(0.2, 0.8)

this.y = opt.y || 0

// 目标位置

this.ty = canvasHeight * getRandom(0.6, 0.8)

// 半径

this.radius = opt.radius || getRandom(2, 5)

// 发射的持续时间

this.duration = opt.duration || getRandom(2000, 3500)

// 发射时的时间

this.startTime = 0

}

start() {

this.startTime = Date.now()

}

easeOutCubic(t, b, c, d) {

return c * ((t = t / d - 1) * t * t + 1) + b

}

update() {

const x = this.x

let y = this.easeOutCubic(

Date.now() - this.startTime,

this.y,

this.ty - this.y,

this.duration

)

y = Math.min(y, this.ty)

// 透明度变小

let opacity = 1 - 1 * (y / this.ty)

if (opacity < 0) opacity = 0

this.draw(x, y, opacity)

// 添加痕迹碎片

if (Math.random() > 0.7 && opacity >= 0.1) {

this.firework.addDebris({

x: x + getRandom(-2, 2), // x坐标添加一段随机量

y

})

}

return {

x,

y,

isEnd: y >= this.ty //返回true代表发射结束

}

}

draw(x, y, opacity) {

// 外圆,烟花的颜色

drawCircle({

opacity: opacity,

x: x,

y: y,

radius: this.radius,

color: this.color

})

// 内圆,白色

drawCircle({

opacity: opacity,

x: x,

y: y,

radius: this.radius / 2,

color: '#fff'

})

}

}

// 烟花类

class Firework {

constructor(opt = {}) {

// 颜色

this.color = opt.color || tinycolor.random().toHexString()

// 发射器

this.launcher = null

// 爆炸器

this.explosive = null

// 烟花状态:waiting(等待发射)、launching(发射中)、bursting(爆炸中)、end(烟花结束)

this.status = 'waiting'

// 痕迹碎片列表

this.debrisList = []

}

// 发射

launch() {

this.launcher = new Launcher({

firework: this,

color: this.color

})

this.launcher.start()

this.status = 'launching'

}

// 爆炸

burst({ x, y }) {

this.explosive = new Explosive({

firework: this,

x,

y,

color: this.color

})

this.explosive.start()

}

// 更新

update() {

if (this.status === 'launching') {

const res = this.launcher.update()

if (res.isEnd) {

this.status = 'bursting'

this.burst(res)

}

} else if (this.status === 'bursting') {

const res = this.explosive.update()

if (res.isEnd) {

this.status = 'end'

}

}

// 更新痕迹碎片

this.updateDebris()

}

// 添加痕迹碎片

addDebris(opt = {}) {

const debris = new Debris({

...opt,

color: opt.color || this.color

})

debris.start()

this.debrisList.push(debris)

}

// 更新痕迹碎片

updateDebris() {

const list = [...this.debrisList]

list.forEach(debris => {

const res = debris.update()

if (res.isEnd) {

deleteFromList(this.debrisList, debris)

}

})

}

isEnd() {

return this.status === 'end'

}

}

3、给自己放个烟花秀吧

创建一个文件夹,将以上两个文件 index.html & index.js 放到创建的文件夹中

在电脑端双击打开 index.html,即可在浏览器中打开页面,点击屏幕给自己放个烟花秀吧

!!!

  1. 转载请保留原文链接谢谢!
  2. 本站所有资源文章出自互联网收集整理,本站不参与制作,如果侵犯了您的合法权益,请联系本站我们会及时删除。
  3. 本站发布资源来源于互联网,可能存在水印或者引流等信息,请用户擦亮眼睛自行鉴别,做一个有主见和判断力的用户。
  4. 本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。
  5. 联系方式(#替换成@):bccfxs&proton.me