用canvas实现一个vue弹幕组件

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

内容简介:看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弹幕组件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Practical JavaScript, DOM Scripting and Ajax Projects

Practical JavaScript, DOM Scripting and Ajax Projects

Frank Zammetti / Apress / April 16, 2007 / $44.99

http://www.amazon.com/exec/obidos/tg/detail/-/1590598164/ Book Description Practical JavaScript, DOM, and Ajax Projects is ideal for web developers already experienced in JavaScript who want to ......一起来看看 《Practical JavaScript, DOM Scripting and Ajax Projects》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具