文章目录
- 一、前言
- 二、创意名
- 三、效果展示
- 四、烟花代码
- 五、总结
一、前言
2022年圣诞节到来啦,圣诞节是基督教纪念耶稣诞生的重要节日。亦称耶稣圣诞节、主降生节,天主教亦称耶稣圣诞瞻礼。耶稣诞生的日期,《圣经》并无记载。公元336年罗马教会开始在12月25日过此节。12月25日原是罗马帝国规定的太阳神诞辰。有人认为选择这天庆祝圣诞,是因为基督教徒认为耶稣就是正义、永恒的太阳。5世纪中叶以后,圣诞节作为重要节日,成了教会的传统,并在东西派教会中逐渐传开。因所用历法不同等原因,各教派会举行庆祝的具体日期和活动形式也有差别。圣诞节习俗传播到亚洲主要是在十九世纪中叶,日本、韩国等都受到了圣诞文化的影响。现在西方在圣诞节常互赠礼物,举行欢宴,并以圣诞老人、圣诞树等增添节日气氛,已成为普遍习俗。圣诞节也成为西方世界以及其他很多地区的公共假日。
二、创意名
圣诞节就要到了,本篇我们将用html+js写一个动态的烟花代码,程序员的浪漫这不就来了吗,感兴趣的小伙伴可下载学习,安静的在家中读懂它的那一刻,在这疫情肆虐的日子里也是一件很不错的事,将有趣的东西分享给你,希望你度过一个愉快的圣诞节!
三、效果展示
基础版动画效果,有声音
进阶版动画效果,可点击绽放烟花
四、烟花代码
动画主要由焰火类,背景图和随机函数等组成。进阶版可点击屏幕直接开始绽放烟花。
以下是HTML部分,完整代码及效果点击下载烟花代码
进阶版烟花代码2
<!doctype html><html><head> <meta charset="utf-8"> <title>动态烟花代码</title> <style> html, * { margin: 0; padding: 0 } body { background-image: url(bg.png); background-size: 100% 100%; background-size: 100%; background-repeat:no-repeat; } .demo { margin: 0 auto; width: 100%; height: 100%; } h1 { margin: 150px auto 30px auto; text-align: center; font-family: 'Roboto'; } </style></head><body> <div class="demo"> </div> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script> <script src="fireworks.js"></script> <script> $('.demo').fireworks({ sound: true, opacity: 0.6, width: '100%', height: '100%' }); </script></body></html>
js部分
// 焰火集合类class Fireworks { _timer = null _animater = null _useAnimationFrame = true ctx = null // 画布上下文,都画这上面 offScreenCtx = null // 离屏 canvas,优化性能 fps = 60 // 帧率控制 fireworks = [] // 焰火数组 fireworkCount = 8 // 焰火数量 fireworkInterval = 400 // 焰火爆炸间隔 fireworkColors = DEFAULT_COLORS // 焰火颜色随机取值数组 particleOptions = { // 粒子配置 size: 15, // 几块钱的烟花 speed: 15, // 燃烧的速度 gravity: 0.08, // 地球的引力,向下的 power: 0.93, // 动力,值越大冲越远 shrink: 0.97, // 燃料消耗的速度 jitter: 1, // 摇摇晃摇 color: 'hsla(210, 100%, 50%, 1)', // 颜色 } constructor(dom, options = {}) { if (!(dom instanceof HTMLElement)) { options = dom || {} } if (!dom) { dom = document.body } this.initCanvas(dom) const { particleOptions = {}, ...others } = options this.particleOptions = { ...this.particleOptions, ...particleOptions } Object.keys(others).forEach(key => this[key] = others[key]) this._useAnimationFrame = this.fps >= 60 } // 初始化画布 initCanvas(dom) { let canvas = dom const isCanvas = canvas.nodeName.toLowerCase() === 'canvas' if (!isCanvas) { canvas = document.createElement('canvas') dom.appendChild(canvas) } const { width, height } = dom.getBoundingClientRect() canvas.width = width canvas.height = height canvas.style.cssText = `width: ${width}px; height: ${height}px;` this.ctx = canvas.getContext('2d') const offScreenCanvas = canvas.cloneNode() this.offScreenCtx = offScreenCanvas.getContext('2d') } // 创建单个焰火 createFirework(x, y, color) { const { ctx, particleOptions, fireworkColors } = this const { width, height } = ctx.canvas x = x ?? random(width * 0.1, width * 0.9) y = y ?? random(height * 0.1, height * 0.9) color = color ?? random(fireworkColors) const particleCount = random(80, 100) const firework = new Firework({ particleOptions, particleCount, x, y, color }) this.fireworks.push(firework) } // 焰火燃尽,无情灭之 checkFireworks() { this.fireworks = this.fireworks.filter(firework => !firework.isBurnOff()) } // 检查是否需要创建焰火 loop() { let interval = this.fireworkInterval * random(0.5, 1) this._timer = setTimeout(() => { this.checkFireworks() if (this.fireworks.length < this.fireworkCount) { this.createFirework() } this.loop() }, interval) } // 绘制焰火 render(animationFunction, interval) { this._animater = animationFunction(() => { const { width, height } = this.ctx.canvas // 通过绘制黑色透明图层,达到尾焰的效果 this.ctx.fillStyle = 'rgba(0, 0, 0, 0.05)' this.ctx.fillRect(0, 0, width, height) this.offScreenCtx.clearRect(0, 0, width, height) this.fireworks.forEach(firework => { firework.render(this.offScreenCtx) }) this.ctx.save() this.ctx.globalCompositeOperation = 'lighter' this.ctx.drawImage(this.offScreenCtx.canvas, 0, 0, width, height) this.ctx.restore() this.render(animationFunction, interval) }, interval) } // 前进四 !!! start() { this.loop() // 60 帧就用 requestAnimationFrame,否则用 setTimeout const animationFunction = this._useAnimationFrame ? requestAnimationFrame : setTimeout const interval = 16.67 * (60 / this.fps) this.render(animationFunction, interval) } // 休息一下 pause() { this._timer && clearTimeout(this._timer) this._animater && (this._useAnimationFrame ? cancelAnimationFrame(this._animater) : clearTimeout(this._animater)) this._timer = null this._animater = null } // 结束吧这个世界 stop() { this.pause() this.fireworks.length = 0 const { width, height } = this.ctx.canvas() this.ctx.clearRect(0, 0, width, height) } } // 焰火类 class Firework { _status = STATUS.INIT x = 0 y = 0 color = 'rgba(255, 255, 255, 1)' particleCount = 80 particles = [] particleOptions = {} constructor(options = {}) { Object.keys(options).forEach(key => this[key] = options[key]) this._status = STATUS.INIT this.initParticles() } // 初始化粒子 initParticles() { const { x, y, color, particleOptions } = this const { size: baseSize } = particleOptions for (let index = 0; index < this.particleCount; index++) { const size = random(-baseSize / 2, baseSize / 2) + baseSize const particle = new Particle({ ...particleOptions, x, y, size, color }) this.particles.push(particle) } } // 更新粒子 updateParticles() { this.particles.forEach(particle => particle.update()) this.particles = this.particles.filter(particle => !particle.isBurnOff()) // 拥有的粒子都燃尽了,自己也就结束了 if (this.particles.length === 0) { this._status = STATUS.COMPLETED } } // 渲染粒子 render(ctx) { this.updateParticles() if (this.isBurnOff()) return this.particles.forEach(particle => { particle.render(ctx) }) } isBurnOff() { return this._status === STATUS.COMPLETED } } // 焰火粒子类 class Particle { size = 10 speed = 15 gravity = 0.2 power = 0.92 shrink = 0.93 jitter = 0.08 color = 'hsla(210, 100%, 50%, 1)' shadowColor = 'hsla(210, 100%, 50%, 0.1)' x = 0 // x 坐标位置 y = 0 // y 坐标位置 vel = { // 速度 x: 0, y: 0, } constructor(options) { Object.keys(options).forEach(key => { this[key] = options[key] }) const angle = random(0, Math.PI * 2) const speed = Math.cos(random(0, Math.PI / 2)) * this.speed this.vel = { x: Math.cos(angle) * speed, y: Math.sin(angle) * speed, } this.shadowColor = tinycolor(this.color).setAlpha(0.1) } // 移形换位 update() { this.vel.x *= this.power this.vel.y *= this.power this.vel.y += this.gravity const jitter = random(-1, 1) * this.jitter this.x += this.vel.x + jitter this.y += this.vel.y + jitter this.size *= this.shrink } // 绘制单粒子 render(ctx) { if (this.isBurnOff()) return ctx.save() const { x, y, size, color, shadowColor } = this // 红里透白,像极了爱情 const gradient = ctx.createRadialGradient(x, y, 0, x, y, size / 2) gradient.addColorStop(0.1, 'rgba(255, 255, 255, 0.3)') gradient.addColorStop(0.6, color) gradient.addColorStop(1, shadowColor) ctx.fillStyle = gradient // ctx.beginPath() // ctx.arc(x, y, size, 0, Math.PI * 2, true) // ctx.closePath() // ctx.fill() // 绘制矩形性能更好 ctx.fillRect(x, y, size, size) ctx.restore() } // 小到看不到 isBurnOff() { return this.size < 1 } }
五、总结
圣诞节,玲儿响,温情祝福传递忙;喜盛宴,披红装,圣诞金娃送吉祥;夜月美,心儿醉,吉祥安康永相随;平安夜,送平安,幸福快乐人变美。最后,祝所有和我一样即将考研的人旗开得胜,坚持就是胜利,世上无难事,只要肯攀登。