资讯专栏INFORMATION COLUMN

弹幕,是怎样练成的?

lwx12525 / 2425人阅读

说起弹幕看过视频的都不会陌生,那满屏充满着飘逸评论的效果,让人如痴如醉,无法自拔

最近也是因为在学习关于 canvas 的知识,所以今天就想和大家分享一个关于弹幕的故事

那么究竟弹幕是怎样炼成的呢? 我们且往下看(look)

看什么?看效果

效果图已经呈现给各位了,那么是不是有点小激动呢?是的,感慨万分,思绪宁乱,无语凝噎

无论以后我们的工作中是否会遇到这样的需求,也请给自己一个增加技能的机会吧!!
本次弹幕的效果,项目结构如下图所示

项目整体已经给出,那么我们就撸起袖子加油干吧。

让弹幕飞

上面我们提到了 canvas 的事情,所以呢,这就是制作弹幕了。我们利用 canvas 绘图来实现弹幕的功能

首先,我们先给出html的结构

// index.html文件

听妈妈的话 - 周杰伦

// 引入index.js文件用来实现弹幕功能

结构相对来说没什么高级的内容,主要就是写上了 canvas 标签还有 video 标签,他们才是视频网站弹幕的绝佳拍档

那么不再卖关子了,赶紧进行主要活动吧

模拟数据

// index.js文件
let data = [
    {value: "周杰伦的听妈妈的话,让我反复循环再循环", time: 5, color: "red", speed: 1, fontSize: 22},
    {value: "想快快长大,才能保护她", time: 10, color: "#00a1f5", speed: 1, fontSize: 30},
    {value: "听妈妈的话吧,晚点再恋爱吧!爱呢?", time: 15},
];

数据里代表了什么:

value:代表弹幕的内容 (必填)

time:代表弹幕展现的时间 (必填)

color:代表弹幕文字的颜色

speed:代表弹幕飘过的速度

fontSize:代表弹幕文字的大小

opacity:代表弹幕文字的透明度

除了弹幕的内容和展现的时间外,其他都是可选的,模拟的数据里没有这些参数也没关系的

获取 dom 元素

// index.js文件 
// 模拟数据
...省略
// 获取到所有需要的dom元素
let doc = document;
let canvas = doc.getElementById("canvas");
let video = doc.getElementById("video");
let $txt = doc.getElementById("text");
let $btn = doc.getElementById("btn");
let $color = doc.getElementById("color");
let $range = doc.getElementById("range");

Canvas渲染弹幕

下面我们将用面向对象的方式来实现canvas绘制弹幕的功能,之所以选择用这种方式主要是方便复用和后续添加方法;

下面我们先来创建一个CanvasBarrage类,主要用做canvas来渲染整个弹幕;
在实现之前,我们先来调用一下,看看是如何创建实例的。

// index.js文件
// 模拟数据
...省略
// 获取到所有需要的dom元素
...省略
// 创建CanvasBarrage类
class CanvasBarrage {
    // todo
}
// 创建CanvasBarrage实例
let canvasBarrage = new CanvasBarrage(canvas, video, { data });

实现 CanvasBarrage


我们在“得到所有的弹幕消息”那里,通过数组的 map 方法返回的还是个数组,不过返回的内容是一个 Barrage类,这是为什么呢?

还记得之前说过么,用类的好处就是方便扩展,后续再添加方法的话可以直接在该类中添加即可。
所以我们也不推崇直接map方法里直接返回一个{}这种形式

// 不推荐 
this.barrages = this.data.map(item => { item });

说到这里我们还要先写一下Barrage这个类,不然接下来的console.log(this)会因为找不到Barrage类而报错

// index.js文件
++++++++++++++++++++++

// 创建Barrage类,用来实例化每一个弹幕元素
class Barrage {
   constructor(obj, ctx) {        // todo    }
}

