首页 > 网页制作 > HTML/Xhtml教程 > 正文

HTML使用canvas实现弹幕功能_HTML/Xhtml_网页制作

2018-10-13 20:19:28

简介

 最近在做大作业的时候需要做一个弹幕播放器。借鉴了一下别人的源码自己重新实现了一个,演示如下

主要的功能有

发送弹幕
设置弹幕的颜色,速度和类型
显示弹幕
 

已知缺陷:

不能全屏

canvas没有做自适应
没有自定义播放器控件
没有根据播放时间显示相应的弹幕
弹幕不能实现悬停
已知的缺陷以后会进行改进。网上能找到的弹幕播放器的源码一般只做了滚动的弹幕而没有做静止的弹幕,这里我特意加上了静止弹幕的实现。

Canvas绘制文字以及文字滚动效果

 整个播放器的核心就是绘制文字以及做文字滚动的动画,canvas中对于文字并没有很好的动画支持,只能通过自己实现,实现的思路就是不断的清屏然后重写文字,当清屏重写的频率达到24fps的时候就是流畅的动画了。

先在HTML文件中添加视频video标签和画布canvas标签

<div id="barrageplayer">    <canvas id="cv_video" width="900px" height="450px"></canvas>    <video id="v_video" src="test.MP4" controls type="video/mp4"></video></div>

把canvas标签的位置样式设置为position:absolute然后视频和画布就重叠在一起,看起来就是一个弹幕播放器了。然后为画布添加弹幕相关的内容,首先获取画布的相关信息和设置画布的字体大小和字体样式

var c=document.getElementById("cv_video");//获取画布大小var c_height=c.height;var c_width=c.width;//获取画布ctx=c.getContext("2d");//设置字体样式ctx.font="25px DengXian";画布信息已经获取和设置,巧妇难为无米之炊,接着我们就要构造弹幕对象,使用的构造模式是动态原型模式//弹幕对象function Barrage(content,color,type,speed){    this.content=content;    this.color=color;    this.type=type;    this.speed=speed;    if(this.type=="default"){        this.height=parseInt(Math.random()*c_height)+10;    }else if (this.type=="static top"){        this.height=parseInt((c_height/2)-Math.random()*c_height/2)+10;    }else if (this.type=="static bottom"){        this.height=parseInt((c_height/2)+Math.random()*c_height/2)+10;    }    if(typeof this.move!="function"){        Barrage.prototype.move=function(){            if(this.type=="default"){                this.left=this.left-this.speed;            }        }    }}

构造的弹幕对象初始化了各种参数,包括内容,颜色,运动类型和速度,定义了move()方法来控制弹幕的缓动,每出发一次move()方法向左滚动一个单位speed的像素。
弹幕对象构造完成之后就进入到主题,动画的制作,直接上代码

//循环擦写画布实现动画效果setInterval(function(){    ctx.clearRect(0,0,c_width,c_height);    ctx.save();    for(var i=0;i<msgs.length;i++){        if(msgs[i]!=null){            if(msgs[i].type=="default"){                handleDefault(msgs[i]);            }else{                handleStatic(msgs[i]);           }        }    }},20)

每20ms执行一次擦写,ctx.clearRect(0,0,c_width,c_height);是将整张当前的画布清除,然后使用ctx.save()将当前的画布保存,接着遍历弹幕列表(msgs是弹幕列表,当每发送一条弹幕都会将该弹幕实例添加到列表中),然后按照默认样式的弹幕还是静止样式的弹幕分别处理。如果是默认样式的弹幕将会按照以下的方法处理

//处理默认弹幕样式function handleDefault(barrage){    if(barrage.left==undefined||barrage.left==null){        barrage.left=c.width;    }else{         if(barrage.left<-200){            barrage=null;        }else{            barrage.move()            ctx.fillStyle=barrage.color;            ctx.fillText(barrage.content,barrage.left,barrage.height)            ctx.restore();        }    }  }

 

首先如果弹幕实例没有设置left属性则将画布的宽度赋予它,如果弹幕实例已经退出画布则将其置null以节省内存,否则的话就调用弹幕实例的move()方法改变left属性的值,然后设置文字的颜色,一级写入新的文字,恢复画布。这样就完成了一帧动画。

对于静止弹幕的实现方法如下

//处理静止弹幕样式function handleStatic(barrage){    ctx.moveTo(c_width/2,barrage.height);    ctx.textAlign="center";    ctx.fillStyle=barrage.color;    ctx.fillText(barrage.content,c_width/2,barrage.height);    if(barrage.left==undefined||barrage.left==null){        barrage.left=c.width;    }else{        if(barrage.left<-200){            ctx.fillText("",c_width/2,barrage.height);                            barrage=null;            //ctx.restore();            ctx.clearRect(0,0,c_width,c_height);                }else{            barrage.left=barrage.left-6;        }    }}

