热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用canvas实现视频里的弹幕效果-

这次给大家带来使用canvas实现视频里的弹幕效果,使用canvas实现视频弹幕效果的注意事项有哪些,下面就是实战案例,一起来看一下。
这次给大家带来使用canvas实现视频里的弹幕效果,使用canvas实现视频弹幕效果的注意事项有哪些,下面就是实战案例,一起来看一下。

最近在着手开发弹幕视频网站,通过html5中的canvas实现了弹幕的功能。

那么闲言碎语不要讲,先说思路后上代码。

思路:从页面布局上来说就是将一块画布覆盖在了video标签产生的视频窗口之上,使用绝对定位就能实现了。最重要的就是js控制画布上弹幕的显示了,每一个弹幕都包装成一个对象,对象包含的属性有弹幕应该出现的时间,弹幕的颜色,弹幕是否是移动的以及弹幕的文本。弹幕对象拥有方法包含:设置弹幕的横纵坐标,弹幕的移动函数。实现的原理,在监听视频开始播放的事件,在视频开始播放时生成一个定时器,定时器每隔一个时间去遍历循环弹幕对象数组并根据对象的属性在画布的适当位置上绘制出弹幕,计时器中除了绘制弹幕的代码还有执行更新弹幕数组的代码。

下图是弹幕效果截屏

那么下面开始直接上代码:

