HTMLはキャンバスを使用して箇条書きスクリーン機能を実装します

HTMLはキャンバスを使用して箇条書きスクリーン機能を実装します

導入

最近、大きな課題をこなす際に、弾幕プレイヤーを作る必要がありました。他の人のソースコードを借りて自分で再実装しました。デモは次のようになります

主な機能は

弾幕を送る 弾幕の色、速度、種類を設定する 弾幕を表示する

既知の欠陥:

全画面表示できません

キャンバスが適応せず、プレイヤーコントロールがカスタマイズされず、再生時間に応じて対応する弾幕が表示されず、弾幕をホバーできません。既知の欠陥は今後改善される予定です。インターネット上で見つかる弾幕プレイヤーのソースコードには、一般的にスクロール弾幕しかなく、静的弾幕はありません。ここでは、静的弾幕の実装を特別に追加しました。

キャンバスはテキストとテキストスクロール効果を描画します

プレーヤー全体の核となるのは、テキストを描画し、テキストのスクロールアニメーションをすることです。キャンバスにはテキストのアニメーションをサポートする良いツールがないので、自分で実装するしかありません。アイデアは、継続的に画面をクリアしてテキストを書き換えることです。画面のクリアと書き換えの頻度が 24fps に達すると、スムーズなアニメーションになります。

まず、HTMLファイルにビデオタグとキャンバスタグを追加します。

<div id="弾幕プレイヤー">
    <キャンバスid="cv_video" 幅="900ピクセル" 高さ="450ピクセル"></キャンバス>
    <ビデオ id="v_video" src="test.MP4" コントロール タイプ="video/mp4"></ビデオ>
</div>

キャンバス タグの位置スタイルを 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";
キャンバス情報が取得され、設定されました。料理が上手でも、米がなければ料理はできません。次に、弾幕オブジェクトを構築する必要があります。使用する構築モードは、動的プロトタイプ モードです // 弾幕オブジェクト関数 Barrage (content, color, type, speed) {
    this.content=コンテンツ;
    色
    タイプ
    this.speed=速度;
    if(this.type=="default"){
        this.height=parseInt(Math.random()*c_height)+10;
    }それ以外の場合 (this.type=="static top"){
        this.height=parseInt((c_height/2)-Math.random()*c_height/2)+10;
    }それ以外の場合 (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() メソッドがトリガーされるたびに、単位速度で 1 ピクセル左にスクロールします。
弾幕オブジェクトが構築された後、テーマとアニメーション制作に入り、直接コードを入れます

//アニメーション効果を実現するためにキャンバスをループ消去する setInterval(function(){
    ctx.clearRect(0,0,c_width,c_height);
    ctx.save();
    for(var i=0;i<msgs.length;i++){
        if(メッセージ[i]!=null){
            if(msgs[i].type=="default"){
                handleDefault(メッセージ[i]);
            }それ以外{
                handleStatic(メッセージ[i]);
           }
        }
    }
},20)

消去は 20 ミリ秒ごとに実行されます。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;
    }それ以外{
         if(barrage.left<-200){
            弾幕=null;
        }それ以外{
            弾幕移動()
            ctx.fillStyle=弾幕.color;
            ctx.fillText(barrage.content,barrage.left,barrage.height)
            ctx.restore();
        }
    }  
}

まず、箇条書きメッセージ インスタンスに left 属性が設定されていない場合は、キャンバスの幅を割り当てます。箇条書きメッセージ インスタンスがキャンバスから出ている場合は、メモリを節約するために null に設定します。それ以外の場合は、箇条書きメッセージ インスタンスの move() メソッドを呼び出して left 属性の値を変更し、テキストの色を設定し、新しいテキストを書き込んで、キャンバスを復元します。これでアニメーションの 1 フレームが完成します。

静的弾幕の実装方法は次のとおりです

//静的な弾幕スタイルを処理する function handleStatic(barrage){
    ctx.moveTo(c_width/2,barrage.height);
    ctx.textAlign="中央";
    ctx.fillStyle=弾幕.color;
    ctx.fillText(barrage.content,c_width/2,barrage.height);
    if(barrage.left==undefined||barrage.left==null){
        barrage.left=c.width;
    }それ以外{
        if(barrage.left<-200){
            ctx.fillText("",c_width/2,barrage.height);                
            弾幕=null;
            //ctx.restore();
            ctx.clearRect(0,0,c_width,c_height);        
        }それ以外{
            barrage.left=barrage.left-6;
        }
    }
}

まず、キャンバスの基点をキャンバスの中心に移動します。このとき新しいキャンバスが生成され、元のキャンバスの clearRect() メソッドはこのキャンバスには適用できなくなることに注意してください。次に、テキストの配置を中央に設定し、テキスト スタイルを設定して、テキストを入力します。弾幕は静的なので緩和の必要はありません。ただし、静的弾幕も消えてしまうので、一定時間で消えるようにフラグを立てる必要があります。ここで余分な属性を占有しないように、left 属性を直接フラグとして使用し、left 属性を減分しますが、キャンバスに減分を反映しません。left がしきい値に達すると、ctx.clearRect() メソッドを使用して箇条書きコメントをクリアします。これにより、静的弾幕の処理が実現されます。

