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 よりも強力なフロントエンド フレームワーク

推薦する

Expressはログイン認証を実装

この記事では、ログイン認証を実装するためのExpressの具体的なコードを例として紹介します。具体的...

MySQLの一般的なバックアップコマンドとシェルバックアップスクリプトの共有

複数のデータベースをバックアップするには、次のコマンドを使用できます。 mysqldump -uro...

Ubuntu 20.04 LTS で Java 開発環境を構成する

Java開発キットjdkをダウンロードするJDK のダウンロード アドレスはhttp://www.o...

反応自動構築ルーティングの実装

目次順序1. 集中ルーティング2. ファイルディレクトリ3. CompileRouterを作成する4...

Vueプロジェクトのパッケージ化の詳細な説明

目次1. 関連構成ケース1(使用ツールはvue-cil)ケース2(使用するツールはwebpack) ...

キャンバスはスクラッチカード効果を描画します

この記事では、キャンバスでスクラッチカード効果を描画するための具体的なコードを参考までに共有します。...

Spring Boot のパッケージ化と Docker リポジトリへのアップロードの詳細な手順

重要な注意: この記事を読む前に、Docker コンテナに関する知識と、一般的な Docker 操作...

入力テキストボックスの長さをコンテンツに応じて変更する方法

初め:コードをコピーコードは次のとおりです。 <input type="text&q...

mysql5.7.17 zip の解凍とインストールの詳細な手順

1. ダウンロードアドレスhttps://dev.mysql.com/downloads/mysql...

CSS を使用して波状のウォーターボール効果を実装するためのサンプルコード

今日は新しいCSS特殊効果、波型ウォーターボール効果を学びました。これもとても美しいです HTML:...

MySQLにおけるテーブルインデックスの定義方法と導入

概要インデックスは、テーブル内の 1 つ以上の列に基づいて DBMS によって特定の順序で作成される...

Node.js は、異なるリクエストパスに応じて異なるデータを返します。

目次1. 異なるリクエストパスに応じて異なるデータを返す方法を学びます。 2. 送信データ: データ...

MySQL 8.0.13 のダウンロードとインストールのチュートリアル(画像とテキスト付き)

MySQL は最もよく使用されるデータベースです。詳しく知るには、コンピュータにインストールする必...

geoip を使用して nginx で地域を制限する方法

このブログは仕事のメモです環境: nginx バージョン: nginx/1.14.0 Centos ...

Vueコンポーネントが相互に値を転送する方法の詳細な説明

目次概要1. 親コンポーネントが子コンポーネントに値を渡す2. 子コンポーネントが親コンポーネントに...