小枭资源网-免费提供绿色软件、活动线报以及其他网络资源,好货不私藏!
XML地图/ 广告合作 /版权声明
当前位置:网站首页 > 软件仓库 > 安卓软件 > 正文

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

作者:小枭日期:2024-10-31浏览:800分类:安卓软件

技术揭秘

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

!!!

已有29位网友发表了看法:

  • 游客

    游客  评论于 [2024-10-31 21:57:24]  回复

    楼主今年多大了?http://7jc6.haiab.com

  • skype电脑版

    skype电脑版  评论于 [2024-11-01 01:21:12]  回复

    楼主的帖子实在是写得太好了。文笔流畅,修辞得体!https://www.skypeis.com/

  • whatsapp官网

    whatsapp官网  评论于 [2024-11-01 03:28:59]  回复

    信楼主,得永生!https://www.whatsappis.com/

  • 指尖网

    指尖网  评论于 [2024-11-01 16:20:53]  回复

    很多天不上线,一上线就看到这么给力的帖子!http://6otg.twistforum.com

  • 指尖站群

    指尖站群  评论于 [2024-11-02 03:08:06]  回复

    很有看点!http://zue.qishuang.top

  • 指尖网

    指尖网  评论于 [2024-11-02 04:11:11]  回复

    我回帖楼主给加积分吗?http://homewarrantyjz.com/html/31d98998979.html

  • 指尖网

    指尖网  评论于 [2024-11-02 04:21:37]  回复

    太邪乎了吧?http://ladei.cn/html/08f98999002.html

  • telegram官网

    telegram官网  评论于 [2024-11-02 11:38:43]  回复

    楼主的头像能辟邪啊!https://www.telegramlp.com/

  • skype电脑版

    skype电脑版  评论于 [2024-11-02 13:25:07]  回复

    被楼主的逻辑打败了!https://www.skypeis.com/

  • telegram官方网站

    telegram官方网站  评论于 [2024-11-02 15:04:49]  回复

    很多天不上线,一上线就看到这么给力的帖子!https://www.telegramxp.com/

  • telegram官网

    telegram官网  评论于 [2024-11-04 16:29:15]  回复

    信楼主,得永生!https://www.telegramlp.com/

  • 游客

    游客  评论于 [2024-11-05 08:51:53]  回复

    东方不败还是灭绝师太啊?http://il8w.haiab.com

  • skype官方网站

    skype官方网站  评论于 [2024-11-05 20:27:25]  回复

    楼主练了葵花宝典吧?https://www.skypeis.com/

  • telegram中文版

    telegram中文版  评论于 [2024-11-08 01:09:01]  回复

    今天上网不回帖,回帖就回精华帖!https://www.telegramis.com/

  • skype官网

    skype官网  评论于 [2024-11-08 08:06:22]  回复

    不错的帖子,值得收藏!https://www.skypeis.com/

  • skype电脑版

    skype电脑版  评论于 [2024-11-09 23:16:10]  回复

    楼上的这是啥态度呢?https://www.skypeis.com/

  • skype电脑版

    skype电脑版  评论于 [2024-11-11 15:13:40]  回复

    楼上的别说的那么悲观好吧!https://www.skypeis.com/

  • skype电脑版

    skype电脑版  评论于 [2024-11-13 18:56:31]  回复

    回帖也有有水平的!https://www.skypeis.com/

  • skype电脑版

    skype电脑版  评论于 [2024-11-13 23:05:12]  回复

    我默默的回帖,从不声张!https://www.skypeis.com/

  • 游客

    游客  评论于 [2024-11-14 03:24:43]  回复

    鉴定完毕!http://www.dnf8888.com

  • 游客

    游客  评论于 [2024-11-14 03:29:32]  回复

    有机会找楼主好好聊聊!http://gxji.haiab.com

  • 游客

    游客  评论于 [2024-11-14 13:19:31]  回复

    写的太好啦,评论一个https://www.guangcexing.net/vodplay/mobileemvztwgg.html

  • 电报官网

    电报官网  评论于 [2024-11-15 00:47:42]  回复

    白富美?高富帅?https://www.telegramip.com/

取消回复欢迎 发表评论:

Copyright© XXZY525.XYZ版权所有〖小枭资源网〗 
本站资源均从互联网上收集,仅供学习和交流使用;请遵循相关法律法规;
本站一切资源不代表本站立场,如有侵权、后门、不妥,请联系删除,敬请谅解!联系方式E-mail:341231887@qq.com
本站同款服务器| 侵权处理 | 版权声明 | 网站地图 | 广告合作