项目官网地址:https://fly-barrage.netlify.app/;
👑🐋🎉如果感觉项目还不错的话,还请点下 star 🌟🌟🌟。
Gitee:https://gitee.com/fei_fei27/fly-barrage(Gitee 官方推荐项目);
Github:https://github.com/feiafei27/fly-barrage;
其他系列文章:
fly-barrage 前端弹幕库(1):项目介绍
fly-barrage 前端弹幕库(2):弹幕内容支持混入渲染图片的设计与实现
fly-barrage 前端弹幕库(3):滚动弹幕的设计与实现
fly-barrage 前端弹幕库(4):顶部、底部弹幕的设计与实现
高级弹幕的计算是最简单的,因为每个高级弹幕和其他弹幕是无交互的,不需要处理相互重叠的问题,只需要根据当前视频的播放时间计算出高级弹幕处于的位置即可。
1:相关类型
/*** 用于描述高级弹幕*/
export default class SeniorBarrage extends BaseBarrage {constructor(seniorBarrageOptions: SeniorBarrageOptions, barrageRenderer: BarrageRenderer) {}
}export type SeniorBarrageOptions = BaseBarrageOptions & {// 弹幕的类型barrageType: 'senior';// 高级弹幕配置seniorBarrageConfig: SeniorBarrageConfig;
}/*** 用于描述二位平面中的一点(单位 px)*/
export type Location = {x: number;y: number;
}/*** 用于描述二位平面中的一点(面向用户)*/
export type LocationDefine = Location & {// 定义的类型:直接像素 或 canvas 百分比type?: 'PIXEL' | 'PERCENT';// 在 x、y 定义的基础上进行坐标偏移offsetX?: number;offsetY?: number;
}/*** 用于描述高级弹幕的运动配置*/
export type SeniorBarrageConfig = {// 起始点startLocation: LocationDefine;// 结束点endLocation: LocationDefine;// 生存时间(单位为毫秒)(数据要求:> 0)totalDuration: number;// 延迟时间(单位为毫秒)(数据要求:>= 0)delay: number;// 运动时长(单位为毫秒)(数据要求:>= 0)motionDuration: number;
}
高级弹幕的运动分为三部分:
- 运动前(此时位置一定是在 startLocation);
- 运动时(根据运动时间、运动速度以及 startLocation 可以计算出来);
- 运动完成(此时的位置 endLocation);
2:高级弹幕关键数据的计算
export default class SeniorBarrage extends BaseBarrage {constructor(seniorBarrageOptions: SeniorBarrageOptions, barrageRenderer: BarrageRenderer) {this.calcActualLocation();}/*** 计算关键点的实际坐标*/calcActualLocation() {const { startLocation, endLocation, motionDuration } = this.seniorBarrageConfig;// 计算实际起始点的位置// 计算 actualStartLocationlet actualStartLocationX = (startLocation.type || 'PIXEL') === 'PIXEL' ? startLocation.x : startLocation.x * this.canvasSize.width;let actualStartLocationY = (startLocation.type || 'PIXEL') === 'PIXEL' ? startLocation.y : startLocation.y * this.canvasSize.height;if (startLocation.offsetX) actualStartLocationX += startLocation.offsetX;if (startLocation.offsetY) actualStartLocationY += startLocation.offsetY;this.actualStartLocation = {x: actualStartLocationX,y: actualStartLocationY};// 计算 actualEndLocationlet actualEndLocationX = (endLocation.type || 'PIXEL') === 'PIXEL' ? endLocation.x : endLocation.x * this.canvasSize.width;let actualEndLocationY = (endLocation.type || 'PIXEL') === 'PIXEL' ? endLocation.y : endLocation.y * this.canvasSize.height;if (endLocation.offsetX) actualEndLocationX += endLocation.offsetX;if (endLocation.offsetY) actualEndLocationY += endLocation.offsetY;this.actualEndLocation = {x: actualEndLocationX,y: actualEndLocationY};// 根据实际起始点的位置,计算 vx 和 vythis.vx = (this.actualEndLocation.x - this.actualStartLocation.x) / motionDuration;this.vy = (this.actualEndLocation.y - this.actualStartLocation.y) / motionDuration;}
}
这里根据用户提供的配置计算出起始点以及结束点的实际坐标,并根据 运动路程 / 运动时间 计算出运动速度,这些关键数据是在接下来计算高级弹幕实时位置时需要的。
3:获取当前应该渲染的高级弹幕,并计算渲染位置
/*** 获取当前应该渲染的高级弹幕* @param time 视频播放时间点*/
getRenderSeniorBarrages(time: number): SeniorBarrage[] {// 获取当前能够渲染的高级弹幕const renderSeniorBarrages = this.seniorBarrageInstances.filter(barrage =>// 当前时间大于等于弹幕的出现时间 并且 当前时间小于等于弹幕的结束时间time >= barrage.time &&time <= (barrage.time + barrage.seniorBarrageConfig.totalDuration));// 遍历计算高级弹幕的 top 和 leftrenderSeniorBarrages.forEach(barrage => {const startPoint = barrage.time;const delayEndPoint = startPoint + barrage.seniorBarrageConfig.delay;const motionEndPoint = delayEndPoint + barrage.seniorBarrageConfig.motionDuration;if (time >= startPoint && time <= delayEndPoint) {// delay 时间段内(渲染在开始点即可)barrage.left = barrage.actualStartLocation.x;barrage.top = barrage.actualStartLocation.y;} else if (time >= delayEndPoint && time <= motionEndPoint) {// motion 时间段内// 当前的运动时长const motionTime = time - delayEndPoint;barrage.left = barrage.actualStartLocation.x + motionTime * barrage.vx;barrage.top = barrage.actualStartLocation.y + motionTime * barrage.vy;} else {// 运动结束时间段内(渲染在结束点即可)barrage.left = barrage.actualEndLocation.x;barrage.top = barrage.actualEndLocation.y;}});return renderSeniorBarrages;
}
首先根据弹幕的出现时间和 totalDuration 以及当前的 time 过滤出当前应该渲染的高级弹幕。
然后遍历应该渲染的弹幕,进行渲染位置的计算,在这里,先计算出高级弹幕所处于的运动阶段,如果是运动前的话,弹幕的渲染位置就是上文计算好的 actualStartLocation,然后是运动后的话,弹幕的渲染位置就是上文计算好的 actualEndLocation,如果是运动中的话,可以根据运动时间以及速度计算出运动的偏移量,再将偏移量加上起始点的位置即可计算出弹幕此时应该渲染的位置。