依星源码资源网,依星资源网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

限时开通VIP永久会员,可免费下载所有附件
查看: 10|回复: 0

[html模板] 【炫酷!在你的网页上来场烟花秀吧!】(附源码)

[复制链接] 主动推送

1万

主题

1万

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
11646
发表于 7 小时前 | 显示全部楼层 |阅读模式
【炫酷!在你的网页上来场烟花秀吧!】(附源码)

技术揭秘

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

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

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

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

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

【炫酷!在你的网页上来场烟花秀吧!】(附源码)

【炫酷!在你的网页上来场烟花秀吧!】(附源码)

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

  1. <!DOCTYPE html>

  2. <html lang="en">

  3. <head>

  4.   <meta charset="UTF-8">

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

  6.   <title>烟花</title>

  7. </head>

  8. <style>

  9.   body {

  10.     margin: 0;

  11.     padding: 0;

  12.     overflow: hidden;

  13.   }



  14.   .canvasBox {

  15.     width: 100%;

  16.     height: 100%;

  17.     display: flex;

  18.     justify-content: center;

  19.     align-items: center;

  20.   }

  21.   canvas {

  22.     border: 1px solid;

  23.     background-color: #000;

  24.   }

  25. </style>



  26. <body>

  27.   <div class="canvasBox">

  28.     <canvas id="canvas"></canvas>

  29.   </div>

  30. </body>



  31. </html>

  32. <script src="./index.js"></script>

  33. <script>

  34.   const canvas = document.getElementById('canvas')

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

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

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

  38.   canvas.width = canvasWidth * ratio

  39.   canvas.height = canvasHeight * ratio

  40.   canvas.style.width = canvasWidth + 'px'

  41.   canvas.style.height = canvasHeight + 'px'



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

  43.   ctx.scale(ratio, ratio)



  44.   const getRandom = (min, max) => {

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

  46.   }



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

  48.     ctx.save()

  49.     ctx.globalAlpha = opacity

  50.     ctx.beginPath()

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

  52.     ctx.fillStyle = color

  53.     ctx.fill()

  54.     ctx.restore()

  55.   }

  56.   const deleteFromList = (list, target) => {

  57.     const index = list.findIndex(item => {

  58.       return item === target

  59.     })

  60.     list.splice(index, 1)

  61.   }

  62.   // 动画循环

  63.   // 烟花列表

  64.   const fireworkList = []

  65.   const draw = () => {

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

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

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



  69.     ctx.save()



  70.     // 修改坐标系

  71.     ctx.translate(0, canvasHeight)

  72.     ctx.scale(1, -1)



  73.     const list = [...fireworkList]

  74.     list.forEach(firework => {

  75.       firework.update()

  76.       if (firework.isEnd()) {

  77.         deleteFromList(fireworkList, firework)

  78.       }

  79.     })



  80.     ctx.restore()



  81.     requestAnimationFrame(draw)

  82.   }

  83.   draw()



  84.   // 烟花颜色列表

  85.   const createFireworkColor = () => {

  86.     const colorList = [

  87.       '#ff0043',

  88.       '#14fc56',

  89.       '#1e7fff',

  90.       '#e60aff',

  91.       '#ffbf36',

  92.       '#ffffff'

  93.     ]

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

  95.   }



  96.   // 发射烟花

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

  98.     const firework = new Firework(



  99. {

  100.       color: createFireworkColor()

  101.     })

  102.     fireworkList.push(firework)

  103.     firework.launch()

  104.   })



  105. </script>
