HTML应用canvas完成弹幕作用

简介

 近期在做手游大作业的情况下必须做1个弹幕播发器。效仿了1下他人的源代码自身再次完成了1个,演试以下

关键的作用有

推送弹幕
设定弹幕的色调,速率和种类
显示信息弹幕
 

已知缺点:

不可以全屏

canvas沒有做自融入
沒有自定播发器控制
沒有依据播发時间显示信息相应的弹幕
弹幕不可以完成悬停
已知的缺点之后会开展改善。在网上能寻找的弹幕播发器的源代码1般只做了翻转的弹幕而沒有做静止不动的弹幕,这里我特地再加了静止不动弹幕的完成。

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随后视頻和画布就重合在1起,看起来便是1个弹幕播发器了。随后为画布加上弹幕有关的內容,最先获得画布的有关信息内容和设定画布的字体样式尺寸和字体样式款式

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()方式来操纵弹幕的缓动,每考虑1次move()方式向左翻转1个企业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实行1次擦写,ctx.clearRect(0,0,c_width,c_height);是将整张当今的画布消除,随后应用ctx.save()将当今的画布储存,接着遍历弹幕目录(msgs是弹幕目录,当每推送1条弹幕都会将该弹幕案例加上到目录中),随后依照默认设置款式的弹幕還是静止不动款式的弹幕各自解决。假如是默认设置款式的弹幕可能依照下列的方式解决

//解决默认设置弹幕款式
function handleDefault(barrage){
    if(barrage.left==undefined||barrage.left==null){
        barrage.left=c.width;
    }else{
         if(barrage.left<⑵00){
            barrage=null;
        }else{
            barrage.move()
            ctx.fillStyle=barrage.color;
            ctx.fillText(barrage.content,barrage.left,barrage.height)
            ctx.restore();
        }
    }  
}

 

最先假如弹幕案例沒有设定left特性则将画布的宽度授予它,假如弹幕案例早已撤出画布则将其置null以节约运行内存,不然的话就启用弹幕案例的move()方式更改left特性的值,随后设定文本的色调,1级写入新的文本,修复画布。这样就进行了1帧动漫。

针对静止不动弹幕的完成方式以下

//解决静止不动弹幕款式
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<⑵00){
            ctx.fillText("",c_width/2,barrage.height);                
            barrage=null;
            //ctx.restore();
            ctx.clearRect(0,0,c_width,c_height);        
        }else{
            barrage.left=barrage.left⑹;
        }
    }
}

最先将画布的基点挪动到画布的管理中心,必须留意的是这时候候相对性与转化成了1张新的画布,原先画布的clearRect()方式早已不可用与这张画布了。随后再设定文本对齐为垂直居中对齐,设定文本款式,填充文本。由于弹幕是静止不动的因此不必须开展缓动,可是静止不动弹幕也是会消退的,必须设定1个标示位来使他定时执行消退。在这里以便不占有附加的特性,大家立即应用left特性做为标示位,一样开展left特性的下降,但不把下降反应到画布中,当left做到阀值,则应用ctx.clearRect()方式将弹幕消除。这样就完成了静止不动弹幕的解决。

别的有关色调,款式的设定有1定基本的人应当是很非常容易把握的在这里就很少详细介绍了,自身看可运作编码一部分了解1下就好。

总结

 这个新项目关键是应用了canvas开展文本绘图和完成文本的缓动动漫,关键用到的方式有

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

原先我对与save()和restore()是不可以了解的,如今我算是有1点了解了,当你变更了画布情况,如今的画布就早已并不是原先的画布,因此在改动画布情况以前先把画布情况储存,切换画布情况,进行工作中以后,修复为原先的画布情况再次工作中。像我解决静态数据弹幕的情况下,把画布的基点更改了,那末原先画布的消除方式就已不可用于当今画布,仅有在当今画布中自身应用此外的消除方式。随后再修复到原先的画布。

可运作编码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF⑻">
    <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<⑵00){
                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<⑵00){
                ctx.fillText("",c_width/2,barrage.height);                
                barrage=null;
                //ctx.restore();
                ctx.clearRect(0,0,c_width,c_height);        
            }else{
                barrage.left=barrage.left⑹;
            }
        }
    }
    </script>
</body>
</html>

以上所述是网编给大伙儿详细介绍的HTML应用canvas完成弹幕作用,期待对大伙儿有一定的协助,假如大伙儿有任何疑惑请给我留言,网编会立即回应大伙儿的。在此也十分谢谢大伙儿对脚本制作之家网站的适用!