HTML uses Canvas to realize bullet screen function

HTML uses canvas to realize bullet screen function

brief introduction

Recently, when doing big homework, we need to make a bullet screen player. Learn from other people's source code and re-implement it yourself. The demonstration is as follows.

The main functions are as follows:

  • Send the barrage
  • Setting the colour, speed and type of the barrage
  • Show the barrage

Known defects:

  • Not full screen
  • canvas does not adapt
  • No custom player controls
  • No corresponding barrage screen was displayed according to the playback time.
  • Bullet curtain can't hover

Known defects will be improved later. The source code of the ballistic screen player that can be found on the Internet generally only scrolls the ballistic screen but does not do the static one. Here I add the realization of the static one.

Canvas Drawing Text and Text Scrolling Effect

The core of the player is to draw text and make text scrolling animation. canvas has no good animation support for text, but can only be achieved by itself. The idea is to constantly clear the screen and rewrite the text. When the frequency of clear screen rewriting reaches 24fps, it is a smooth animation.

First add video Video Tags and canvas tags to HTML files

<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>

Set the location style of the canvas tag to position:absolute and the video and canvas overlap to look like a bullet screen player. Then add the content related to the canvas. First, get the information about the canvas and set the font size and font style of the canvas.

var c=document.getElementById("cv_video");
//Get the canvas size
var c_height=c.height;
var c_width=c.width;

//Getting Canvas
ctx=c.getContext("2d");

//Setting font style
ctx.font="25px DengXian";

Canvas information has been acquired and set up, and it is difficult for a skillful woman to cook without rice. Then we need to construct a bomb screen object, using the construction model is Dynamic prototype model

//Barrage target
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;
            }
        }
    }
}

The constructed projectile curtain object initializes various parameters, including content, color, motion type and speed. A move() method is defined to control the slowing of the projectile curtain. Each start of the move() method scrolls a unit speed pixel to the left.
After the construction of the bomb curtain object is completed, it enters into the theme, the production of animation, and the code directly.

//Cyclic Scrubbing Canvas to Realize Animation Effect
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)

Every 20ms, ctx.clearRect(0,0,c_width,c_height); clears the entire current canvas, saves the current canvas using ctx.save(), then traverses the list of barrages (msgs is the list of barrages, when each Barrage is sent, the instance of the barrage is added to the list), and then processes the barrage according to the default style or the static style respectively. If it is the default style, the barrage will be processed in the following way

//Processing default barrage style
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();
        }
    }  
}

Firstly, if the bullet-screen instance does not set the left attribute, the width of the canvas will be given to it. If the bullet-screen instance has exited the canvas, it will be null to save memory. Otherwise, the move() method of the bullet-screen instance will be called to change the value of the left attribute. Then the color of the text will be set, and the new text will be written at the first level to restore the canvas. This completes a frame of animation.

The method of realizing static Barrage is as follows.

//Dealing with Static Barrage Style
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;
        }
    }
}

First of all, move the base point of the canvas to the center of the canvas. It should be noted that at this time, a new canvas is relatively created. The clearRect() method of the original canvas is no longer applicable to the canvas. Then set the text alignment to center alignment, set the text style, fill the text. Because the barrage is stationary, there is no need to slow down, but the stationary barrage will disappear, so it needs to set a mark to make it disappear regularly. In order not to occupy additional attributes, we use the left attributes as markers directly, and also reduce the left attributes, but do not reflect the decline to the canvas. When the left reaches the threshold, we use the ctx.clearRect() method to clear the barrage. In this way, the static barrage can be processed.

Other color, style settings have a certain basis for people should be easy to grasp, here is not much introduced, you see the runnable code part to understand it.

summary

This project mainly uses canvas to draw text and realize slow motion animation of text. The main methods used are as follows:

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

I couldn't understand with save() and restore(), but now I have a little understanding. When you change the canvas state, the canvas is not the original canvas. So before you change the canvas state, save the canvas state, switch the canvas state, and resume the original canvas state after finishing the work. If I change the base point of the canvas when dealing with static barrage, then the original canvas removal method is no longer applicable to the current canvas, only in the current canvas I use another method of removal. Then it was restored to the original canvas.

Runnable code

<!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="Please enter the content of the barrage"/>
            <button id="send"> Send out</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">default
            <input type="radio" name="type" value="static top">Stationary top 
            <input type="radio" name="type" value="static bottom">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=[];

        //Get the canvas size
        var c_height=c.height;
        var c_width=c.width;

        //Getting Canvas
        ctx=c.getContext("2d");
        ctx.font="25px DengXian";

        //Processing color selection
        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;
            }
        })

        //Processing Send Barrage
        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);
        }


        //
        //Barrage Function Part Code
        //
        //Barrage target
        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;
                    }
                }
            }
        }

        //Cyclic Scrubbing Canvas to Realize Animation Effect
        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)

    //Processing default barrage style
    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();
            }
        }  
    }

    //Dealing with Static Barrage Style
    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>

Keywords: Attribute IE

Added by mrmachoman on Fri, 21 Jun 2019 01:34:08 +0300