关于javascript:万事胜意🧧你可能不知道的烟花秀🎆

🙇 前言

  • 大家好我是小卢,转眼间又到了一年春节,而往年的春节也正好是我的本命年🐯。
  • 因为疫情的起因可能又回不了家过年了,还是很想回去看看烟花感触下年味的🧧。
  • 既然回不去那就本人做一个吧~跟大家一起赏烟花🎆。
  • Ps: 本文没有波及到性能优化,请不要在正式我的项目应用喔~

    🏮 ToDoList

  • [ ] 获取文字像素点
  • [ ] 初始化烟花
  • [ ] 烟花发射
  • [ ] 烟花爆炸

    🧧 Just Do It

    获取文字像素点

  • 首先咱们先创立一个canvas

    <!-- index.html -->
    <canvas id="textFireWorks"></canvas>
  • 初始化canvas并在canvas中填充想要输入的文字

    // fireWork.js
    let textCanvas, textCtx;
    const canvasWidth = window.innerWidth;
    const canvasHeight = window.innerHeight;
    const fontSize =180
    function fireWorksShowBegin() {
      initCanvas();
    }
    function initCanvas() {
      textCanvas = document.getElementById("textFireWorks");
      textCtx = textCanvas.getContext("2d");
      textCanvas.style.width = canvasWidth + "px";
      textCanvas.style.height = canvasHeight + "px";
      textCanvas.width = canvasWidth;
      textCanvas.height = canvasHeight;
      textCtx.textAlign = "center";
      textCtx.textBaseline = "top";
      textCtx.font = fontSize + 'px "宋体"';
      textCtx.fillStyle = "#fff";
      textCtx.fillText("新春快乐", canvasWidth / 2, 0);
    }

  • canvas初始化实现后咱们须要获取每个像素点对应的地位

    // fireWork.js
    let textPixels = [];
    function initCanvas() {
      // ...
      //获取画布地位
      let pix = textCtx.getImageData(0, 0, canvasWidth, canvasHeight).data;
      let gap = 6;
      for (let h = 0; h < canvasHeight; h += gap) {
        for (let w = 0; w < canvasWidth; w += gap) {
          // 以后像素块绝对于画布的索引地位
          let position = (canvasWidth * h + w) * 4;
          let r = pix[position],
              g = pix[position + 1],
              b = pix[position + 2];
          if (r + g + b !== 0) {
            textPixels.push({
              x: w,
              y: h,
            });
          }
        }
      }
     }
  • canvas中咱们能够通过getImageData办法拿到画布的信息
  • 其中的data就是色调信息,每4个元素示意一个像素色彩
  • 咱们能够通过以上算法在程度和垂直方向均以固定间隙去读取imageData像素点信息,如果是齐全不通明的像素点,则作为咱们须要的要害坐标保留下来至textPixels数组中用于咱们之后烟花渲染。

    初始化烟花

  • 对于烟花的出现在这里我应用了一个PixiJS库,这是一个HTML5创立引擎,用它能够很不便的渲染2D动画。
  • 首先引入该库后咱们创立一个容器和渲染器增加到咱们的dom中。

    // fireWork.js
    // 创立一个Container
    const stage = new PIXI.Container();
    //自动检测渲染器
    const renderer = PIXI.autoDetectRenderer(canvasWidth, canvasHeight);
    document.body.appendChild(renderer.view);
  • 接下来咱们须要将烟花最终绽开的地位摆满烟花,也就是以上像素点的地位。
  • 应用PIXI.Texture我将福的图标作为烟花占位符。
  • 将每一个像素点都替换成福图标。
  • stage容器中增加这些子节点,并把每一个firework记录下来不便接下来应用。
// fireWork.js
const fireworks = [];
const yOffset = canvasHeight * 0.4;
const textures = PIXI.Texture.from("https://s3.bmp.ovh/imgs/2022/01/0d7afb4d0700761e.png");
function fireWorksShowBegin() {
  //...
  initFireworks();
}
function initFireworks() {
  // shuffle(textPixels);
  for (let i = 0, l = textPixels.length; i < l; i++) {
    createEmojiFirework(textures, textPixels[i], i);
  }
}
function createEmojiFirework(text, pos, i) {
  const size = 20;
  const firework = new PIXI.Sprite(text);
  firework.position.x = pos.x;
  firework.position.y = pos.y + yOffset;
  firework.width = size;
  firework.height = size;
  firework.image = text;
  fireworks.push(firework);
  stage.addChild(firework);
}
  • 因为最终咱们要始终循环渲染这个页面所以采纳requestAnimationFrame,这个办法之前我在产品经理:你能不能让词云动起来?介绍过了,这里我就不细讲了。
// fireWork.js
function fireWorksShowBegin() {
  //...
  requestAnimationFrame(fireWorksAnimate);
}
function fireWorksAnimate() {
  requestAnimationFrame(fireWorksAnimate);
  // 将对象渲染到其 WebGL 视图。
  renderer.render(stage);
}
  • 咱们来看看当初的成果吧