复制代码

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

  1. // 爆炸碎片类

  2. class ExplosiveDebris {

  3.   constructor(opt) {

  4.     this.firework = opt.firework

  5.     this.x = opt.x

  6.     this.y = opt.y

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

  8.     this.radius = opt.radius || 2

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

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

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

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

  13.     this.g = opt.g || 0.98

  14.     this.time = getRandom(0.5, 1)

  15.     this.startTime = 0

  16.     // 痕迹碎片数量

  17.     this.debrisCount = opt.debrisCount || 3

  18.     // 是否要进行二次爆炸

  19.     this.secondBurst = opt.secondBurst || false

  20.   }



  21.   start() {

  22.     this.startTime = Date.now()

  23.   }



  24.   update() {

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

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

  27.     this.x += this.vx

  28.     this.y += vy

  29.     const progress = duration / this.time

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

  31.     if (opacity < 0) opacity = 0

  32.     drawCircle({

  33.       x: this.x,

  34.       y: this.y,

  35.       color: this.color,

  36.       radius: this.radius,

  37.       opacity: opacity

  38.     })

  39.     // 添加痕迹碎片

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

  41.       this.debrisCount--

  42.       this.firework.addDebris({

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

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

  45.         color: this.color,

  46.         radius: 0.5,

  47.         g: 0.1

  48.       })

  49.     }

  50.     return {

  51.       x: this.x,

  52.       y: this.y,

  53.       isEnd: progress >= 1

  54.     }

  55.   }

  56. }





  57. // 爆炸器类

  58. class Explosive {

  59.   constructor(opt) {

  60.     this.firework = opt.firework

  61.     this.x = opt.x

  62.     this.y = opt.y

  63.     this.color = opt.color

  64.     // 爆炸碎片列表

  65.     this.debrisList = []

  66.     // 爆炸碎片数量

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

  68.     // 是否要二次爆炸

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

  70.     //是否是第一次爆炸

  71.     this.isFirstBurst = true

  72.   }



  73.   start(debrisNum, opt = {}) {

  74.     const num = debrisNum || this.debrisNum

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

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

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

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

  79.       const explosiveDebris = new ExplosiveDebris({

  80.         firework: this.firework,

  81.         color: this.color,

  82.         ...opt

  83.       })

  84.       explosiveDebris.start()

  85.       this.debrisList.push(explosiveDebris)

  86.     }

  87.     this.isFirstBurst = false

  88.   }



  89.   update() {

  90.     const list = [...this.debrisList]

  91.     list.forEach(debris => {

  92.       const res = debris.update()

  93.       if (res.isEnd) {

  94.         deleteFromList(this.debrisList, debris)

  95.         // 二次爆炸

  96.         if (debris.secondBurst) {

  97.           this.start(5, {

  98.             x: res.x,

  99.             y: res.y,

  100.             speed: 1

  101.           })

  102.         }

  103.       }

  104.     })

  105.     return {

  106.       isEnd: list.length <= 0

  107.     }

  108.   }

  109. }



  110. // 痕迹碎片类

  111. class Debris {

  112.   constructor(opt = {}) {

  113.     // 颜色

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

  115.     // 透明度

  116.     this.opacity = getRandom(0.1, 0.5)

  117.     // 半径

  118.     this.radius = opt.radius || 1

  119.     // 存在时间

  120.     this.time = getRandom(0.5, 1)

  121.     // 重力,px/s2

  122.     this.g = opt.g || 0.98

  123.     // 位置

  124.     this.x = opt.x

  125.     this.y = opt.y

  126.     // 创建的时间

  127.     this.startTime = 0

  128.   }



  129.   start() {

  130.     this.startTime = Date.now()

  131.   }



  132.   update() {

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

  134.     this.y -= this.g * duration

  135.     drawCircle({

  136.       opacity: this.opacity,

  137.       x: this.x,

  138.       y: this.y,

  139.       radius: this.radius,

  140.       color: this.color

  141.     })

  142.     return {

  143.       x: this.x,

  144.       y: this.y,

  145.       isEnd: duration > this.time

  146.     }

  147.   }

  148. }





  149. // 发射器类

  150. class Launcher {

  151.   constructor(opt = {}) {

  152.     // 烟花实例

  153.     this.firework = opt.firework

  154.     // 颜色

  155.     this.color = opt.color

  156.     // 初始位置

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

  158.     this.y = opt.y || 0

  159.     // 目标位置

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

  161.     // 半径

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

  163.     // 发射的持续时间

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

  165.     // 发射时的时间

  166.     this.startTime = 0

  167.   }



  168.   start() {

  169.     this.startTime = Date.now()

  170.   }



  171.   easeOutCubic(t, b, c, d) {

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

  173.   }



  174.   update() {

  175.     const x = this.x

  176.     let y = this.easeOutCubic(

  177.       Date.now() - this.startTime,

  178.       this.y,

  179.       this.ty - this.y,

  180.       this.duration

  181.     )

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

  183.     // 透明度变小

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

  185.     if (opacity < 0) opacity = 0

  186.     this.draw(x, y, opacity)

  187.     // 添加痕迹碎片

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

  189.       this.firework.addDebris({

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

  191.         y

  192.       })

  193.     }

  194.     return {

  195.       x,

  196.       y,

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

  198.     }

  199.   }

  200.   draw(x, y, opacity) {

  201.     // 外圆,烟花的颜色

  202.     drawCircle({

  203.       opacity: opacity,

  204.       x: x,

  205.       y: y,

  206.       radius: this.radius,

  207.       color: this.color

  208.     })

  209.     // 内圆,白色

  210.     drawCircle({

  211.       opacity: opacity,

  212.       x: x,

  213.       y: y,

  214.       radius: this.radius / 2,

  215.       color: '#fff'

  216.     })

  217.   }

  218. }



  219. // 烟花类

  220. class Firework {

  221.   constructor(opt = {}) {

  222.     // 颜色

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

  224.     // 发射器

  225.     this.launcher = null

  226.     // 爆炸器

  227.     this.explosive = null

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

  229.     this.status = 'waiting'

  230.     // 痕迹碎片列表

  231.     this.debrisList = []

  232.   }



  233.   // 发射

  234.   launch() {

  235.     this.launcher = new Launcher({

  236.       firework: this,

  237.       color: this.color

  238.     })

  239.     this.launcher.start()

  240.     this.status = 'launching'

  241.   }



  242.   // 爆炸

  243.   burst({ x, y }) {

  244.     this.explosive = new Explosive({

  245.       firework: this,

  246.       x,

  247.       y,

  248.       color: this.color

  249.     })

  250.     this.explosive.start()

  251.   }



  252.   // 更新

  253.   update() {

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

  255.       const res = this.launcher.update()

  256.       if (res.isEnd) {

  257.         this.status = 'bursting'

  258.         this.burst(res)

  259.       }

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

  261.       const res = this.explosive.update()

  262.       if (res.isEnd) {

  263.         this.status = 'end'

  264.       }

  265.     }

  266.     // 更新痕迹碎片

  267.     this.updateDebris()

  268.   }



  269.   // 添加痕迹碎片

  270.   addDebris(opt = {}) {

  271.     const debris = new Debris({

  272.       ...opt,

  273.       color: opt.color || this.color

  274.     })

  275.     debris.start()

  276.     this.debrisList.push(debris)

  277.   }



  278.   // 更新痕迹碎片

  279.   updateDebris() {

  280.     const list = [...this.debrisList]

  281.     list.forEach(debris => {

  282.       const res = debris.update()

  283.       if (res.isEnd) {

  284.         deleteFromList(this.debrisList, debris)

  285.       }

  286.     })

  287.   }



  288.   isEnd() {

  289.     return this.status === 'end'

  290.   }

  291. }