(function () {
    window.Onload=function () {
        var video = document.getElementsByTagName("video")[0]
        var cav = document.getElementsByTagName("canvas")[0]
        //设置常量canvas的高度以及宽度
        var cavWidth = 800 
        var cavHeight = 420
        cav.width=cavWidth
        cav.height=cavHeight 
        var ctx = cav.getContext("2d")
        //存储弹幕对象的数组
        var capObjs = []
        var lastItemTime
        var capHeight = 20 
        var inputEle = document.getElementsByClassName("caption-input-text")[0]
        var sendEle = document.getElementsByClassName("caption-sendButton")[0]
        var colorUl = document.getElementsByClassName("colorItems")[0]
        var ismoveInputEle = document.getElementsByClassName("caption-input-ismove")[0]
        //弹幕颜色
        var colors=["#fff","#FFCCCC","#CCFFCC","#CCCCFF","#FFFFCC","#CCFFFF"]
        var selectedColorIndex = 0
        var prevPlayTime = 0
        //测试数据的数组
        var testArrayCopy = []
        var capobjId = 0
        //弹幕在画布中高度可能值组成的数组
        var topObjs = [{blank:true , value : 20 ,index:0},
                        {blank:true , value : 50 ,index:1},
                        {blank:true , value : 80 ,index:2},
                        {blank:true , value : 110 ,index:3},
                        {blank:true , value : 140 ,index:4},
                        {blank:true , value : 170 ,index:5},
                        {blank:true , value : 200 ,index:6},
                        {blank:true , value : 230 ,index:7},
                        {blank:true , value : 260 ,index:8},
                        {blank:true , value : 290 ,index:9},
                        {blank:true , value : 320 ,index:10},
                        {blank:true , value : 350 ,index:11},
                        {blank:true , value : 380 ,index:12},
                        {blank:true , value : 410 ,index:13}]
//test data 测试数据
var testArray = [{content:"ABCDEFGHIJKLMNOPQRSTUVWXYZ",time:"1",ismove:false,colorIndex:0},
{content:"233333333333333",time:"2",ismove:true,colorIndex:0},
{content:"干杯,哈哈哈~~~~~~",time:"2",ismove:true,colorIndex:5},
{content:"干杯,哈哈哈~~~~~~",time:"2",ismove:true,colorIndex:4},
{content:"干杯,哈哈哈~~~~~~",time:"2",ismove:true,colorIndex:4},
{content:"干杯,哈哈哈~~~~~~",time:"2",ismove:true,colorIndex:0},
{content:"干杯,哈哈哈~~~~~~",time:"2",ismove:true,colorIndex:0},
{content:"233333333333333",time:"3",ismove:true,colorIndex:0},
{content:"233333333333333",time:"3",ismove:true,colorIndex:0},
{content:"233333333333333",time:"3",ismove:true,colorIndex:0},
{content:"233333333333333",time:"3",ismove:true,colorIndex:0},
{content:"233333333333333",time:"3",ismove:true,colorIndex:0},
{content:"233333333333333",time:"3",ismove:true,colorIndex:0},
{content:"233333333333333",time:"4",ismove:false,colorIndex:0},
{content:"233333333333333",time:"5",ismove:true,colorIndex:4},
{content:"233333333333333",time:"6",ismove:true,colorIndex:2},
{content:"233333333333333",time:"7",ismove:true,colorIndex:2},
{content:"233333333333333",time:"7",ismove:true,colorIndex:2},
{content:"233333333333333",time:"7",ismove:true,colorIndex:2},
{content:"233333333333333",time:"7",ismove:true,colorIndex:2},
{content:"233333333333333",time:"7",ismove:true,colorIndex:2},
{content:"233333333333333",time:"7",ismove:true,colorIndex:2},
{content:"233333333333333",time:"8",ismove:true,colorIndex:0},
{content:"233333333333333",time:"9",ismove:true,colorIndex:0},
{content:"233333333333333",time:"10",ismove:true,colorIndex:0},
{content:"老师说的非常好,我要好好学习了》》》》",time:"12",ismove:true,colorIndex:0},
{content:"老师说的非常好,我要好好学习了》》》》",time:"13",ismove:true,colorIndex:0},
{content:"老师说的非常好,我要好好学习了》》》》",time:"14",ismove:true,colorIndex:2},
{content:"老师说的非常好,我要好好学习了》》》》",time:"15",ismove:false,colorIndex:0},
{content:"老师说的非常好,我要好好学习了》》》》",time:"16",ismove:true,colorIndex:2},
{content:"老师说的非常好,我要好好学习了》》》》",time:"17",ismove:true,colorIndex:3},
{content:"老师说的非常好,我要好好学习了》》》》",time:"18",ismove:true,colorIndex:2},
{content:"老师说的非常好,我要好好学习了》》》》",time:"19",ismove:true,colorIndex:0},
{content:"老师说的非常好,我要好好学习了》》》》",time:"20",ismove:true,colorIndex:3},
{content:"老师说的非常好,我要好好学习了》》》》",time:"21",ismove:true,colorIndex:0},
{content:"老师说的非常好,我要好好学习了》》》》",time:"22",ismove:true,colorIndex:0},
{content:"老铁们,小礼物走一波了,小汽车小火箭刷起来吧=========",time:"23",ismove:true,colorIndex:0},
{content:"老铁们,小礼物走一波了,小汽车小火箭刷起来吧=========",time:"24",ismove:true,colorIndex:0},
{content:"老铁们,小礼物走一波了,小汽车小火箭刷起来吧=========",time:"25",ismove:true,colorIndex:3},
{content:"老铁们,小礼物走一波了,小汽车小火箭刷起来吧=========",time:"26",ismove:true,colorIndex:0},
{content:"老铁们,小礼物走一波了,小汽车小火箭刷起来吧=========",time:"27",ismove:true,colorIndex:5},
{content:"老铁们,小礼物走一波了,小汽车小火箭刷起来吧=========",time:"28",ismove:false,colorIndex:5},
{content:"老铁们,小礼物走一波了,小汽车小火箭刷起来吧=========",time:"29",ismove:true,colorIndex:5},
{content:"老铁们,小礼物走一波了,小汽车小火箭刷起来吧=========",time:"30",ismove:true,colorIndex:5},
{content:"马上就下课了,瓦罗蓝大陆走起了~~~",time:"31",ismove:true,colorIndex:5},
{content:"马上就下课了,瓦罗蓝大陆走起了~~~",time:"32",ismove:true,colorIndex:2},
{content:"马上就下课了,瓦罗蓝大陆走起了~~~",time:"33",ismove:true,colorIndex:2},
{content:"马上就下课了,瓦罗蓝大陆走起了~~~",time:"33",ismove:true,colorIndex:5},
{content:"马上就下课了,瓦罗蓝大陆走起了~~~",time:"34",ismove:true,colorIndex:5},
{content:"马上就下课了,瓦罗蓝大陆走起了~~~",time:"35",ismove:true,colorIndex:5},
{content:"马上就下课了,瓦罗蓝大陆走起了~~~",time:"36",ismove:true,colorIndex:2},
{content:"马上就下课了,瓦罗蓝大陆走起了~~~",time:"37",ismove:true,colorIndex:2}]
        //将测试数据备份
        copyArray(testArray , testArrayCopy)
        /*弹幕对象的构造函数,参数分别是:1.ismove:弹幕是否是移动的弹幕,2.spe:弹幕的移动速度,3.col:弹幕的颜色,4.text:弹幕的文本*/
        /*原型链方法 setTopValue设置纵坐标,setLeftValue设置横坐标,moving完成坐标的改变,setId完成id值的设置*/
        function Caption( ismove , spe , col , text ) {
            this.isMove = ismove
            this.speed = spe
            this.color = col || "#ff0"
            this.cOntent= text
            this.latestTime = 0 
            this.width = text.length * 20 
            this.id = 0
            this.topIndex = 0
            this.occupyPos = true 
            this.top = 300
            this.left = 0
            this.setLeftValue()
            this.setTopValue()
        }
        Caption.prototype.setTopValue = function  () {
            for(var i = 0 ,len = topObjs.length ; i  450) {
                    topObjs[this.topIndex].blank = true 
                }
            }
        }
        Caption.prototype.setId = function  () {
            this.id = capobjId
            capobjId++
        }
        var cap1 = new Caption(  false , 1 , 0 , "小礼物走一波,双击6666。。。。")
        capObjs.push(cap1)
        cap1.setId()
        
        //循环遍历数组,根据对象的属性绘制在画布上
        function drawAllText () {
            ctx.clearRect( 0 , 0 , cavWidth , cavHeight)
            ctx.beginPath()
            for(var i=0 , len = capObjs . length ; i = 0; i--) {
                if (objs[i].left <- cavWidth || objs[i].latestTime > 450 ) {
                    objs.splice(i , 1)
                }
            }
        }
        
        //更新保存弹幕对象的数组
        function updateArray () {
            var now = parseInt( video.currentTime )
            for (var i = testArray.length - 1; i >= 0; i--) {
                var nowItemTime = parseInt(testArray[i].time) 
                if ( nowItemTime == now ) {
                    //首次写的控制高度的方式,空间利用不充分,后来改为setTopValue中的方式
                    // var nowItemLeft = getLeftValue(testArray[i])
                    // var diffTime = Math.abs(nowItemTime - lastItemTime)
                    // if (diffTime <6) { 
                    //     capHeight += 30
                    //     capHeight = capHeight > 400 ? 20 : capHeight
                    // }    
                    var temcolor = colors[testArray[i].colorIndex]
                    var temcap = new Caption (  testArray[i].ismove , 1 , temcolor , testArray[i].content  )
                    capObjs.push(temcap)
                    capObjs[capObjs.length - 1].setId()
                    temcap = null
                    testArray.splice(i,1)
                }
            }
        }
        
        //当用户点击send发送弹幕的回调函数
        function sendCaption (argument) {
            var inputEleTxt = inputEle.value
            var now = parseInt( video.currentTime )
            var inputIsmoveValue = ismoveInputEle.checked
            var temObj = {content:inputEleTxt,time:now,ismove:inputIsmoveValue,colorIndex:selectedColorIndex}
            testArray.push(temObj)
            inputEle.value = ""
        }
        // function getLeftValue (obj) {
        //     if (obj.ismove) {
        //         return 0
        //     }
        //     else {
        //         var cOntentLength= obj.content.length
        //         var nowItemLeft = 420 - contentLength * 9
        //         return nowItemLeft
        //     }
        // }
        
        //重新启动canvas,用在人为导致进度条时间的改变
        function reinitCav (argument) {
            // testArray = testArrayCopy
            copyArray(testArrayCopy , testArray)
            capObjs = []
            capHeight = 0
            clearInterval(canvasTimer)
            canvasTimer = null
            initCanvas()
        }
        var canvasTimer = null 
        
        //初始化canvas,用在开始播放时
         function initCanvas () {
             if (canvasTimer == null ) {
                canvasTimer = setInterval(function (argument) {
                    drawAllText()
                    updateArray()
                    refreshObjs(capObjs)
                },10)
             }
            
        }//end function initCanvas
        
        //复制数组
        function copyArray (arr1 , arr2) {
            for (var i =0 , len=arr1.length ; i  1) {
                reinitCav()
            }
        }, false)
        
        //视频暂停执行代码
        video.addEventListener("pause" , function () {
            clearInterval(canvasTimer)
            canvasTimer = null 
        })
        
        //点击send的监听事件
        sendEle.addEventListener("click" , sendCaption)
        
        //input的回车监听事件
        inputEle.addEventListener("keydown", function(e) {
            var keynum = 0
            keynum = window.event ? e.keyCode : e.which
            if (keynum == 13) {
                sendCaption()
            }
        })
        var aaaa = function() {
            alert(1)
        }
        aaaa()
        // function b(aaaa){
        //     return aaaa()
        // }
        // b()    
    }//end
})()