首先将画布的基点移动到画布的中心,需要注意的是这时候相对与生成了一张新的画布,原来画布的clearRect()方法已经不适用与这张画布了。然后再设置文字对齐为居中对齐,设置文字样式,填充文字。因为弹幕是静止的所以不需要进行缓动,但是静止弹幕也是会消失的,需要设置一个标志位来使他定时消失。在这里为了不占用额外的属性,我们直接使用left属性作为标志位,同样进行left属性的递减,但不把递减反映到画布中,当left达到阈值,则使用ctx.clearRect()方法将弹幕清除。这样就实现了静止弹幕的处理。

其他关于颜色,样式的设置有一定基础的人应该是很容易掌握的在这里就不多介绍了,自己看可运行代码部分理解一下就好。

总结

 这个项目主要是使用了canvas进行文字绘制以及实现文字的缓动动画,主要用到的方法有

canvasDom.getContext()canvas.save()/canvas.restore()canvas.clearRect()canvas.moveTo()

原来我对与save()和restore()是不能理解的,现在我算是有一点理解了,当你更改了画布状态,现在的画布就已经不是原来的画布,所以在修改画布状态之前先把画布状态保存,切换画布状态,完成工作之后,恢复为原来的画布状态继续工作。像我处理静态弹幕的时候,把画布的基点改变了,那么原来画布的清除方法就不再适用于当前画布,只有在当前画布中自己使用另外的清除方法。然后再恢复到原来的画布。

可运行代码

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <meta http-equiv="X-UA-Compatible" content="ie=edge">    <title>Document</title></head><style type="text/css">    .pickdiv{        width: 30px;        height: 30px;        cursor: pointer;        border: 2px solid gray;        display: inline-block;    }    #white{        background: white;    }    #red{        background:#ff6666;    }    #yellow{        background:#ffff00;    }    #blue{        background:#333399;    }    #green{        background:#339933;    }    #cv_video{        position: absolute;        z-index: 1;    }    #barrageplayer{        position: relative;        display: block;        width: 900px;        height: 500px;    }    #v_video{        position: absolute;        width: 100%;        height: 100%;        z-index: 0;    }</style><body>    <div id="barrageplayer">        <canvas id="cv_video" width="900px" height="450px"></canvas>        <video id="v_video" src="test.MP4" controls type="video/mp4"></video>    </div>    <div id="barrageinput">        <div>            <input type="text" id="smsg" placeholder="请输入弹幕内容"/>            <button id="send"> 发送</button>        </div>        <div id="colorpick">            <div class="pickdiv" id="white"></div>            <div class="pickdiv" id="red"></div>            <div class="pickdiv" id="yellow"></div>            <div class="pickdiv" id="blue"></div>            <div class="pickdiv" id="green"></div>        </div>        <div id="typepick">            <input type="radio" name="type" value="default">默认            <input type="radio" name="type" value="static top">静止顶部             <input type="radio" name="type" value="static bottom">静止底部        </div>        <div id="speedpick">            <input type="radio" name="speed" value="1">1X            <input type="radio" name="speed" value="2">2X            <input type="radio" name="speed" value="3">3X        </div>        <div id="stylepick"></div>    </div>    <script>        var c=document.getElementById("cv_video");        var typeDom=document.getElementsByName("type");        var speedDom=document.getElementsByName("speed");        var colorpick=document.getElementById("colorpick");        var smsg=document.getElementById("smsg");        var color="#white";        var speed=1;        var type="default";        var msgs=[];        //获取画布大小        var c_height=c.height;        var c_width=c.width;        //获取画布        ctx=c.getContext("2d");        ctx.font="25px DengXian";        //处理颜色选择        colorpick.addEventListener('click',function(event){            switch(event.target.id){                case "white":                    color="white";                    break;                case "red":                    color="#ff6666";                    break;                case "yellow":                    color="#ffff00";                    break;                case "green":                    color="#339933";                    break;                case "blue":                    color="#333399";                    break;            }        })        //处理发送弹幕        document.getElementById("send").onclick=function(){            var text=smsg.value;            for(var i=0;i<typeDom.length;i++){                if(typeDom[i].checked){                    type=typeDom[i].value;                    break;                }            }            for(var i=0;i<speedDom.length;i++){                if(speedDom[i].checked){                    speed=2*parseInt(speedDom[i].value);                    break;                }            }            var tempBarrage=new Barrage(text,color,type,speed);            msgs.push(tempBarrage);        }        //        //弹幕功能部分代码        //        //弹幕对象        function Barrage(content,color,type,speed){            this.content=content;            this.color=color;            this.type=type;            this.speed=speed;            if(this.type=="default"){                this.height=parseInt(Math.random()*c_height)+10;            }else if (this.type=="static top"){                this.height=parseInt((c_height/2)-Math.random()*c_height/2)+10;            }else if (this.type=="static bottom"){                this.height=parseInt((c_height/2)+Math.random()*c_height/2)+10;            }            if(typeof this.move!="function"){                Barrage.prototype.move=function(){                    if(this.type=="default"){                        this.left=this.left-this.speed;                    }                }            }        }        //循环擦写画布实现动画效果        setInterval(function(){            ctx.clearRect(0,0,c_width,c_height);            ctx.save();            for(var i=0;i<msgs.length;i++){                if(msgs[i]!=null){                    if(msgs[i].type=="default"){                        handleDefault(msgs[i]);                    }else{                        handleStatic(msgs[i]);                    }                }            }        },20)    //处理默认弹幕样式    function handleDefault(barrage){        if(barrage.left==undefined||barrage.left==null){            barrage.left=c.width;        }else{            if(barrage.left<-200){                barrage=null;            }else{                barrage.move()                ctx.fillStyle=barrage.color;                ctx.fillText(barrage.content,barrage.left,barrage.height)                ctx.restore();            }        }      }    //处理静止弹幕样式    function handleStatic(barrage){        ctx.moveTo(c_width/2,barrage.height);        ctx.textAlign="center";        ctx.fillStyle=barrage.color;        ctx.fillText(barrage.content,c_width/2,barrage.height);        if(barrage.left==undefined||barrage.left==null){            barrage.left=c.width;        }else{            if(barrage.left<-200){                ctx.fillText("",c_width/2,barrage.height);                                barrage=null;                //ctx.restore();                ctx.clearRect(0,0,c_width,c_height);                    }else{                barrage.left=barrage.left-6;            }        }    }    </script></body></html>

