【Canvas】用Canvas为你的视频加上弹幕

102 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情

今天尝试使用canvas来实现为网页上的视频增加弹幕效果。

页面准备

首先是准备一段短视频,然后使用 video 元素来播放视频,同时定义一个 input 文本输入框用来输入弹幕内容,一个 button 发送弹幕的按钮,以及我们今天的主角 canvas 元素,除了 video 元素,其他3个元素均设置id属性,方便一会获取DOM元素。

code.png

然后设置 video 元素的样式,宽度100%,正好直接撑满,高度不设置(是因为懒,视频的高度是850),然后因为弹幕是在视频的上半部分显示,所以给 canvas 设置高度为 video 高度的一半,设为400px。然后其他元素的样式微调一下,得到如下的页面:

image.png

弹幕构造函数

使用canvas做动画最重要的东西就是面向对象,我们把每一条弹幕都看成是一个个的对象实例,让它们都拥有自己的xy坐标来表示自身当前所在位置,这样我们才可以通过改变xy的值让每一条弹幕动起来。在此之前,我们要先完成弹幕的构造函数,方便我们产生一条条弹幕对象。

code.png

上图的代码是弹幕的构造函数,因为弹幕都是从屏幕左边开始出现,然后到屏幕的右边消失不见,因此弹幕的x坐标默认都是0,也就无需我们特意去传参了。但是每条弹幕出现的高度是可以不同的,因此我们要传递一个y,表示弹幕是从什么高度开始发射的,然后就是弹幕的速度dx,通过控制dx的大小可以让我们的弹幕滚动速度变快变慢。

这里绘制弹幕使用了canvas的 fillText 方法,代表是填充字体,也就是实心的字体,这个方法的语法如下:

ctx.fillText(text,x,y[,maxPixelWidth])
  • text:文本内容
  • x/y:绘制文本的位置
  • maxPixelWidth:文本的最大宽度,当要绘制的字符串超出最大宽度限制,则文本会被水平压缩,以达到限定宽度。(注意,是水平压缩,就是挤,而不是压)

这个方法模拟了在网页中渲染文本,因此在平时会使用的较多。

在使用 fillText 方法,可以使用 font 属性来设置字体的大小粗体等样式

ctx.font = "bold 14px Arial"; 

以及使用 fillStyle 来设置字体的颜色

ctx.fillStyle = 'red' // 红色字体

如果想要实现具有更丰富功能的弹幕,可以让这两个属性也自定义即可。

弹幕池

有了弹幕,我们还需要一个地方用来存放我们发出去的弹幕,因此需要定义一个变量 BARRAGE_POOL 用来存放所有的弹幕实例,然后每次遍历这个池子中的弹幕,调用里面弹幕的update方法,更新弹幕的位置。

发送弹幕

当我们点击“发送弹幕”按钮的时候,会执行 addBarrage 函数,这个函数会去获取文本输入框中输入的弹幕内容,然后在指定的范围内随机获取一个y值,作为弹幕的起始高度,然后可以通过判断弹幕内容的文本长度来为弹幕设置不同的速度dx,并根据这些值来实例化一个弹幕对象,再将这个对象放入到弹幕池中,这样下次绘制的时候就会把新增加的弹幕绘制出来了。 最后就是,记得清空文本框中的值,体验更好。

code.png

弹幕动画函数

这个就是让我们的弹幕动起来的东西了,我们定义一个 animate 函数,在函数里面使用 requestAnimationFrame 调用自身,以此达到循环绘制的目的,进而实现让弹幕动起来的效果。

在这个函数中,我们使用 for...of... 遍历弹幕池,并且调用每个弹幕的update方法,绘制更新位置后的弹幕。要注意的是,每次进行遍历前,都要先清空画布,不然的话会在屏幕上留下一串弹幕的痕迹。

code.png

记得定义完成后调用 animate 函数,不然动画无法执行。

最终效果

20221123_212313.gif

一条弹幕没氛围感,我们可以先给它来100条

20221123_212748.gif

好家伙,bug这不就来了吗,让我们冷静分析一波,出现这种情况的原因是,弹幕的x坐标都是0,弹幕速度dx都一样,又因为弹幕的x坐标为0是确定的,所以我们对dx动手,让它也是随机取值,进而让弹幕们错开。

分析完毕,动手。

20221123_213227.gif

服了,继续分析,每条弹幕除了有各自的速度,它们之间的相对位置应该是不变的,也就是说,每条弹幕的x坐标不该是相同的,而应该是一个负的随机数,这样它们就各自有各自的位置了。

20221123_214330.gif

终于有那味了,最后贴上完整代码

code.png