最近、プロジェクトで弾幕機能をカスタマイズする必要があったため、キャンバスを使用してコンポーネントを開発してみました。いくつかのローエンドマシンでテストした結果、明らかな遅れはありませんでしたので、ご紹介します。
弾幕効果機能紹介使用
npm i vue-barrage
パラメータ設定
名前 | タイプ | デフォルト | 説明 |
---|---|---|---|
バリアリスト | 配列 | [] | 弾幕データ |
スピード | 番号 | 4 | 弾幕のスクロール速度 |
ループ | ブール値 | 真実 | ループスクロールするかどうか |
チャンネル | 番号 | 2 | 弾幕トラックの数 |
htmlスタイル
<テンプレート> <div class=barrage-container> <div class=container :style={height: barrageHeight/2+'px'}> <canvas id=canvas ref=canvas :width=barrageWidth :height=barrageHeight :style= {'width': barrageWidth/2 + 'px','height': barrageHeight/2 + 'px'}/> </div> </div></template>js実装
データソースを聞く
watch: { barrageList (val) { if (val.length !== 0) { this.initData() // データ初期化 this.render() // レンダリング開始} }}
データの初期化
barrageArray
は、デフォルトの弾幕リストや新しい弾幕アイテムなどの弾幕データを保存するために使用されます。
/** * データの初期化*/initData () { for (let i = 0; i < this.barrageList.length; i++) { // ここでは 40 文字のみが表示されます let content = this.barrageList[i]。長さ > 40 ? `${this.barrageList[i].content.substring(0, 40)}...` : this.barrageList[i].content this.pushMessage(content, this.barrageList[i].color) }},/** * データを追加* @param content * @param color */pushMessage (content, color) { let Position = this.getPosition() / / 滑走路の位置を決定します let x = this.barrageWidth // 初期位置 let offsetWidth = 0 for (let i = 0, len = this.barrageArray.length; i < len; i++) { let item = this.barrageArray[i] if (position === item.position) { // 同じトラック上にある場合は後ろに移動 offsetWidth += Math.floor(this.ctx.measureText( item.content) .width * 3 + 60) } } this.barrageArray.push({ content: content, // 弾幕コンテンツ x: x + offsetWidth, //各コメントの初期位置を決定しますoriginX: x + offsetWidth, // ループ中に使用できるようにコメントの現在位置を保存しますposition:position, width: this.ctx.measureText(content).width * 3, / / キャンバス描画コンテンツの幅 color: color this.getColor() // カスタム カラー })},
初期化データで処理する必要があるのは、 canvas
描画するときに使用できるように、現在の弾幕の軌跡、位置、および幅を計算することです。
canvas
を描く
/** * Render*/render () { this.ctx.clearRect(0, 0, this.barrageWidth, this.barrageHeight) this.ctx.font = '30px Microsoft YaHei' this.draw() window.requestAnimationFrame(this .render) // 16.6 ミリ秒ごとにレンダリングします。setInterval を使用すると、ローエンド モデルでは少し遅れます。},/** *テキストと背景の描画を開始*/draw () { for (let i = 0, len = this.barrageArray.length; i < len; i++) { let barrage = this.barrageArray[i] try { barrage.x -= this .speed if (barrage.x < -barrage.width - 100) { // ここで弾幕が消える時間を求める if (i === this.barrageArray.length - 1) { // 最後の弾幕が消えた場合の判定ロジック if (!this.loop) { // ループでない場合は描画をキャンセルしてループかどうかを判定し、ループなしで cancelAnimationFrame を実行 cancelAnimationFrame(this.render) return } if (this.addArray .length !== 0) { // ここで弾幕を追加するロジックを決定します this.barrageArray = this.barrageArray.concat(this.addArray) this.addArray = [] } for (let j = 0; j < this.barrageArray.length; j++) { // 各弾幕に x の初期値を与える this.barrageArray[j].x = this.barrageArray[j].originX } } if (barrage.x <= 2 * document.body.clientWidth + barrage.width) { // いつ描画を開始するかを決定します。そうしないと、弾幕のスクロールが停止します。 //背景を描画します this.drawRoundRect(this.ctx, barrage.x - 15, barrage.position - 30, barrage.width + 30, 40, 20, `rgba(0,0,0,0.75)`) // 背景を描画しますテキスト this .ctx.fillStyle = `${barrage.color}` this.ctx.fillText(barrage.content, barrage.x, barrage.position) } } catch (e) { console.log(e) } }},
ここでキャンセルのタイミング、弾幕の描画開始の判断、弾幕の消滅のタイミングなどの描画ロジックを判断します。
その他の機能
/** * テキストの位置を取得します * pathWayIndex を使用して各弾幕が配置されているトラックを確認します * 上部からの距離を返します * @TODO これは、各トラックの距離に基づいて次の弾幕の位置を決定するように最適化することもできます*/ getPosition () { let range = this.channels let top = (this.pathWayIndex % range) * 50 + 40 this.pathWayIndex++ return top},/** * ランダムな色を取得します*/getColor () { return '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).slice(-6);},/** * 角丸長方形を描画します* @ param context * @param x * @param y * @param width * @param height * @param radius * @param color */drawRoundRect (context, x, y, 幅, 高さ, 半径, カラー) { context.beginPath() context.fillStyle = color context.arc(x + 半径, y + 半径, 半径, Math.PI, Math.PI * 3 / 2) context.lineTo (幅 - 半径 + x, y) context.arc(幅 - 半径 + x, 半径 + y, 半径, Math.PI * 3 / 2, Math.PI * 2) context.lineTo(width + x、高さ + y - 半径) context.arc(幅 - 半径 + x、高さ - 半径 + y、半径、0、Math.PI / 2) context.lineTo(半径 + x、高さ + y) context.arc (半径 + x、高さ - 半径 + y、半径、Math.PI / 2、Math.PI) context.fill() context.closePath()}
弾幕サービス機能はこちら
使用
<barrage ref=barrage class=barrage :barrage-list=barrageList :speed=speed :loop=loop :channels=channels/> import Barrage from 'vue-barrage'// Barrage データの初期化 this.barrageList = [{ content: 'テスト データ テスト番号 テスト データ番号 テスト データ', カラー: '白'}]// 新しい弾幕を追加します this.$refs.barrage.add({ content: '新しい弾幕を追加新しい弾幕を追加'、色: '白'})結論
全体として、このコンポーネントにはまだ最適化の余地があり、今後も改善を続けていきます。
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。また、VeVb Wulin Network をご支援いただければ幸いです。