前言

跟着视频稍微过了一遍Canvas,收获挺大的

弹幕

大概就是文字的横向移动,明白原理的话其实也挺简单的

至于实现思路的话,大概是这样的

canvas中要发送一条弹幕需要这些值

文字内容 文字宽度 文字大小 颜色 x轴位置 y轴位置 速度 弹幕发送时间

这里除x轴位置以外,其它值均需要进行保存

文字宽度在发送时通过 ctx.measureText(text).width 获取并保存

(这样操作是为了省去加载弹幕宽度的步骤

  • 弹幕发送时间

这里可以根据定时器对播放时间进行累加,再根据 累加值 & 累加值 + 运行间隔 来查出该区间需要发送的弹幕

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    body {
      margin: 0;
    }

    #canvas {
      height: 600px;
      width: 600px;
    }
  </style>
</head>
<body>
<canvas id="canvas" height="600" width="600" style="border: 1px solid"></canvas>
<video id="video" controls="controls" autoplay="autoplay" src="http://tdwh-oss.oss-cn-qingdao.aliyuncs.com/video/2022022218172286075.mp4"></video>
</body>
<script>
 let canvas = document.querySelector("#canvas");
 let canvasH = canvas.clientHeight;
 let ctx = canvas.getContext("2d");
 video();


 /* 视频 + 弹幕实现 */
 function video() {
    let videoDom = document.querySelector("#video");
    ctx.font = "20px 微软雅黑"
    let interval;
    let danMuKu = [
      {
        text: "233333",
        height: 50,
        speed: 1,
        width: 0,
        color: "aqua"
      },
      {
        text: "233333333333",
        height: 70,
        speed: 2,
        width: 0,
        color: "white"
      },
      {
        text: "emmmmmm",
        height: 50,
        speed: 3,
        width: 0,
        color: "azure"
      },
    ]
    // 这里循环取文字宽度
    for (let i = 0; i <= danMuKu.length - 1; i++) {
      danMuKu[i].width = ctx.measureText(danMuKu[i].text).width;
    }
    let canvasW = canvas.clientWidth;
    videoDom.onplay = () => {
      interval = setInterval(() => {
        ctx.clearRect(0, 0, 600, 600)
        ctx.fillStyle = "black"
        ctx.fillRect(0, 0, 600, 600);
        ctx.drawImage(videoDom, 0, 131.25, 600, 337.5);

        danMuKu.forEach(v => {
          // 初始化起始位置
          if (v.initX == null) v.initX = canvasW;
          v.initX -= v.speed;
          ctx.fillStyle = v.color;
          ctx.fillText(v.text, v.initX, v.height);
          if (v.initX <= -1 * v.width) v.initX = canvasW
        })
      }, 10)
    }
    videoDom.onpause = () => {
      clearInterval(interval)
    }
  }
</script>
</html>

雪花

雪花的运动方向自然是从上往下,稍微复杂的点大致在运动轨迹了

// 这里根据正负值(大小)初始化运动方向, 左/右
if (v.path == null) v.path = randomNum(-.5, .5);
// 这里得出第一个x值, v.x为雪花的初始x轴位置, +path 则表示雪花会往那个方向飘动
let num1 = v.x + v.path;
// 这里得出第二个x值, 这里用num1而不是用v.x的原因是因为 v.x运动轨迹可能会变成波浪线/接近笔直的一条线,num1则会保持原运动轨迹
let num2 = num1 + (v.path < 0 ? -.5 : .5);
// 再从num1和num2中取出一个随机数
v.x = randomNum(num1, num2)
// 获取n & m之间的随机数(小数/负数)
function randomNum(n, m) {
  return Math.random() * (m - n) + n;
}

创意工坊

加上了canvas后顺便也上传了新的视频壁纸到创意工坊

To Wallpaper Engine

Ex - ploooosion!