简单的Canvas弹幕效果(2)

字数 539阅读 209

在上一篇文章里,只是实现了简单的弹幕位移。

现在把元素改为真正的播放器:

<div class="video-placeholder"></div> 

=>

<style>
#videoBarrage {
  background-color: black;
  outline: 1px solid #eee;
}
</style>

<video id="videoBarrage" width="640" height="360" src="F:/BaiduYunDownload/电影/13.mp4" controls>
</video>
image.png

这时发现,视频暂停的时候,弹幕不会停止,现在实现这个功能,这时只要加一个标志就可以了,并且只在不暂停时运行render:

    var video = document.getElementById('videoBarrage');
    var isPause = true;

    video.addEventListener('play', function() {
        isPause = false;
        render();
    });
    video.addEventListener('pause', function() {
        isPause = true;
    });

    var render = function() {
        context.clearRect(0, 0, canvas.width, canvas.height);
        drawAll();
        if (!pause) {
            requestAnimationFrame(render);
        }
    };

(2)实现弹幕的颜色、透明度、字号

就修改一下即可:

        function Barrage(obj, index) {
            // 随机x坐标也就是横坐标,对于y纵坐标,以及变化量speed
            this.x = canvas.width;
            this.y = canvas.height * Math.random();
            this.speed = 2;

            this.opacity = 0.8;
            this.text = obj.value || '';
            this.color = obj.color || 'red';
            this.fontSize = obj.fontSize || 24;

        };

这时传入的数据就这样写了:

        var data = [{
            value: '使用的是静态数据',
            color: 'red',
            fontSize: 20
        }, {
            value: '随机循环播放',
            color: 'blue',
            fontSize: 28
        }, {
            value: '可以控制区域和垂直分布范围',
            color: 'yellow',
            fontSize: 16
        }, {
            value: '字体大小和速度在方法内设置',
            color: 'black',
            fontSize: '30'
        }]

(3)弹幕的时间

发弹幕一般是看到视频的哪里,弹幕就出现在那时间,而我们现在的弹幕都是一开始就出现的。

现在实现这个功能,给弹幕对象增加一个属性:
this.time = obj.time;

所以传入的数据就要有time属性:

{
  value: '随机循环播放',
  color: 'blue',
  fontSize: 28,
  time: 4
}

这时候后,弹幕就不能直接绘制到画布上了,而是等时间到了再绘制上去即可:

        var drawAll = function() {
            for (var i in store) {
                var barrage = store[i];
                if (video.currentTime > barrage.time) {
                    barrage.x -= barrage.speed;
                    store[i].draw();
                }
            }
        };

(4)发送弹幕功能

首先增加元素:

    <input id="input" name="value" required>
    <button id="submit" disabled>发送弹幕</button>

当输入框有内容时,可点击发送弹幕按钮,然后添加新弹幕到store中,时间为此时veido的时间。

      var input = document.getElementById('input');
      var submitBtn = document.getElementById('submit');

      input.addEventListener('input', () => {
          if (input.value.trim()) {
              submitBtn.disabled = false;
          } else {
              submitBtn.disabled = true;
          }
      }); 

      submitBtn.addEventListener('click', (event) => {
        event.preventDefault();

        barrage.add({
            value: input.value,
            time: document.getElementById('videoBarrage').currentTime
        });

        input.value = '';
        submitBtn.disabled = true;
     });

store是CanvasBarrage函数中的变量,这时候就要在函数中定义接口add暴露出来,随便把render函数也修改一下:

            var render = function() {
                    context.clearRect(0, 0, canvas.width, canvas.height);
                    drawAll();
                    if (!pause) {
                        requestAnimationFrame(render);
                    }
                };
                var add = function(obj) {
                store[Object.keys(store).length] = new Barrage(obj);
            };

                return {
                    add,
                    render
                }

这时函数就要这样使用了:

var barrage = CanvasBarrage('#canvasBarrage', barrageData);
barrage.render();

(4)视频拖动
弹幕有个问题,就是拖动视频进度后,弹幕不再绘制了。这时因为弹幕都绘制过了。

这时可以监听veido的拖动进度事件,然后重置一下弹幕位移。

                video.addEventListener('seeked', () => {
                    reset();
                });

                var reset = function() {
                    for (var i in store) {
                        store[i].x = canvas.width;
                    }
                }

但是当进度时间大于弹幕时间时,这时所有弹幕会一起出现,所以我们的绘制条件要修改一下,给每个弹幕对象一个标志:

this.isShow = true;

此时绘制条件也改为:

                    if (video.currentTime > barrage.time && barrage.isShow) {
                        barrage.x -= barrage.speed;
                        store[i].draw();
                    }

重置方法改为:

                var reset = function() {
                  context.clearRect(0, 0, canvas.width, canvas.height);

                    for (var i in store) {
                        var barrage = store[i];
                        if (video.currentTime > barrage.time) {
                            barrage.isShow = false;
                        } else {
                            store[i].x = canvas.width;
                        }
                    }
                }

(5)关闭与打开弹幕:

    <div id="toggle">
        <label for="close">打开弹幕</label><input id="open" name="toggle" type="radio" value="open" />
        <label for="open">关闭弹幕</label><input id="close" name="toggle" type="radio" value="close" />     
    </div>
      var toggle = document.getElementById('toggle');

      toggle.addEventListener('change', (event) => {
        if (event.target.value === 'close') {
            barrage.close();
        } else {
            barrage.open();
        }
      });

同样开放接口来控制:

            var close = function() {
                        canvas.style.visibility = 'hidden'; 
                context.clearRect(0, 0, canvas.width, canvas.height);

            }
            var open = function() {
                render();
                        canvas.style.visibility = 'visible';                
            }           

                return {
                    add,
                    render,
                    close,
                    open
                }

当然这里只是简单的显示和隐藏,并没有关闭动画。

推荐阅读更多精彩内容