看吃鸡直播的时候,突发奇想想实现一套适用于H5video的弹幕插件,如何设计一个高性能、精准度的弹幕是件很很有挑战性、也很有趣的事情,插件的地址在danmu-plugin,欢迎大家提出意见
看过弹幕播放的截图后,我们思考一下,实现上图所示的弹幕插件有哪些基本的问题需要考虑的
- 弹幕的管理
- 弹幕的大小,速度和颜色控制
- 不同字号的弹幕位置计算
- 弹幕的碰撞检测(包含一个追击问题)
弹幕的数据结构
对于直播来说,弹幕是持续从后台接口拉取的,这点与视频弹幕不同,我们在拿到弹幕数据之后,对字段进行补齐,弹幕的字段如下所示:
- size 弹幕的字号
- color 弹幕的颜色
- speed 弹幕1s钟滚动的px数值
- content 弹幕的内容
轨道的数据结构
- trackHeight 轨道的高度
- thresholdV 轨道当前的弹幕限制速度
- isExistWaitDanmu 轨道是否存在还未完全进入video视口的弹幕
- danmuNum 轨道中滚动弹幕个数
- lastScrollDanmu 最后添加进轨道的弹幕元素,用于追击插入弹幕的时候使用
弹幕的播放方案
这个是弹幕播放比较难的一个问题了,再说这个问题之前,不得不说一下弹幕的动画原理:利用绝对定位。稍微理解前端性能问题的同学都知道,如果不把“动画元素”脱离文档流,大量的reflow和repaint会使浏览器“累死”。知道绝对定位以后,下一步就是控制弹幕的位置了。
如果我们有一个弹幕那就不是问题了,设置弹幕的起始位置就是播放器的右顶点(top:0;right:播放器的.width)。可是,那么多的弹幕如何计算每个将要入场的弹幕的起始位置呢?
首先,可以把视频播放器想象成为一个有着很多条轨道的跑道,如果当前跑道能够容纳下弹幕,则使用一条轨道就行,如果一条轨道不够的话,那就用两条~
那么,什么情况下,弹幕能够被送上跑道呢?
- 轨道上没有其他弹幕的时候
- 轨道上有其他弹幕,但是我的速度比轨道上滚动的弹幕速度慢,我不会撞到他
- 轨道上有其他弹幕,我的速度也比他快,但是在他滚出播放器之前,我不会撞到他(追击问题)
上述三种情况,弹幕是可以被送上轨道的~
几个关键点
- 需要持续的拉去弹幕数据,并将数据更新到弹幕插件的danmuList中
- 插件会定时去请求轨道,遍历danmuList查看是否有能送上轨道的弹幕
- 弹幕播放完毕之后,插件会删除DOM中的节点,同时更新当前轨道的速度限制
后续想法
目前版本的插件只适用于直播的弹幕,不会保留发射的弹幕,后续想兼容视频的弹幕播放,就需要考虑弹幕与视频内容的匹配等等问题,敬请期待~