<canvas>
要素は、ウェブで 2D グラフィックスを描画するためにもっとも広く使用されている標準規格のひとつです。これはゲームや複雑な視覚化で広く使用されます。しかし、ウェブサイトやアプリで使用する canvas が限界に近づくにつれて、パフォーマンスが悪化していきます。この記事では、ウェブサイトやアプリのパフォーマンスを良好に保つために、canvas 要素の使い方の最適化方法を提案します。
パフォーマンスに関する TIPS
パフォーマンスを向上させるための TIPS 集を以下に掲載します。
同様のプリミティブや繰り返し使用するオブジェクトをオフスクリーン canvas で事前にレンダリングする
複雑な描画操作を毎フレーム行っていることに気づいたら、オフスクリーン canvas を作成していったん (あるいは変化するたびに) そこへ描画して、オフスクリーン canvas を毎フレーム描画することを検討してください。
myEntity.offscreenCanvas = document.createElement("canvas"); myEntity.offscreenCanvas.width = myEntity.width; myEntity.offscreenCanvas.height = myEntity.height; myEntity.offscreenContext = myEntity.offscreenCanvas.getContext("2d"); myEntity.render(myEntity.offscreenContext);
浮動小数点数値の座標を避けて整数を使用する
canvas で整数以外の値を使用してオブジェクトを描画すると、サブピクセルレンダリングを実行します。
ctx.drawImage(myImage, 0.3, 0.5);
これはアンチエイリアス効果を生成するために、ブラウザーに追加の計算処理を実行させます。これを避けるために、たとえば Math.floor()
を使用して、drawImage()
を呼び出す際に使用するすべての座標で端数処理を行ってください。
drawImage
で画像のスケーリングを行わない
drawImage()
でいつも画像のスケーリング処理を行うのではなく、さまざまなサイズの画像をオフスクリーン canvas でキャッシュしてください。
複雑なシーンでは複数レイヤーの canvas を使用する
一部の要素は頻繁に変化したり動き回ったりするのに対して、ほかのもの (UI など) はまったく変化しないことに気づくかもしれません。このような場合の最適化方法は、複数の canvas 要素を使用するレイヤーを作成することです。
たとえば最前面に UI レイヤーを作成して、ユーザの入力中にのみ描画処理を行います。また、既存の実体を頻繁に更新するゲームレイヤーや、まれにしか更新しない実体用の背景レイヤーを作成することもできます。
<div id="stage"> <canvas id="ui-layer" width="480" height="320"></canvas> <canvas id="game-layer" width="480" height="320"></canvas> <canvas id="background-layer" width="480" height="320"></canvas> </div> <style> #stage { width: 480px; height: 320px; position: relative; border: 2px solid black } canvas { position: absolute; } #ui-layer { z-index: 3 } #game-layer { z-index: 2 } #background-layer { z-index: 1 } </style>
大きな背景画像用の CSS
ほとんどのゲームのように静的な背景画像を使用する場合は、CSS の background
プロパティを指定した単純な <div>
を、canvas の下層に配置してください。これにより、大きな画像を毎回 canvas に描画する処理を避けます。
CSS transforms を使用して canvas をスケーリングする
CSS transforms は、GPU を使用しますので高速です。canvas をスケーリングしないのが最良ですが、そうでなければ大きな canvas を縮小するよりも小さな canvas を拡大するほうが良好です。Firefox OS では 480 x 320 px にしてください。
var scaleX = window.innerWidth / canvas.width; var scaleY = window.innerHeight / canvas.height; var scaleToFit = Math.min(scaleX, scaleY); var scaleToCover = Math.max(scaleX, scaleY); stage.style.transformOrigin = "0 0"; //scale from top left stage.style.transform = "scale(" + scaleToFit + ")";
moz-opaque
属性を使用する (Gecko に限る)
canvas を使用するゲームで透過処理が不要であれば、canvas 要素で moz-opaque
属性を設定してください。この情報は、内部で描画処理を最適化するために使用できます。
<canvas id="mycanvas" moz-opaque></canvas>
その他の TIPS
- canvas の呼び出しをひとまとめにします (たとえば、複数に分割した線分ではなくポリラインを描画します)。
- 不必要な canvas の状態変更を避けます。
- 新しい状態の全体を描画せずに、スクリーンの差分だけを描画します。
- 可能な限り
shadowBlur
プロパティを避けます。 - 可能な限り テキストレンダリング を避けます。
- canvas をクリアーする別の方法を試します (
clearRect()
対fillRect()
対 canvas のリサイズ) - アニメーションで
window.setInterval()
の代わりにwindow.requestAnimationFrame()
を使用します。 - 高負荷な物理演算ライブラリーに注意してください。