キャンバス canvas の高速化手法 その3


キャンバスを使った二次元グラフィックを提供する際に、利用者のマシンの性能や利用しているブラウザによっては、パフォーマンスに影響が出ることがあります。
この改善のための手法をいくつか紹介します。

キャンバスの複数レイヤー化

キャンバスの高速化手法の第三弾です。
今回は複数のキャンバス使用したレイヤーによる高速化になります。

キャンバスのレイヤー化のイメージ

下図がキャンバスをレイヤー化した際のイメージになります。

ここでは canvasA と canvasBと canvasC の3個のキャンバスをイメージにしてみました。
3個のキャンバスは完全に重なった位置に配置され、一番上に見えるのが canvasCになります。
canvasB は canvasC で透過された部分が画面に現れます。
canvasA は canvasB と canvasC の両方が透過された部分のみ画面に現れます。

この方法の何が優れているかというと、例えば、
 canvasA : 背景画像
 canvasB : 動きのある描画
 canvasC : ユーザーへのメッセージ
という感じで役割を決めてやれば、動きのある描画(アニメーション等)を更新するたびに背景画像を書き直さなくて済みますし、メッセージはアニメーションを気にしないでいつでも表示できます。
これによって、マシンが描画をする負担を大幅に削減することができます。

それではキャンバスのレイヤー化の作り方と使い方を見てみましょう。

キャンバスのレイヤー化の作り方

キャンバスをレイヤー化すにるは、HTMLとCSSとJavaScriptの作成が必要ですので、それぞれに順番に説明していきます。

《HTML》

<canvas id="canvasC" width="200" height="200"></canvas>
<canvas id="canvasB" width="200" height="200"></canvas>
<canvas id="canvasA" width="200" height="200"></canvas>

まずはHTMLの記載です。
ここではレイヤー化するキャンバスの3個を定義しています。
それぞれにユニークなIDが必要です。
サイズは全て同じで記載していますが、必須ではなく、この方が楽だからと理解ください。

HTML上の記載箇所は、他のHTML要素と同じで表示したい場所に記載すればオッケイですが、レイヤー化する3個のキャンバスは連続で書きましょう。

次がstyleの記載です。

《style》

#canvasA{
z-index: 1;
}
#canvasB{
z-index: 2;
position: absolute;
}
#canvasC{
z-index: 3;
position: absolute;
}

スタイルは各ID毎に記載が必要で、まず大切なのは z-index で順番を明確にすることです。
x-index は数字が大きい方が上に重なります。
ここでの例は前記のイメージ図と同じで canvasA が一番下、canvasB が真ん中、canvasCが一番上になります。

もう一つ書かなければいけないのが position: absolute で、canvasB と canvasC を通常のフローから除外しておくことです。
canvasA に対しても同じ記載にしてしまうと迷路に入り込みますので注意してください。

最後がscriptの記載になります。
ここではコンテキストの取得までを説明します。

《script》

var canvasA = document.getElementById("canvasA");
var ctxA = canvas.getContext('2d');
var canvasB = document.getElementById("canvasB");
var ctxB = canvas.getContext('2d');
var canvasC = document.getElementById("canvasC");
var ctxC = canvas.getContext('2d');

各キャンバスのIDからエレメントを取得し、さらにそれぞれのエレメントのコンテキストを取得します。
ここで取得した ctxA、ctxB、ctxC が実際の描画の際に利用できます。

ここで注意すべき点を説明します。
作成したキャンバスに対するマウスイベントなどを取得するために addEventListener() メソッドを利用する場合、対象のキャンバスは必ず一番上に描画されるキャンバスを指定してください。
この例の中では canvasC がそれに該当します。
これを canvasA や canvasB で記載してしまうと、いつまで待ってもイベントが通知されません。

キャンバスのレイヤー化の使用例

では実際にキャンバスをレイヤー化して描画してみましょう。
ここでは前述の通り canvasA、canvasB、canvasC の3個を使います。
HTMLとstyleは前述のままで行けすので、ここではscriptだけを説明します。

《script》

var canvasA, canvasB, canvasC;
var ctxA, ctxB, ctxC;
var interval;
var x = 100;
var y = 100;
var dx = 8;
var dy = 5;
function init() {
	canvasA = document.getElementById("canvasA");
	ctxA = canvasA.getContext('2d');
	canvasB = document.getElementById("canvasB");
	ctxB = canvasB.getContext('2d');
	canvasC = document.getElementById("canvasC");
	ctxC = canvasC.getContext('2d');
	ctxA.fillStyle = "white";
	ctxA.fillRect(0, 0, canvasA.width, canvasA.height);
	ctxA.fillStyle = "#aaa";
	for( var i = 0; i < 10; i++) {
		for (var j = 0; j < 5; j++) {
			ctxA.fillRect(j * 40 + (i % 2) * 20, i * 20, 20, 20);
		}
	}
	ctxC.clearRect(0, 0, canvasC.width, canvasC.height);
	ctxC.fillStyle = "blue";
	ctxC.font = "bold 36px sans-serif";
	ctxC.fillText("canvas", 40, 120);
	interval = setInterval(drawTimer, 50);
}
function drawTimer() {
	ctxB.clearRect(0, 0, canvasB.width, canvasB.height);
	ctxB.fillStyle = "red";
	ctxB.beginPath();
	ctxB.arc(x, y, 20, 0, Math.PI * 2);
	ctxB.fill();
	if (x < 20 || x > 180)	dx *= -1;
	if (y < 20 || y > 180)	dy *= -1;
	x += dx;
	y += dy;
}

《実行結果》

この例では、チェック柄の背景の上で赤いボールが動いていて、その上に青い文字が描かれています。
ボールの動作は setInterval() メソッドを利用して、時間で描き変わるようにしていますが、背景と文字は一度描画しただけです。

この例の簡単な説明です。

今回は簡単な描画での説明ですが、より複雑な描画において効果を発揮します。

ここまでがキャンバスの高速化手法 その3 になります。