 ++++++++++++++++++++++
class CanvasBarrage {    ...省略}

Now,通过上面代码中的console.log(this),我们可以看到,所有挂载到this实例上的属性和原型上的方法都呈现眼前了

render 一下

接着上面的 CanvasBarrage 类里 render 方法继续写,我们来把 todo 完成

todo都做了什么?

1、清除之前画布所有的绘制,防止绘制重叠的影响

this.clear()

2、渲染真正的弹幕数据 (还未实现)

this.renderBarrage()

3、判断是否继续渲染弹幕

this.isPaused为false时表示为播放状态

4、递归调用render

通过requestAnimationFrame来递归调用render

要比setInterval这样的方式好很多

渲染整个弹幕 render 方法就完成了,那么要继续写了,应该是刚才未实现的 renderBarrage 方法了

But,在此之前,我们要先写个别的,它就是Barrage类
因为还需要它来大显身手一下呢,每一个弹幕的实例都由它来制造

创建 Barrage 类

弹幕制造者来了,下面我们就来实现一下这个Barrage类,看它都具备哪些属性和方法,继续todo吧

todo都做了什么?

1、从传入的obj中取到必要的value和time

this.value = obj.value; // 内容 
this.time = obj.time;   // 时间

2、初始化弹幕

对每个弹幕所需的参数进行设置,如果obj上没有,就取默认参数

计算每个弹幕的宽度

由于不能直接操纵canvas画布里的元素,所以先创建一个p标签

p标签的宽度即为弹幕的宽 -> this.width = p.clientWidt

设置每个弹幕的x和y坐标 (起始位置)

横向x坐标起始位置都是从右边进入,即:画布的宽度

this.x = this.context.canvas.width

纵向y坐标起始位置是不固定的,选在画布之内的任意位置出现

this.y = this.context.canvas.height * Math.random()

处理弹幕超出画布区域

canvas是按照字号基线来展示字体的,如果小于这个字号大小

this.y = this.fontSize

如果大于了画布高度 - 字号大小

this.y = this.context.canvas.height - this.fontSize

3、渲染每个弹幕

绘制文本需要设置文本的字体字号、颜色和文本的内容与坐标

字体字号api

this.context.ctx.font = ${this.value}px Arial

颜色api

this.context.ctx.fillStyle = this.color

内容与坐标api

this.context.ctx.fillText(this.value, this.x, this.y)

以上三步就是整个Barrage类所做的事情了。Barrage这个类都已经敲完了,那么接下来开始真正的渲染步骤吧

renderBarrage才是主角

此时我们再添加一个触发弹幕的事件,让弹幕飞起来


大家一起写到了这里,也是时候展示一下成果了,往下看

别急,让弹幕再飞一会儿

渲染弹幕的功能,我们已经完成了,接下来让我们马不停蹄的写下如何发弹幕吧。别犹豫,开撸!!!

发弹幕

发弹幕相对来说还是很简单的,获取到 value, time, color, fontSize 之后把他们当作对象传给 CanvasBarrage 的 add方法进行添加就好了
下面我们再写一下add方法,回到CanvasBarrage类里继续写

// index.js文件
class CanvasBarrage {
    constructor() { ...省略}
    render() { ...省略 }
    renderBarrage() { ...省略 }
    clear() { ...省略 }
    +++++++++++++++++++++++++++
    add(obj) {
        // 实际上就是往barrages数组里再添加一项Barrage的实例而已
        this.barrages.push(new Barrage(obj, this));
    }
    +++++++++++++++++++++++++++
}

完成,漂亮,看看效果吧

写到这里我们已经完成了视频网站上的弹幕功能了,可喜可贺
下面我们再来完善一下视频播放时对弹幕的播放处理吧

暂停和拖动

暂停就停止渲染弹幕

// index.js文件
   ...省略
   // 播放
   video.addEventListener("play", () => {
       canvasBarrage.isPaused = false;
       canvasBarrage.render();
   });
   +++++++++++++++++++++++++++++++++++++++
   // 暂停
   video.addEventListener("pause", () => {
       // isPaused设为true表示暂停播放
       canvasBarrage.isPaused = true;
   });
   +++++++++++++++++++++++++++++++++++++++

回放时需要重新渲染该时刻的弹幕

  // index.js文件
  
  // 暂停
  video.addEventListener("pause", () => {
      canvasBarrage.isPaused = true;
  });
  +++++++++++++++++++++++++++++++++++++++
  // 拖动进度条时触发seeked事件
  video.addEventListener("seeked", () => {
      // 调用CanvasBarrage类的replay方法进行回放,重新渲染弹幕
      canvasBarrage.replay();
  });
  +++++++++++++++++++++++++++++++++++++++

让我们再次回到CanvasBarrage这个类上

OK,写到这里,所有关于弹幕功能的代码就全部结束了!!
如果工作中让你开发弹幕功能,你也可以在多敲几遍以上代码之后,得心应手的保证完成任务了。
敬请期待,下节更精彩

接下来我们再利用 WebSocket 和 redis 来进行一下较为实战的功能吧。

作者:chenhongdong
来源:
https://juejin.im/post/5be54a...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99996.html

相关文章

  • 一文解锁BILIBILI、ACFUN等弹幕网站如何审核视频

    摘要:欢迎访问网易云社区,了解更多网易技术产品运营经验。网易云易盾智能反垃圾服务,基于网易年专业的反垃圾经验,以及积累的亿级别的海量数据,为客户提供极速智能的广告过滤智能鉴黄暴恐识别涉政检测云服务,助力打造互联网纯净内容生态。文章来源网易云社区 欢迎访问网易云社区,了解更多网易技术产品运营经验。 人工审核对于A站和B站都是很重要的。 AcFun稿件审核通行标准(V1.1) 表明,要审核的东西...

    刘德刚 评论0 收藏0
  • 你只知道别人很牛,但你知道那些编程水平很高的程序员怎么成的吗?

    摘要:要达到水平很高的程序员,第一要找能提供优质实践机会的大厂,第二要在诸如高并发或机器学习的项目里多解决实际问题,第三还要不断跳槽,不断地找更优质的平台和更优质的项目机会。 ...

    booster 评论0 收藏0
  • 我的Java开发之路

    摘要:提高有了入门的基础,开始自学当时流行的三大框架和。业余的时间,经常在上闲逛,看一些博客或开源的代码。 最近有一位小伙伴通过公众号给我留言, 我参加工作没多久,看着圈里的技术大牛,特别羡慕,也渴望成为技术大牛,想让您分享一下从小白到大牛是怎样练成的,我该如何提高自己 首先,谢谢这位小伙伴的一直关注。其次,我并不是大牛,只是早搬了几年的砖而已,不过可以分享一下我的Java开发之路。 入门 ...

    lidashuang 评论0 收藏0
  • 弹幕给 PPD 生个孩子

    摘要:使用的的方法实现了文字滚动我们需要做一些准备工作例如我们为了让弹幕可以变颜色我们写了下面这个方法。判断存储弹幕信息的数据是否为空随机抽取数组中的一个元素之后把它追加到这个中执行文字滚动的方法。 怎样才能跑起来我写的弹幕程序 资源下载 申请野狗后端云账号注册 创建应用:showImg(https://segmentfault.com/img/remote/146000000683932...

    linkFly 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<