Canvas + WebSocket实现视频弹幕

this.canvas = canvas; // 当前的 canvas 元素

this.video = video; // 当前的 video 元素

// 设置 canvas 与 video 等高

this.canvas.width = video.clientWidth;

this.canvas.height = video.clientHeight;

// 默认暂停播放,表示不渲染弹幕

this.isPaused = true;

// 没传参数的默认值

let defaultOptions = {

fontSize: 20,

color: “gold”,

speed: 2,

opacity: 0.3,

data: []

};

// 对象的合并,将默认参数对象的属性和传入对象的属性统一放到当前实例上

Object.assign(this, defaultOptions, options);

// ********** 以下为新增代码 **********

// 存放所有弹幕实例,Barrage 是创造每一条弹幕的实例的类

this.barrages = this.data.map(item => new Barrage(item, this));

// ********** 以上为新增代码 **********

}

}

其实通过上面操作以后,我们相当于把 data 里面的每一条弹幕对象转换成了一个 Barrage 类的一个实例,把当前的上下文 this 传入后可以随时在每一个弹幕实例上获取 CanvasBarrage 类实例的属性,也方便我们后续扩展方法,遵循这种开放封闭原则的方式开发,意义是不言而喻的。

3、在 CanvasBarrage 类实现渲染所有弹幕的 render 方法

CanvasBarrage 的 render 方法是在创建弹幕功能实例的时候应该渲染 Canvas 所以应该在 CanvasBarrage 中调用,在 render 内部,每一次渲染之前都应该先将 Canvas 画布清空,所以需要给当前的 CanvasBarrage 类新增一个属性用于存储 Canvas 画布的内容。

// 文件:index.js

class CanvasBarrage {

constructor(canvas, video, options = {}) {

// 如果没有传入 canvas 或者 video 直接跳出

if (!canvas || !video) return;

this.canvas = canvas; // 当前的 canvas 元素

this.video = video; // 当前的 video 元素

// 设置 canvas 与 video 等高

this.canvas.width = video.clientWidth;

this.canvas.height = video.clientHeight;

// 默认暂停播放,表示不渲染弹幕

this.isPaused = true;

// 没传参数的默认值

let defaultOptions = {

fontSize: 20,

color: “gold”,

speed: 2,

opacity: 0.3,

data: []

};

// 对象的合并,将默认参数对象的属性和传入对象的属性统一放到当前实例上

Object.assign(this, defaultOptions, options);

// 存放所有弹幕实例,Barrage 是创造每一条弹幕的实例的类

this.barrages = this.data.map(item => new Barrage(item, this));

// ********** 以下为新增代码 **********

// Canvas 画布的内容

this.context = canvas.getContext(“2d”);

// 渲染所有的弹幕

this.render();

// ********** 以上为新增代码 **********

}

// ********** 以下为新增代码 **********

render() {

// 渲染整个弹幕

// 第一次先进行清空操作,执行渲染弹幕,如果没有暂停,继续渲染

this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

// 渲染弹幕

this.renderBarrage();

if (this.isPaused == false) {

// 递归渲染

requestAnimationFrame(this.render.bind(this));

}

}

// ********** 以上为新增代码 **********

}

在上面的 CanvasBarrage 的 render 函数中,清空时由于 Canvas 性能比较好,所以将整个画布清空,所以从坐标 (0, 0) 点,清空的宽高为整个 Canvas 画布的宽高。

只要视频是在播放状态应该不断的调用 render 方法实现清空画布、渲染弹幕、判断是否暂停,如果非暂停状态继续渲染,所以我们用到了递归调用 render 去不断的实现渲染,但是递归时如果直接调用 render,性能特别差,程序甚至会挂掉,以往这种情况我们会在递归外层加一个 setTimeout 来定义一个短暂的递归时间,但是这个过程类似于动画效果,如果使用 setTimeout 其实是将同步代码转成了异步执行,会增加不确定性导致画面出现卡顿的现象。

这里我们使用 H5 的新 API requestAnimationFrame,可以在平均 1/60 S 内帮我执行一次该方法传入的回调,我们直接把 render 函数作为回调函数传入 requestAnimationFrame,该方法是按照帧的方式执行,动画流畅,需要注意的是,render 函数内使用了 this,所以应该处理一下 this 指向问题。

由于我们使用面向对象的方式,所以渲染弹幕的具体细节,我们抽离出一个单独的方法 renderBarrage,接下来看一下 renderBarrage 的实现。

4、CanvasBarrage 类 render 内部 renderBarrage 的实现

// 文件:index.js

class CanvasBarrage {

constructor(canvas, video, options = {}) {

// 如果没有传入 canvas 或者 video 直接跳出

if (!canvas || !video) return;

this.canvas = canvas; // 当前的 canvas 元素

this.video = video; // 当前的 video 元素

// 设置 canvas 与 video 等高

this.canvas.width = video.clientWidth;

this.canvas.height = video.clientHeight;

// 默认暂停播放,表示不渲染弹幕

this.isPaused = true;

// 没传参数的默认值

let defaultOptions = {

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值