烟花发射

  • 当初最终须要出现的成果曾经做好了,咱们只须要在循环动画fireWorksAnimate办法中将每一个图标都缓缓发射到对应的像素点即可。
  • fireWorksAnimate中咱们首先须要做一件事件,那就是将图标的地位从一个中央位移到咱们真正想要烟花爆炸💥的地位,然而在这之前咱们曾经将图标放到爆炸的地位了,当初咱们须要对初始化创立的图标做解决从新给定一个终点记录爆炸的地位让他迟缓位移。
  • 咱们须要改变createEmojiFirework办法,设置终点position(x,y)和起点explodePositio(x,y)并设置图标挪动速度speed

    // fireWork.js
    function createEmojiFirework(text, pos, i) {
      //...
      // 记录最终爆炸的地位
      firework.explodePosition = {
        x: pos.x,
        y: pos.y + yOffset,
      };
      //给图标一个终点地位
      firework.position.x = 20;
      firework.position.y = 30;
      //设置图标挪动速度
      firework.speed = 0.02
    }
  • 而在fireWorksAnimate中咱们须要计算从终点到起点的每次位移。
// fireWork.js
function fireWorksAnimate() {
  for (let i = 0; i < fireworks.length; i++) {
    fireworks[i].position.x +=
      (fireworks[i].explodePosition.x - fireworks[i].position.x) *
      fireworks[i].speed;
    fireworks[i].position.y +=
      (fireworks[i].explodePosition.y - fireworks[i].position.y) *
      fireworks[i].speed;
  }
}
  • 当初的成果是这样的
  • 好家伙成果是挪动了,然而太参差了,咱们在createEmojiFirework中给烟花一个定时器让他提早一个一个的发射,这下成果就好很多了。

烟花爆炸

  • 烟花发射成功了,接下来咱们要欠缺烟花爆炸的成果。
  • 爆炸的原理其实也是跟生成图标差不多。

    • 在每一次的动画中循环中咱们都要计算图标是否快要达到起点。
    • 如果快要达到就给它一个标记并触发爆炸事件。
    • 在爆炸事件中咱们须要生成多个粒子,给每个粒子初始化不同的x轴y轴的位移速度,并且记录大小和地位。
// fireWork.js
let particles = [];
function fireWorksAnimate() {
  //...
  for (let i = 0; i < fireworks.length; i++) {
  //...
    if (!fireworks[i].exploded) {
      //计算是否快要达到起点
      if (
        Math.abs(fireworks[i].position.x - fireworks[i].explodePosition.x) +
          Math.abs(fireworks[i].position.y - fireworks[i].explodePosition.y) <
        100
      ) {
        fireworks[i].exploded = true;
        explodeFirework(fireworks[i]);
      }
    }
  }
 //...
}
function explodeFirework(firework) {
  for (let i = 0; i < 20; i++) {
    const size = 20;
    let particle = new PIXI.Sprite(firework.image);
    particle.speed = {
      x: (Math.random() - 0.5) * (Math.random() * 10),
      y: (Math.random() - 0.5) * (Math.random() * 10),
    };
    particle.position.x = firework.position.x;
    particle.position.y = firework.position.y;
    particle.width = size;
    particle.height = size;
    particles.push(particle);
    stage.addChild(particle);
  }
}
  • 至此每个图标烟花就会在达到起点后生成20个雷同大小的例子,然而这个例子始终存在于画布中,咱们须要计算他的位移产生一种爆炸的成果。
  • 在每次画布从新渲染中咱们将每一个粒子都依照它本身的速度别离在xy位移,并设置alpha不透明度递加。
// fireWork.js
function fireWorksAnimate() {
  //...
  for (let i = 0, l = particles.length; i < l; i++) {
      particles[i].position.x += particles[i].speed.x;
      particles[i].position.y += particles[i].speed.y;
      particles[i].speed.y += 0.03;
      particles[i].alpha -= 0.01;
    }
 //...
}
  • 最初出现的成果就是这样啦~~
  • 然而当初的成果太对立了,如果当咱们将发射地位 起点地位 发射速度 爆炸大小全副随机之后会产生什么呢?

最终成果

  • 好啦这样想要的成果就制作实现了,接下来就加上小卢给大家的新年贺语就完结了(贺卡有彩蛋喔~😆)。
  • 源码地址   
  • 展现地址(请在PC端关上喔~)

    👋 写在最初

  • 首先还是很感激大家看到这里,这次的文章就分享到这里,提前祝大家春节快乐!!
  • 在新的一年心愿大家越来越好,顺顺利利,疫情早日过来!!!!
  • 如果您感觉这篇文章有帮忙到您的的话无妨🍉🍉关注+点赞+珍藏+评论+转发🍉🍉反对一下哟~~😛您的反对就是我更新的最大能源。
  • 如果想跟我一起探讨和学习更多的前端常识能够退出我的前端交流学习群,大家一起畅谈天下~~~

【腾讯云】轻量 2核2G4M,首年65元

阿里云限时活动-云数据库 RDS MySQL  1核2G配置 1.88/月 速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据