Home  >  Article  >  Web Front-end  >  How HTML uses canvas to implement barrage function

How HTML uses canvas to implement barrage function

墨辰丷
墨辰丷Original
2018-06-04 15:00:471944browse

This article mainly introduces how HTML uses canvas to implement the barrage function. Interested friends can refer to it. I hope it will be helpful to everyone.

Introduction

Recently, I needed to make a barrage player when I was doing a big job. I borrowed other people's source code and re-implemented one myself. The demonstration is as follows

The main functions are

Send barrage
Set barrage color, speed and type
Show barrage

Known defects:

Cannot be full screen

canvas is not adaptive
No custom player control
No corresponding barrages are displayed according to the playback time
Barrages cannot be hovered
Already Known defects will be improved in the future. The source code of barrage players that can be found on the Internet generally only makes rolling barrage and not static barrage. Here I specially added the implementation of static barrage.

Canvas draws text and text scrolling effect

The core of the entire player is to draw text and animate text scrolling. For text in canvas There is no good animation support, so you can only realize it by yourself. The idea of ​​​​implementing it is to constantly clear the screen and then rewrite the text. When the frequency of screen clearing and rewriting reaches 24fps, the animation will be smooth.

First add the video video tag and canvas tag to the HTML file

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

Set the position style of the canvas tag to position:absolute and then The video and canvas overlap, and it looks like a barrage player. Then add barrage-related content to the canvas. First, obtain the relevant information of the canvas and set the font size and font style of the canvas.

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

Constructed barrage object initialization Various parameters, including content, color, motion type and speed, are defined. The move() method is defined to control the easing of the barrage. Each time the move() method is launched, it scrolls to the left by one pixel of unit speed.
After the construction of the barrage object is completed, enter the theme and animation production, directly enter the code

//循环擦写画布实现动画效果
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)

Erase is executed every 20ms, ctx.clearRect (0,0,c_width,c_height); is to clear the entire current canvas, then use ctx.save() to save the current canvas, and then traverse the barrage list (msgs is the barrage list, when each barrage is sent The barrage instance will be added to the list), and then processed separately according to the default style barrage or the static style barrage. If it is a barrage of the default style, it will be processed according to the following method

//处理默认弹幕样式
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();
        }
    }  
}

First of all, if the barrage instance does not set the left attribute, it will The width of the canvas is assigned to it. If the barrage instance has exited the canvas, it is set to null to save memory. Otherwise, the move() method of the barrage instance is called to change the value of the left attribute, and then the color of the text is set. First-level writing New text, restore canvas. This completes one frame of animation.

The implementation method for static barrage is as follows

//处理静止弹幕样式
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 move the base point of the canvas to the center of the canvas. It should be noted that at this time Compared with a new canvas, the clearRect() method of the original canvas is no longer applicable to this canvas. Then set the text alignment to center alignment, set the text style, and fill the text. Because the barrage is stationary, there is no need to slow it down, but static barrages will also disappear. You need to set a flag to make them disappear regularly. In order not to occupy additional attributes here, we directly use the left attribute as the flag. We also decrement the left attribute, but do not reflect the decrease in the canvas. When left reaches the threshold, use the ctx.clearRect() method to clear the barrage. Clear. In this way, the processing of static barrage is realized.

Other people who have a certain foundation in setting colors and styles should be able to easily master it. I won’t introduce it here. Just look at the runnable code and understand it yourself.

Summary

This project mainly uses canvas for text drawing and text easing animation. The main methods used are

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

Originally I couldn’t understand save() and restore(), but now I have a little understanding. When you change the canvas state, now The canvas is no longer the original canvas, so before modifying the canvas state, save the canvas state and switch the canvas state. After completing the work, return to the original canvas state and continue working. For example, when I deal with static barrages and change the base point of the canvas, the original canvas clearing method no longer applies to the current canvas, and I can only use another clearing method in the current canvas. Then return 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">
    .pickp{
        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>
    <p id="barrageplayer">
        <canvas id="cv_video" width="900px" height="450px"></canvas>
        <video id="v_video" src="test.MP4" controls type="video/mp4"></video>
    </p>
    <p id="barrageinput">
        <p>
            <input type="text" id="smsg" placeholder="请输入弹幕内容"/>
            <button id="send"> 发送</button>
        </p>
        <p id="colorpick">
            <p class="pickp" id="white"></p>
            <p class="pickp" id="red"></p>
            <p class="pickp" id="yellow"></p>
            <p class="pickp" id="blue"></p>
            <p class="pickp" id="green"></p>
        </p>
        <p 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">静止底部
        </p>
        <p 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
        </p>
        <p id="stylepick"></p>
    </p>
    <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(&#39;click&#39;,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>

Summary: The above is the entire content of this article, I hope it will be helpful to everyone's learning.

related suggestion:

H5 Canvas use case detailed explanation

How to use Vue canvas to implement the mobile handwriting pad function

js canvasImplement the sliding puzzle verification code function

The above is the detailed content of How HTML uses canvas to implement barrage function. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:5 types of spaces in HTMLNext article:5 types of spaces in HTML