视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
h5怎样通过canvas来实现滚动弹幕功能
2020-11-27 15:27:16 责编:小采
文档

这次给大家带来h5怎样通过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 < len ; i++){
 if (topObjs[i].blank) {
 this.top = topObjs[i].value
 this.topIndex = i
 topObjs[i].blank = false
 break
 }
 }
 }
 Caption.prototype.setLeftValue = function () {
 if (this.isMove) {
 this.left = cavWidth
 }
 else {
 var contentLength = this.content.length
 var nowItemLeft = 420 - contentLength * 9
 this.left = nowItemLeft
 }
 }
 Caption.prototype.moving = function () {
 if (this.isMove) {
 this.left-=this.speed
 if ( this.left + this.width < cavWidth && this.occupyPos) {
 this.occupyPos = false
 topObjs[this.topIndex].blank = true
 }
 }
 else{
 this.latestTime += 1
 if (this.latestTime > 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 < len ; i++ ){
 ctx.fillStyle = capObjs[i].color
 ctx.font = "bold 20px Courier New"
 ctx.fillText( capObjs[i].content , capObjs[i].left , capObjs[i].top )
 ctx.closePath()
 capObjs[i].moving()
 // if (capObjs[i].left < - cavWidth ) {
 // capObjs.splice (i ,1)
 // if excute this statement , will has fault because some item in array is null
 // solution is : write a new function to refresh the array 
 // }
 }
 }
 
 //更新数组,当对象已经超出范围的时候从数组删除这个对象
 function refreshObjs(objs) {
 for (var i = objs.length - 1; 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 < len ; i++) {
 arr2[i] = arr1[i]
 } 
 }
 
 //color select event 用户发送弹幕的颜色控制代码
 colorUl.addEventListener("click", function( e ){
 var prevSelectItemId = ""
 switch (selectedColorIndex) {
 case 0:
 prevSelectItemId = "colorItemFrist"
 break;
 case 1:
 prevSelectItemId = "colorItemSecond"
 break;
 case 2:
 prevSelectItemId = "colorItemThrid"
 break;
 case 3:
 prevSelectItemId = "colorItemFourth"
 break;
 case 4:
 prevSelectItemId = "colorItemFifth"
 break;
 case 5:
 prevSelectItemId = "colorItemSixth"
 break;
 default:
 // statements_def
 break;
 }
 var prevSelectItem = document.getElementById(prevSelectItemId)
 prevSelectItem.className = ""
 var eventTarget = e.target
 eventTarget.className = "selectedColor"
 var eveTarId = eventTarget.id.substring(9)
 switch (eveTarId) {
 case "Frist":
 selectedColorIndex = 0
 break;
 case "Second":
 selectedColorIndex = 1
 break;
 case "Thrid":
 selectedColorIndex = 2
 break;
 case "Fourth":
 selectedColorIndex = 3
 break;
 case "Fifth":
 selectedColorIndex = 4
 break;
 case "Sixth":
 selectedColorIndex = 5
 break;
 default:
 // statements_def
 break;
 }
 }, false)
 
 video.addEventListener("playing" , function () {
 initCanvas()
 })
 
 //进度条改变执行代码
 video.addEventListener("timeupdate", function () {
 var nowPlayTime = video.currentTime
 var diffTime = Math.abs(nowPlayTime - prevPlayTime)
 prevPlayTime = nowPlayTime
 if (diffTime > 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
})()

相信看了这些案例你已经掌握了方法,更多精彩请关注Gxl网其它相关文章!

相关阅读:

HTML的table鼠标拖拽排序该如何实现

HTML 5之新增的特性该如何使用

怎样解决各种ie6-ie10的兼容问题

下载本文
显示全文
专题