色やスタイルに関するその他の設定については、ある程度の基礎知識がある人であれば簡単に使いこなせるはずなので、ここでは詳しく紹介しません。実行コードの部分だけ読んで理解してください。

要約する

このプロジェクトでは、主にキャンバスを使用してテキストを描画し、テキストのスローアニメーションを実現します。使用される主な方法は、

キャンバスDom.getContext()
キャンバス.保存()/キャンバス.復元()
キャンバス.clearRect()
キャンバスを移動します()

以前は save() と restore() がよく分かりませんでしたが、今は少し理解できるようになりました。キャンバスの状態を変更すると、現在のキャンバスは元のキャンバスではなくなるため、変更前にキャンバスの状態を保存し、キャンバスの状態を切り替え、作業が完了したら元のキャンバスの状態に戻して作業を続けます。たとえば、静的弾幕を扱う場合、キャンバスの基点を変更します。すると、元のキャンバスのクリア方法は現在のキャンバスには適用できなくなります。現在のキャンバスでは別のクリア方法を使用する必要があります。その後、元のキャンバスに戻します。

実行可能なコード

<!DOCTYPE html>
<html lang="ja">
<ヘッド>
    <メタ文字セット="UTF-8">
    <meta name="viewport" content="width=デバイス幅、初期スケール=1.0">
    <meta http-equiv="X-UA-compatible" content="ie=edge">
    <title>ドキュメント</title>
</head>
<スタイル タイプ="text/css">
    .pickdiv{
        幅: 30ピクセル;
        高さ: 30px;
        カーソル: ポインタ;
        境界線: 2px の灰色
        表示: インラインブロック;
    }
    #白{
        背景: 白;
    }
    #赤{
        背景:#ff6666;
    }
    #黄色{
        背景:#ffff00;
    }
    #青{
        背景:#333399;
    }
    #緑{
        背景:#339933;
    }
    #cv_ビデオ{
        位置: 絶対;
        zインデックス: 1;
    }
    #弾幕プレイヤー{
        位置: 相対的;
        表示: ブロック;
        幅: 900ピクセル;
        高さ: 500px;
    }
    #v_ビデオ{
        位置: 絶対;
        幅: 100%;
        高さ: 100%;
        zインデックス: 0;
    }
</スタイル>
<本文>
    <div id="弾幕プレイヤー">
        <キャンバスid="cv_video" 幅="900ピクセル" 高さ="450ピクセル"></キャンバス>
        <ビデオ id="v_video" src="test.MP4" コントロール タイプ="video/mp4"></ビデオ>
    </div>
    <div id="弾幕入力">
        <div>
            <input type="text" id="smsg" placeholder="箇条書きコメントの内容を入力してください"/>
            <button id="send">送信</button>
        </div>
        <div id="カラーピック">
            <div class="pickdiv" id="white"></div>
            <div class="pickdiv" id="red"></div>
            <div class="pickdiv" id="黄色"></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="スピードピック">
            <input type="radio" name="speed" value="1">1倍速
            <input type="radio" name="speed" value="2">2倍速
            <input type="radio" name="speed" value="3">3倍速
        </div>
        <div id="stylepick"></div>
    </div>
    <スクリプト>
        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 速度 = 1;
        var type="default";
        var メッセージ = [];
        //キャンバスのサイズを取得します。var c_height=c.height;
        var c_width = c.width;
        //キャンバスを取得します ctx=c.getContext("2d");
        ctx.font="25px 鄧賢";
        //色選択の処理 colorpick.addEventListener('click',function(event){
            スイッチ(イベント.ターゲット.id){
                ケース「白」:
                    色="白";
                    壊す;
                ケース「赤」:
                    カラー = "#ff6666";
                    壊す;
                ケース「黄色」:
                    カラー="#ffff00";
                    壊す;
                ケース「緑」:
                    カラー = "#339933";
                    壊す;
                ケース「青」:
                    カラー = "#333399";
                    壊す;
            }
        })
        //送信箇条書き画面の処理 document.getElementById("send").onclick=function(){
            var text=smsg.value;
            for(var i=0;i<typeDom.length;i++){
                (typeDom[i].checked)の場合{
                    タイプ=typeDom[i].値;
                    壊す;
                }
            }
            for(var i=0;i<speedDom.length;i++){
                speedDom[i]がチェックされている場合
                    速度=2*parseInt(speedDom[i].value);
                    壊す;
                }
            }
            var tempBarrage = new Barrage(テキスト、色、タイプ、速度);
            msgs.push(tempBarrage);
        }
        //
        // 連射機能コードの一部 //
        //Barrage オブジェクト function Barrage(content,color,type,speed){
            this.content=コンテンツ;
            this.color=色;
            タイプ
            this.speed=速度;
            if(this.type=="default"){
                this.height=parseInt(Math.random()*c_height)+10;
            }それ以外の場合 (this.type=="static top"){
                this.height=parseInt((c_height/2)-Math.random()*c_height/2)+10;
            }それ以外の場合 (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(メッセージ[i]!=null){
                    if(msgs[i].type=="default"){
                        handleDefault(メッセージ[i]);
                    }それ以外{
                        handleStatic(メッセージ[i]);
                    }
                }
            }
        },20)
    //デフォルトの弾幕スタイルを処理する function handleDefault(barrage){
        if(barrage.left==undefined||barrage.left==null){
            barrage.left=c.width;
        }それ以外{
            if(barrage.left<-200){
                弾幕=null;
            }それ以外{
                弾幕移動()
                ctx.fillStyle=弾幕.color;
                ctx.fillText(barrage.content,barrage.left,barrage.height)
                ctx.restore();
            }
        }  
    }
    //静的な弾幕スタイルを処理する function handleStatic(barrage){
        ctx.moveTo(c_width/2,barrage.height);
        ctx.textAlign="中央";
        ctx.fillStyle=弾幕.color;
        ctx.fillText(barrage.content,c_width/2,barrage.height);
        if(barrage.left==undefined||barrage.left==null){
            barrage.left=c.width;
        }それ以外{
            if(barrage.left<-200){
                ctx.fillText("",c_width/2,barrage.height);                
                弾幕=null;
                //ctx.restore();
                ctx.clearRect(0,0,c_width,c_height);        
            }それ以外{
                barrage.left=barrage.left-6;
            }
        }
    }
    </スクリプト>