以上所述是小编给大家介绍的HTML使用canvas实现弹幕功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

  • 相关标签:HTML/Xhtml教程
  • 本文发布HTML5中文学习网 ,转载请注明出处,感谢您!
  • 相关文章


  • Asp.net Core与类库读取配置文件信息的方法_实用技巧
  • asp.net在Repeater嵌套的Repeater中使用复选框详解_实用技巧
  • 利用IIS调试ASP.NET网站程序的完整步骤_实用技巧
  • Asp.Net Core轻松学习系列之配置文件_实用技巧
  • ASP.NET 页生命周期概述(小结)_实用技巧
  • 详解ASP.NET Core WebApi 返回统一格式参数_实用技巧
  • 2018年网络流行语有哪些?2018年十大网络流行语盘点
  • 华为首席财务官孟晚舟被暂扣 深圳市政府要求加方立即放人!
  • 微信支付勒索病毒制造者被锁定 网友:史上最蠢的黑客!
  • 英国电信宣布从核心设备中删除华为产品 5G不采用
  • 独孤九贱(4)_PHP视频教程

    江湖传言:PHP是世界上最好的编程语言。真的是这样吗?这个梗究竟是从哪来的?学会本课程,你就会明白了。 PHP中文网出品的PHP入门系统教学视频,完全从初学者的角度出发,绝不玩虚的,一切以实用、有用...

    独孤九贱(5)_ThinkPHP5视频教程

    ThinkPHP是国内最流行的中文PHP开发框架,也是您Web项目的最佳选择。《php.cn独孤九贱(5)-ThinkPHP5视频教程》课程以ThinkPHP5最新版本为例,从最基本的框架常识开始,将...

    独孤九贱(1)_HTML5视频教程

    《php.cn原创html5视频教程》课程特色:php中文网原创幽默段子系列课程,以恶搞,段子为主题风格的php视频教程!轻松的教学风格,简短的教学模式,让同学们在不知不觉中,学会了HTML知识。 ...

    ThinkPHP5实战之[教学管理系统]

    本套教程,以一个真实的学校教学管理系统为案例,手把手教会您如何在一张白纸上,从零开始,一步一步的用ThinkPHP5框架快速开发出一个商业项目。

    PHP入门视频教程之一周学会PHP

    所有计算机语言的学习都要从基础开始,《PHP入门视频教程之一周学会PHP》不仅是PHP的基础部分更主要的是PHP语言的核心技术,是学习PHP必须掌握的内容,任何PHP项目的实现都离不开这部分的内容,通...

    作者信息

    kevin

    永远在学习的路上!

    相关教程

  • javascript初级视频教程 javascript初级视频教程
  • jquery 基础视频教程 jquery 基础视频教程
  • javascript三级联动视频教程 javascript三级联动视频教程
  • 独孤九贱(3)_JavaScript视频教程 独孤九贱(3)_JavaScript视频教程
  • 独孤九贱(6)_jQuery视频教程 独孤九贱(6)_jQuery视频教程
  • 热门教程