开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
今天尝试使用canvas来实现为网页上的视频增加弹幕效果。
页面准备
首先是准备一段短视频,然后使用 video
元素来播放视频,同时定义一个 input
文本输入框用来输入弹幕内容,一个 button
发送弹幕的按钮,以及我们今天的主角 canvas
元素,除了 video
元素,其他3个元素均设置id属性,方便一会获取DOM元素。
然后设置 video
元素的样式,宽度100%,正好直接撑满,高度不设置(是因为懒,视频的高度是850),然后因为弹幕是在视频的上半部分显示,所以给 canvas
设置高度为 video
高度的一半,设为400px。然后其他元素的样式微调一下,得到如下的页面:
弹幕构造函数
使用canvas做动画最重要的东西就是面向对象,我们把每一条弹幕都看成是一个个的对象实例,让它们都拥有自己的xy坐标来表示自身当前所在位置,这样我们才可以通过改变xy的值让每一条弹幕动起来。在此之前,我们要先完成弹幕的构造函数,方便我们产生一条条弹幕对象。
上图的代码是弹幕的构造函数,因为弹幕都是从屏幕左边开始出现,然后到屏幕的右边消失不见,因此弹幕的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,并根据这些值来实例化一个弹幕对象,再将这个对象放入到弹幕池中,这样下次绘制的时候就会把新增加的弹幕绘制出来了。
最后就是,记得清空文本框中的值,体验更好。
弹幕动画函数
这个就是让我们的弹幕动起来的东西了,我们定义一个 animate
函数,在函数里面使用 requestAnimationFrame
调用自身,以此达到循环绘制的目的,进而实现让弹幕动起来的效果。
在这个函数中,我们使用 for...of...
遍历弹幕池,并且调用每个弹幕的update方法,绘制更新位置后的弹幕。要注意的是,每次进行遍历前,都要先清空画布,不然的话会在屏幕上留下一串弹幕的痕迹。
记得定义完成后调用 animate
函数,不然动画无法执行。
最终效果
一条弹幕没氛围感,我们可以先给它来100条
好家伙,bug这不就来了吗,让我们冷静分析一波,出现这种情况的原因是,弹幕的x坐标都是0,弹幕速度dx都一样,又因为弹幕的x坐标为0是确定的,所以我们对dx动手,让它也是随机取值,进而让弹幕们错开。
分析完毕,动手。
服了,继续分析,每条弹幕除了有各自的速度,它们之间的相对位置应该是不变的,也就是说,每条弹幕的x坐标不该是相同的,而应该是一个负的随机数,这样它们就各自有各自的位置了。
终于有那味了,最后贴上完整代码