使用canvas如何实现发送视频弹幕,H5 Canvas学习

canvas实现视频弹幕

老样子,先看效果图,再进行愉悦的学习~

在这里插入图片描述

什么是canvas

canvas(画布)可以使用Javascript在网页中绘制图形图像。基本结构:

<canvas id="" width="" height=""></canvas>

width:定义画布的宽度

height:定义画布的高度

canvas 的基本使用

基本绘制步骤如下:

let cvs = document.getElementById('canvas');
// 获取用于绘制2维图像的context对象
let ctx = cvs.getContext('2d'); 
// 调用相关API,绘制图像
ctx.fillStyle = 'red'
ctx.fillRect(x, y, width, height);

canvas元素的方法:

let ctx = cvs.getContext(type);

type上下文类型:

2d 返回 CanvasRenderingContext2D。用于画二维图像。

webgl 返回 WebGLRederingContext。用于渲染三维图像。(three.js

canvas基础绘图API

填充

ctx.fillStyle = 'red'   				// 设置填充颜色
ctx.fillRect(x,y,width,height);         // 填充矩形

描边

ctx.strokeStyle = 'blue'  // 设置描边的颜色
ctx.strokeRect(x,y,width,height);   // 描边矩形

绘制文本

ctx.font = '25px  微软雅黑'  // 设置字体
ctx.fillText('文本内容', x, y);    // 填充文本
ctx.strokeText('文本内容', x, y);  // 描边文本
Canvas路径绘图API

路径(Path)是将预先设定好的坐标点按照顺序连接起来所形成的图形。

路径的绘制步骤:

  1. 通过ctx.beginPath()开启一条新的路径。
  2. 通过ctx.moveTo(x, y) 将画笔移动到指定位置。
  3. 通过ctx的相关方法开始绘制路径(经典方法:lineTo(x, y))。
  4. 最后通过ctx.stroke()ctx.fill()方法对路径进行描边或填充。

了解完基础,让我们一起瞅瞅视频弹幕的实现

Canvas动画

动画的本质即:每隔一段时间(非常快 1/60秒[每秒60帧])重绘画布。只要能保证60帧,由于视觉残留现象,就会出现动画效果。

window.setInterval(()=>{
	重绘UI
}, 1000/60)

案例:实现弹幕。

  1. video标签之上蒙一层canvas

  2. 添加inputbutton,实现发送弹幕功能。

    不仅需要发送弹幕,还需要让弹幕动起来。但是不能每个弹幕都启动一个定时器,因为太消耗资源。一个定时器管理所有弹幕的动画足矣。这样设计的话就不能再点击发送按钮时启动定时器,而是页面加载后,就可以启动唯一的定时器了。定时器所做的事情是将所有弹幕的位置一起更新,一起绘制。

    这就意味着,发送弹幕操作,其实只是向弹幕数组中添加一个弹幕对象即可,不需要关心绘制的事情。

    1. 准备一个存储弹幕对象的数组:dmlist = {}
    2. 当发送弹幕时,把弹幕内容、x、y封装成对象,存入dmlist
    3. 页面加载完毕后,启动一个定时器,不断(每秒60帧)执行回调方法,每次执行回调方法时加载dmlist,读取每个弹幕信息,更新弹幕的x坐标,重新绘制canvas中的所有弹幕内容。

具体实现步骤

1.在把canvas的画布定位到video视频标签上,html与css 样式如下

<div>	
	<video id="video" 
      src="https://huazizhanye.oss-cn-beijing.aliyuncs.com/catmovie.mp4"
      width="640" height="360"
      style="background: black;">
    </video>
    <canvas id="canvas" width="640" height="360"></canvas>


    <input id="range" type="range" min="0" value="0" max="100">
    <div class="time">
      <span class="left">00:00</span>
      <span class="right">00:00</span>
    </div>
    
    <button id="btn_play">播放/暂停</button>
    <button id="btn_vp">音量+</button>
    <button id="btn_vm">音量-</button>
    <button id="btn_05">0.5倍速</button>
    <button id="btn_1">1倍速</button>
    <button id="btn_2">2倍速</button>
    <br><br>
    <button id="btn_fc">全屏显示</button>
    <input id='input' type="text" placeholder="填写弹幕内容">
    <button id="send">发送弹幕</button>
 </div>
   .container {
      width: 400px;
      border: 1px solid #ddd;
      text-align: center;
      padding-bottom: 10px;
    }
    .container p{
      font-size: 1.3em;
      font-weight: bold;
      text-align: center;
    }
    .container img{
      width: 340px;
      height: 340px;
      border-radius: 50%;
    }
    .container input{
      width: 340px;
      display: block;
      margin: 10px auto;
    }
    .container .time{
      width: 340px;
      height: 30px;
      margin: 0px auto;
    }
    .container .time .left{
      float: left;
    }
    .container .time .right{
      float: right;
    }
    canvas{
      width: 640px; height: 360px; position: absolute;
      top: 0; left: 0;
    }
    .container{ position: relative; }
随便添加点按钮后~看图说话

在这里插入图片描述

– 点击发送按钮之后,将弹幕出现的位置随机化,并且每一条的信息push 到声明的数组中

// 发送弹幕
send.addEventListener('click', ()=>{
    let content = input.value; // 文本框的内容
    // 封装为dm对象,存入dmlist
    dmlist.push({
        content: content,
        x: 600,
        y: (Math.floor(Math.random() * 12)+1) * 30
    });
    console.log(dmlist);
})

– 实现核心定时器,每次发送新弹幕时候先清除定时器,否则定时器会累加导致卡 !。然后遍历数组中push 进来的数据,绘制到页面上

// 启动一个定时器 每秒执行60次,重绘UI
    window.setInterval(()=>{
      // 把canvas中的像素全部清除  重新绘制
      ctx.clearRect(0, 0, 640, 360);
      // 遍历dmlist,在canvas中进行绘制
      dmlist.forEach(item=>{ //item: 弹幕对象
        ctx.fillStyle = "white";
        ctx.font = '20px 微软雅黑';
        item.x--;
        ctx.fillText(item.content, item.x, item.y);
      })
    }, 1000/60);

完整代码如下,喜欢记得收藏

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>video_player.html</title>
  <style>
    .container {
      width: 400px;
      border: 1px solid #ddd;
      text-align: center;
      padding-bottom: 10px;
    }
    .container p{
      font-size: 1.3em;
      font-weight: bold;
      text-align: center;
    }
    .container img{
      width: 340px;
      height: 340px;
      border-radius: 50%;
    }
    .container input{
      width: 340px;
      display: block;
      margin: 10px auto;
    }
    .container .time{
      width: 340px;
      height: 30px;
      margin: 0px auto;
    }
    .container .time .left{
      float: left;
    }
    .container .time .right{
      float: right;
    }
    canvas{
      width: 640px; height: 360px; position: absolute;
      top: 0; left: 0;
    }
    .container{ position: relative; }
  </style>
</head>
<body>
  <div class="container">
    <video id="video" 
      src="https://huazizhanye.oss-cn-beijing.aliyuncs.com/catmovie.mp4"
      width="640" height="360"
      style="background: black;">
    </video>
    <canvas id="canvas" width="640" height="360"></canvas>


    <input id="range" type="range" min="0" value="0" max="100">
    <div class="time">
      <span class="left">00:00</span>
      <span class="right">00:00</span>
    </div>
    
    <button id="btn_play">播放/暂停</button>
    <button id="btn_vp">音量+</button>
    <button id="btn_vm">音量-</button>
    <button id="btn_05">0.5倍速</button>
    <button id="btn_1">1倍速</button>
    <button id="btn_2">2倍速</button>
    <br><br>
    <button id="btn_fc">全屏显示</button>
    <input id='input' type="text" placeholder="填写弹幕内容">
    <button id="send">发送弹幕</button>
  </div>

  <script src="assets/moment.js"></script>
  <script>

    let dmlist = []; // 存储弹幕对象
    let cvs = document.getElementById('canvas');
    let ctx = cvs.getContext('2d');

    // function step(){
    //   ctx.clearRect(0, 0, 640, 360);
    //   // 遍历dmlist,在canvas中进行绘制
    //   dmlist.forEach(item=>{ //item: 弹幕对象
    //     ctx.fillStyle = "white";
    //     ctx.font = '20px 微软雅黑';
    //     item.x--;
    //     ctx.fillText(item.content, item.x, item.y);
    //   })
    //   // 通知下次绘制UI时,再次执行step
    //   window.requestAnimationFrame(step);
    // }
    // window.requestAnimationFrame(step);

    // 启动一个定时器 每秒执行60次,重绘UI
    window.setInterval(()=>{
      // 把canvas中的像素全部清除  重新绘制
      ctx.clearRect(0, 0, 640, 360);
      // 遍历dmlist,在canvas中进行绘制
      dmlist.forEach(item=>{ //item: 弹幕对象
        ctx.fillStyle = "white";
        ctx.font = '20px 微软雅黑';
        item.x--;
        ctx.fillText(item.content, item.x, item.y);
      })
    }, 1000/60);

    // 发送弹幕
    send.addEventListener('click', ()=>{
      let content = input.value; // 文本框的内容
      // 封装为dm对象,存入dmlist
      dmlist.push({
        content: content,
        x: 600,
        y: (Math.floor(Math.random() * 12)+1) * 30
      });
      console.log(dmlist);
    })


    // 创建一个音频播放器
    let player = document.getElementById('video');

    btn_fc.addEventListener('click', ()=>{
      // player.requestFullscreen(); // 全屏显示dom元素
      btn_fc.requestFullscreen();
    })

    // 当拖拽进度条后,从拖拽结束位置继播放
    range.addEventListener('change', ()=>{
      player.currentTime = range.value;
    })

    // 资源加载完毕后更新总时长
    player.addEventListener('loadedmetadata', ()=>{
      let right=document.getElementsByClassName('right')[0];
      let tt=moment.unix(player.duration).format('mm:ss');
      right.innerHTML= tt;
    })
      
    // 处理一下进度条
    // 在音乐播放过程中捕获持续触发的timeupdate事件
    player.addEventListener('timeupdate', ()=>{
      console.log('timeupdated...');
      // 设置range的max  value   min
      range.max = player.duration; // 总时长
      range.value = player.currentTime; // 当前时长
      // 处理时间文本内容  使用momentjs转换字符串
      let left=document.getElementsByClassName('left')[0];
      let right=document.getElementsByClassName('right')[0];
      let tt=moment.unix(player.duration).format('mm:ss');
      let ct=moment.unix(player.currentTime).format('mm:ss');
      left.innerHTML = ct;
      right.innerHTML= tt;
      
    });

    // 设置倍速播放
    btn_05.addEventListener('click', ()=>{
      player.playbackRate = 0.5;
    })
    btn_1.addEventListener('click', ()=>{
      player.playbackRate = 1;
    })
    btn_2.addEventListener('click', ()=>{
      player.playbackRate = 2;
    })


    // 修改音量
    btn_vp.addEventListener('click', ()=>{
      player.volume = Math.min(1, player.volume+0.1);
      console.log(player.volume);
    })
    btn_vm.addEventListener('click', ()=>{
      player.volume = Math.max(0, player.volume-0.1);
      console.log(player.volume);
    })

    // 直接访问btn_play,就可以找到id=btn_play的dom对象
    btn_play.addEventListener('click', ()=>{
      if(player.paused){
        player.play();
      }else{
        player.pause();
      }
    })
  </script>

</body>
</html>
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值