项目官网地址:fly-barrage.netlify.app/;
👑🐋🎉如果感觉项目还不错的话,还请点下 star 🌟🌟🌟。
Gitee:gitee.com/fei_fei27/f...(Gitee 官方推荐项目);
Github:github.com/feiafei27/f...;
其他系列文章:fly-barrage 前端弹幕库(2):弹幕内容支持混入渲染图片的设计与实现
高级弹幕的计算是最简单的,因为每个高级弹幕和其他弹幕是无交互的,不需要处理相互重叠的问题,只需要根据当前视频的播放时间计算出高级弹幕处于的位置即可。
1:相关类型
typescript
/**
* 用于描述高级弹幕
*/
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:高级弹幕关键数据的计算
typescript
export default class SeniorBarrage extends BaseBarrage {
constructor(seniorBarrageOptions: SeniorBarrageOptions, barrageRenderer: BarrageRenderer) {
this.calcActualLocation();
}
/**
* 计算关键点的实际坐标
*/
calcActualLocation() {
const { startLocation, endLocation, motionDuration } = this.seniorBarrageConfig;
// 计算实际起始点的位置
// 计算 actualStartLocation
let 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
};
// 计算 actualEndLocation
let 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 和 vy
this.vx = (this.actualEndLocation.x - this.actualStartLocation.x) / motionDuration;
this.vy = (this.actualEndLocation.y - this.actualStartLocation.y) / motionDuration;
}
}
这里根据用户提供的配置计算出起始点以及结束点的实际坐标,并根据 运动路程 / 运动时间 计算出运动速度,这些关键数据是在接下来计算高级弹幕实时位置时需要的。
3:获取当前应该渲染的高级弹幕,并计算渲染位置
typescript
/**
* 获取当前应该渲染的高级弹幕
* @param time 视频播放时间点
*/
getRenderSeniorBarrages(time: number): SeniorBarrage[] {
// 获取当前能够渲染的高级弹幕
const renderSeniorBarrages = this.seniorBarrageInstances.filter(barrage =>
// 当前时间大于等于弹幕的出现时间 并且 当前时间小于等于弹幕的结束时间
time >= barrage.time &&
time <= (barrage.time + barrage.seniorBarrageConfig.totalDuration)
);
// 遍历计算高级弹幕的 top 和 left
renderSeniorBarrages.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,如果是运动中的话,可以根据运动时间以及速度计算出运动的偏移量,再将偏移量加上起始点的位置即可计算出弹幕此时应该渲染的位置。