流氓资源网 - 专注免费分享最优质的网络资源,技术教程分享网!

7.6
7.6
7.6
7.6

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

流氓小编 源码仓库
扫码手机访问【炫酷!在你的网页上来场烟花秀吧!】(附源码)
0
      【炫酷!在你的网页上来场烟花秀吧!】(附源码)

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

      技术揭秘

      在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,即可在浏览器中打开页面,点击屏幕给自己放个烟花秀吧

      !!!

      标签:

      暂无标签
        协助本站seo优化一下,谢谢!
        关键词不能为空

      免责声明:

      本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络收集整理,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。如果您喜欢该程序和内容,请支持正版,购买注册,得到更好的正版服务。我们非常重视版权问题,如有侵权请邮件与我们点击联系。敬请谅解!

      评论列表
      签到
      热门文章
      随机推荐
    设置面板