HTML使⽤canvas实现弹幕功能
简介
最近在做⼤作业的时候需要做⼀个弹幕播放器。借鉴了⼀下别⼈的源码⾃⼰重新实现了⼀个,演⽰如下
主要的功能有
发送弹幕
设置弹幕的颜⾊,速度和类型
显⽰弹幕
已知缺陷:
不能全屏
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 ElementById("cv_video");
//获取画布⼤⼩
var c_height=c.height;
var c_width=c.width;
//获取画布
Context("2d");
//设置字体样式
ctx.font="25px DengXian";
画布信息已经获取和设置,巧妇难为⽆⽶之炊,接着我们就要构造弹幕对象,使⽤的构造模式是动态原型模式
canvas动画//弹幕对象
function Barrage(content,color,type,speed){
this.speed=speed;
pe=="default"){
this.height=parseInt(Math.random()*c_height)+10;
}else if (pe=="static top"){
this.height=parseInt((c_height/2)-Math.random()*c_height/2)+10;
}else if (pe=="static bottom"){
this.height=parseInt((c_height/2)+Math.random()*c_height/2)+10;
}
if(ve!="function"){
ve=function(){
pe=="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{
ctx.lor;
ctx.t,barrage.left,barrage.height)
}
}
}
⾸先如果弹幕实例没有设置left属性则将画布的宽度赋予它,如果弹幕实例已经退出画布则将其置null以节省内存,否则的话就调⽤弹幕实例的move()⽅法改变left属性的值,然后设置⽂字的颜⾊,⼀级写⼊新的⽂字,恢复画布。这样就完成了⼀帧动画。
对于静⽌弹幕的实现⽅法如下
//处理静⽌弹幕样式
function handleStatic(barrage){
ctx.lor;
ctx.t,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;
//store();
ctx.clearRect(0,0,c_width,c_height);
}else{
barrage.left=barrage.left-6;
}
}
}
⾸先将画布的基点移动到画布的中⼼,需要注意的是这时候相对与⽣成了⼀张新的画布,原来画布的clearRect()⽅法已经不适⽤与这张画布了。然后再设置⽂字对齐为居中对齐,设置⽂字样式,填充⽂字。因为弹幕是静⽌的所以不需要进⾏缓动,但是静⽌弹幕也是会消失的,需要设置⼀个标志位来使他定时消失。在这⾥为了不占⽤额外的属性,我们直接使⽤left属性作为标志位,同样进⾏left属性的递减,但不把递减反映到画布中,当left达到阈值,则使⽤ctx.clearRect()⽅法将弹幕清除。这样就实现了静⽌弹幕的处理。
其他关于颜⾊,样式的设置有⼀定基础的⼈应该是很容易掌握的在这⾥就不多介绍了,⾃⼰看可运⾏代码部分理解⼀下就好。
总结
这个项⽬主要是使⽤了canvas进⾏⽂字绘制以及实现⽂字的缓动动画,主要⽤到的⽅法有
canvas.save()/store()
canvas.clearRect()
原来我对与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 ElementById("cv_video");
var ElementsByName("type");
var ElementsByName("speed");
var ElementById("colorpick");
var ElementById("smsg");
var color="#white";
var speed=1;
var type="default";
var msgs=[];
//获取画布⼤⼩
var c_height=c.height;
var c_width=c.width;
//获取画布
Context("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;
}
})
//处理发送弹幕
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.speed=speed;
pe=="default"){
this.height=parseInt(Math.random()*c_height)+10;
}else if (pe=="static top"){
this.height=parseInt((c_height/2)-Math.random()*c_height/2)+10;
}else if (pe=="static bottom"){
this.height=parseInt((c_height/2)+Math.random()*c_height/2)+10;
}
if(ve!="function"){
ve=function(){
pe=="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{
ctx.lor;
ctx.t,barrage.left,barrage.height)
}
}
}
//处理静⽌弹幕样式
function handleStatic(barrage){
ctx.lor;
ctx.t,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;
//store();
ctx.clearRect(0,0,c_width,c_height);
}else{
barrage.left=barrage.left-6;
}
}
}
</script>
</body>
</html>
以上所述是⼩编给⼤家介绍的HTML使⽤canvas实现弹幕功能,希望对⼤家有所帮助,如果⼤家有任何疑问请给我留⾔,⼩编会及时回复⼤家的。在此也⾮常感谢⼤家对⽹站的⽀持!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。