相信看了本文案例你已经掌握了方法,更多精彩请关注 第一PHP社区 其它相关文章!

推荐阅读:

H5实现可缩放的时钟动画

Drag事件编辑器实现拖拽上传图片效果

以上就是使用canvas实现视频里的弹幕效果的详细内容,更多请关注 第一PHP社区 其它相关文章!


推荐阅读
  • Bootstrap Paginator 分页插件详解与应用
    本文深入探讨了Bootstrap Paginator这款流行的JavaScript分页插件,提供了详细的使用指南和示例代码,旨在帮助开发者更好地理解和利用该工具进行高效的数据展示。 ... [详细]
  • 本文提供了一个详尽的前端开发资源列表,涵盖了从基础入门到高级应用的各个方面,包括HTML5、CSS3、JavaScript框架及库、移动开发、API接口、工具与插件等。 ... [详细]
  • 本文详细探讨了在Web开发中常见的UTF-8编码问题及其解决方案,包括HTML页面、PHP脚本、MySQL数据库以及JavaScript和Flash应用中的乱码问题。 ... [详细]
  • HTML前端开发:UINavigationController与页面间数据传递详解
    本文详细介绍了如何在HTML前端开发中利用UINavigationController进行页面管理和数据传递,适合初学者和有一定基础的开发者学习。 ... [详细]
  • 本文探讨了当通过Nginx访问网站时出现504 Gateway Timeout错误的解决方案,特别是当请求处理时间超过30秒时的情况。文章提供了调整PHP-FPM配置的具体步骤,以延长请求超时时间。 ... [详细]
  • 本文探讨了线性表中元素的删除方法,包括顺序表和链表的不同实现策略,以及这些策略在实际应用中的性能分析。 ... [详细]
  • 实现Win10与Linux服务器的SSH无密码登录
    本文介绍了如何在Windows 10环境下使用Git工具,通过配置SSH密钥对,实现与Linux服务器的无密码登录。主要步骤包括生成本地公钥、上传至服务器以及配置服务器端的信任关系。 ... [详细]
  • 本文由chszs撰写,详细介绍了Apache Mina框架的核心开发流程及自定义协议处理方法。文章涵盖从创建IoService实例到协议编解码的具体步骤,适合希望深入了解Mina框架应用的开发者。 ... [详细]
  • 本文提供了一个关于AC自动机(Aho-Corasick Algorithm)的详细解析与实现方法,特别针对P3796题目进行了深入探讨。文章不仅涵盖了AC自动机的基本概念,还重点讲解了如何通过构建失败指针(fail pointer)来提高字符串匹配效率。 ... [详细]
  • 本报告记录了嵌入式软件设计课程中的第二次实验,主要探讨了使用KEIL V5开发环境和ST固件库进行GPIO控制及按键响应编程的方法。通过实际操作,加深了对嵌入式系统硬件接口编程的理解。 ... [详细]
  • 本文分享了作者在使用LaTeX过程中的几点心得,涵盖了从文档编辑、代码高亮、图形绘制到3D模型展示等多个方面的内容。适合希望深入了解LaTeX高级功能的用户。 ... [详细]
  • LeetCode 102 - 二叉树层次遍历详解
    本文详细解析了LeetCode第102题——二叉树的层次遍历问题,提供了C++语言的实现代码,并对算法的核心思想和具体步骤进行了深入讲解。 ... [详细]
  • Markdown 编辑技巧详解
    本文介绍如何使用 Typora 编辑器高效编写 Markdown 文档,包括代码块的插入方法等实用技巧。Typora 官方网站:https://www.typora.io/ 学习资源:https://www.markdown.xyz/ ... [详细]
  • 实践指南:使用Express、Create React App与MongoDB搭建React开发环境
    本文详细介绍了如何利用Express、Create React App和MongoDB构建一个高效的React应用开发环境,旨在为开发者提供一套完整的解决方案,包括环境搭建、数据模拟及前后端交互。 ... [详细]
  • 原文地址:https:blog.csdn.netqq_35361471articledetails84715491原文地址:https:blog.cs ... [详细]
author-avatar
多米音乐_34429718
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有