用canvas实现一个vue弹幕组件

栏目: Html5 · 发布时间: 5年前

内容简介:看B站时,对弹幕的实现产生了兴趣,一开始想到用css3动画去实现,后来感觉这样性能不是很好,查了下资料,发现可以用canvas实现,于是就摸索着写了一个简单的弹幕。

看B站时,对弹幕的实现产生了兴趣,一开始想到用css3动画去实现,后来感觉这样性能不是很好,查了下资料,发现可以用canvas实现,于是就摸索着写了一个简单的弹幕。

弹幕功能

  1. 支持动态添加弹幕
  2. 弹幕不重叠
  3. 自定义弹幕颜色

效果图

demo

源码地址

用canvas实现一个vue弹幕组件

前端框架选了比较熟悉的vuejs

弹幕滚动的基本思路就是通过定时器不断地改变弹幕的位置,时时重绘画布。

实现步骤

先加入一个canvas标签,这里有个注意点,关于设备像素比对canvas的影响,会出现绘图模糊。

canvas 绘图模糊问题

<canvas width="600" height="600"></canvas> // 如果单纯这样写,canvas会出现模糊

<canvas width="600" height="600" style="width: 300px;height: 300px"></canvas>

//为了不出现模糊,需要设置canvas的css宽高为上下文宽高的1/devicePixelRatio,
本文是对于devicePixelRatio:2的设备设置的,该值可从window.devicePixelRatio取得。
<canvas ref="hiddenCanvas" width="0" height="0" style="display: none"></canvas> 
// 后面会用到复制代码

我们先定义一个数组来存放弹幕数据,一条弹幕信息,包括文本内容,x,y坐标位置,颜色,速度(可以是随机或者固定,为了计算简单,我们这里采用了固定的速度)

var dmArr = [];
var gap = 80; // 弹幕的上下间距
var hiddenCanvas = this.$refs.hiddenCanvas;

// 增加弹幕的方法
function pushDm(text, color) {
    let y = getY(); // 先确定跑道
    let x = 600; // 初始x坐标为canvas的右边界
    let delayWidth = 0; // 同跑道
    for (let i = 0, len = dmArr.length; i < len; i++) {
        let dm = dmArr[i];
        if (y === dm.y) { // 如果是同跑道,则往后排,设置一定的间隔,保证弹幕不会重叠;
            delayWidth += Math.floor(hiddenCanvas.getContext('2d').measureText(dm.text).width * 4 + 50);
        }   }
   dmArr.push({
       text: text,
       x: x + delayWidth,
       y: y,
       speed: 8,
       color: color || getColor()
   });
}
// 随机获得y坐标
function getY() {
    let range = Math.floor(600 / gap); // 跑道数量
    return Math.floor(Math.random() * range + 1) * gap;
}
// 随机获得颜色
function getColor() {
    return `${Math.floor(Math.random() * 16777215).toString(16)}`;
}

// 写一个for循环,初始化30条弹幕
for (let i = 0; i < 30; i++) {
    pushDm(`It's barrage ${i}`);
}

复制代码

接下来设置一个20ms的定时器,实现弹幕滚动效果

var timer = null;
var ctx = this.$refs.canvas.getContext('2d');
function start(){
  timer = setInterval(() => {
    ctx.clearRect(0, 0, 600, 600); // 每次需要清空画布
    ctx.save();
    ctx.font = '30px Microsoft YaHei'; // 这里需要把字体大小设为需要显示的css大小的2倍(devicePixelRatio为2时)
    if (!dmArr.length) stop(); // 如果没有新弹幕了,就停止计时器
    for (let i = 0, len = this.dmArr.length; i < len; i++) {
        let dm = dmArr[i];
        let overRange = -ctx.measureText(dm.text).width * 2;
        dm.x -= dm.speed;
        if (dm.x < overRange) {
            dmArr.splice(i, 1); // 弹幕在画布中不可见时,从数组中移除该项
            continue;
        }
        ctx.fillStyle = `#${dm.color}`;
        ctx.fillText(dm.text, dm.x, dm.y);
    }
    ctx.restore();
  }, 20);
}
function stop() {
    clearInterval(timer);
    ctx.clearRect(0, 0, 600, 600);
}复制代码

我们还需要一个输入框,来实现手动添加弹幕功能

<input type="text" @keyup.enter="sent" v-model="dmInput" maxlength="20">
<button type="button" @click="sent">发表</button>

var dmInput = '';
var color = ''; // 可自定义弹幕的颜色
function sent() {
    if (!dmInput) return;
    stop();
    pushDm(dmInput, color);
    start();
    dmInput = '';
}复制代码

有待改进的地方和疑问?

  1. 速度不恒定时,怎么保持弹幕不重叠
  2. 视频弹幕是根据弹幕发送时间点来定位到视频的每一帧?如何实现?

以上所述就是小编给大家介绍的《用canvas实现一个vue弹幕组件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Iterative Methods for Sparse Linear Systems, Second Edition

Iterative Methods for Sparse Linear Systems, Second Edition

Yousef Saad / Society for Industrial and Applied Mathematics / 2003-04-30 / USD 102.00

Tremendous progress has been made in the scientific and engineering disciplines regarding the use of iterative methods for linear systems. The size and complexity of linear and nonlinear systems arisi......一起来看看 《Iterative Methods for Sparse Linear Systems, Second Edition》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具