复制代码

3、给自己放个烟花秀吧

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

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

!!!



相关帖子

扫码关注微信公众号,及时获取最新资源信息!下载附件优惠VIP会员5折;永久VIP免费
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

免责声明:
1、本站提供的所有资源仅供参考学习使用,版权归原著所有,禁止下载本站资源参与商业和非法行为,请在24小时之内自行删除!
2、本站所有内容均由互联网收集整理、网友上传,并且以计算机技术研究交流为目的,仅供大家参考、学习,请勿任何商业目的与商业用途。
3、若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。
4、论坛的所有内容都不保证其准确性,完整性,有效性,由于源码具有复制性,一经售出,概不退换。阅读本站内容因误导等因素而造成的损失本站不承担连带责任。
5、用户使用本网站必须遵守适用的法律法规,对于用户违法使用本站非法运营而引起的一切责任,由用户自行承担
6、本站所有资源来自互联网转载,版权归原著所有,用户访问和使用本站的条件是必须接受本站“免责声明”,如果不遵守,请勿访问或使用本网站
7、本站使用者因为违反本声明的规定而触犯中华人民共和国法律的,一切后果自己负责,本站不承担任何责任。
8、凡以任何方式登陆本网站或直接、间接使用本网站资料者,视为自愿接受本网站声明的约束。
9、本站以《2013 中华人民共和国计算机软件保护条例》第二章 “软件著作权” 第十七条为原则:为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。若有学员需要商用本站资源,请务必联系版权方购买正版授权!
10、本网站如无意中侵犯了某个企业或个人的知识产权,请来信【站长信箱312337667@qq.com】告之,本站将立即删除。
郑重声明:
本站所有资源仅供用户本地电脑学习源代码的内含设计思想和原理,禁止任何其他用途!
本站所有资源、教程来自互联网转载,仅供学习交流,不得商业运营资源,不确保资源完整性,图片和资源仅供参考,不提供任何技术服务。
本站资源仅供本地编辑研究学习参考,禁止未经资源商正版授权参与任何商业行为,违法行为!如需商业请购买各资源商正版授权
本站仅收集资源,提供用户自学研究使用,本站不存在私自接受协助用户架设游戏或资源,非法运营资源行为。
 
在线客服
点击这里给我发消息 点击这里给我发消息 点击这里给我发消息
售前咨询热线
312337667

微信扫一扫,私享最新原创实用干货

QQ|免责声明|小黑屋|依星资源网 ( 鲁ICP备2021043233号-3 )|网站地图

GMT+8, 2024-10-28 18:21

Powered by Net188.com X3.4

邮箱:312337667@qq.com 客服QQ:312337667(工作时间:9:00~21:00)

快速回复 返回顶部 返回列表