</本文>
</html>

以上は、HTML でキャンバスを使用して弾幕機能を実現する方法についてご紹介しました。お役に立てれば幸いです。ご質問がある場合は、メッセージを残してください。すぐに返信いたします。また、123WORDPRESS.COM ウェブサイトをサポートしてくださっている皆様にも感謝申し上げます。

<<:  CSS3を使用してボタンホバーフラッシュダイナミック特殊効果コードを実装する

>>:  ツールキット: Bootstrap よりも強力なフロントエンド フレームワーク

推薦する

div+cssとウェブ標準ページの利点

div 要素は、HTML ドキュメント内のブロックレベル コンテンツの構造と背景を提供するために使用...

Docker を使用して静的 Web サイト アプリケーションを作成する (複数の方法)

静的ウェブサイトをホストできるサーバーは数多くあります。この記事では、nginx、apache、to...

MySQL EXPLAIN出力列の詳細な説明

1. はじめにEXPLAIN ステートメントは、MySQL がステートメントを実行する方法に関する情...

モバイルデバイスにおける適応レイアウトの問題に関する簡単な説明 (レスポンシブ、rem/em、Js ダイナミクス)

3G の普及により、携帯電話を使ってインターネットにアクセスする人が増えています。モバイル デバイ...

Docker で LNMP 環境を素早く構築する方法 (最新)

序文ヒント: ここで、この記事に記録するおおよその内容を追加できます。例えば、人工知能の継続的な発展...

CSS フィルターを使用してマウスオーバー効果を記述する例

CSSフィルターを使用してマウスオーバー効果を記述する <div class="fi...

Dockeにredisをインストールする方法

1. redisイメージを検索する docker 検索 redis 2. Redisイメージをダウン...

PostgreSQL正規表現の一般的な機能の概要

PostgreSQL正規表現の一般的な機能の概要正規表現は、複雑なデータ処理を必要とするプログラムに...

Ubuntu サーバーで MySQL を設定し、リモート接続を実装する方法

サーバー: Ubuntu Server 16.04 LSSクライアント: Ubuntu 16.04 ...

Linux での感嘆符コマンド (!) の使用の概要

序文最近、弊社では mbp の設定をしており、ssh を使うことが多くなりました。複雑なコマンドを書...

Windows 10 + mysql 8.0.11 zipインストールチュートリアルの詳細

準備する: MySQL 8.0 Windows zip パッケージのダウンロード アドレス: htt...

CSSで特殊なグラフィックを描く方法

1. 三角形境界線の設定 コード: 幅: 300ピクセル; 高さ: 300px; 背景: 赤; 境界...

Docker で lnmp をデプロイする詳細な手順

目次Centosイメージを取得するCentos ベースの nginx コンテナを生成するCentos...

2017 最新バージョンの Windows インストール MySQL チュートリアル

1. まず、MySQL の公式サイトから最新バージョンの MySQL をダウンロードします。リンクを...

MySQLコンテナ間のレプリケーション構成例の詳細な説明

背景先週、会社で MySQL レプリケーションのトレーニングを受けたので、今週末は学んだことを実践す...