WIZ-CODE.blog

JavaScriptやAjaxをテーマとしたブログです。

*

ClickableCanvasのパフォーマンスを改善する

   

これは以前から気になっていたことなんですが、ClickableCanvasのデモページを自分が持っている低スペックのネットブック(Celeron、XP)で見てみると、すべてのデモがとてつもなく重く動作します。実用性はゼロと言ってもいいくらいです。これはCanvasFighterにも言えることですが、HTML5/Canvas機能がPCのスペックに大きく左右されるためです。 そのなかで、Chrome(ver 19)を使うと低スペックPCでも問題ない水準で動きました。この辺はさすがというか他のモダンブラウザに水をあけている観があります。Chromeのシェアは今年5月時点の情報では約19%。FirefoxIEでシェア減少が続いているなか、じりじりと上昇傾向が続いています。低スペックPCのユーザーにはChromeがお勧めです。 一方でIE9VistaWindows7の環境が必要ですが、これでClickableCanvas バージョン2を実行すると意外に滑らかに動作します。また、ChromeCanvasグラフィックがやや汚いというか劣るのに比べて、IE9Firefox並みにきれいに表示されます。IEのバージョン別内訳を見ると、8が27%で9が17%となっています。IE9の今後の普及にも期待したいところです。 とはいうものの、ブラウザに頼らずに何とかCanvasのパフォーマンスをよくしたいところ。以下のサイトを参考にして、ClickableCanvasの書き直しをしようと考えています。
HTML5 canvas のパフォーマンスの改善
このページの中でいくつか挙げられている方法をどのようにClickableCanvasに取り入れるか考えてながら、Canvasのパフォーマンス改善をはかっていきたいと思います。

対策1: プリレンダリング

Canvasで有効なプリレンダリングの方法は、別のCanvas要素に頻繁に更新しない静的な図形(たとえばキャラクターのグラフィックなど)を描画しておいて、そのCanvas要素をメインで使うCanvas要素でdrawImageメソッドの引数に渡して呼び出し、必要な領域にレンダリングするというものです。要するにfillメソッドやstrokeメソッドを使用して毎回スーパーマリオのキャラを描画するより、あらかじめ他のCanvas要素にレンダリングしておいたキャラグラフィックを画像として呼び出した方が速いということです。というかdrawImageメソッドってImageオブジェクトだけしか受け取らないと勘違いしていました。CanvasImgVideo要素といったHTML要素も第1引数に渡すことができるようです。勉強になりますね。ただ、図形のアニメーションが前提になるClickableCanvasでこの手法を取り入れるのはちょっと難しい気がします。なお、この手法を使う場合、キャラなどが描かれた読み込み専用のCanvas要素のサイズは最小限にすべしとあります。たとえばマリオのサイズが64×64ならば、パフォーマンスのためにもそのCanvas要素を64×64以上にする必要はないということです。

対策2: canvas を一括して呼び出す

これは線形図形やポリゴンを作成するときに適用できる手法です。これらの図形の作成手順は、まずbeginPathメソッドで始点を作り、以降moveTolineToメソッドでパスを作成、ポリゴンの場合だけ最後にclosePathメソッドを実行し、塗りつぶし(fill)やストローク(stroke)メソッドを実行するというものですが、このときできるかぎりfillメソッドやstrokeメソッドを使う回数を減らすべしとのこと。この方法は実際にClickableCanvasで図形単位で行っています。一つの図形を描くのにfillメソッドとstrokeメソッドを一度ずつで済ませるようにしています。

対策3: canvas の状態を不必要に変更しない

この対策の意味することは、CanvasのプロパティであるstrokeStylefillStyleを頻繁に変更するなというものです。たとえば10本の線からなる二色のストライプ図形を作成する場合、座標をずらしながらfillStyleプロパティを変更してそのつど長方形を作成していく方法が考えられますが、これだとfillStyleプロパティを10回変更しなければなりません。一方、最初にひとつの色で一本分の間隔をあけながら長方形を描画し、fillStyleプロパティを変更した後、あいている空間を別の色で埋めていく方法をとれば、fillStyleプロパティの変更は2回で済みます。ただしこれをClickableCanvasに適用するのは難しいです。色をフェードさせるアニメーションでは更新ごとにfillStyleプロパティを書き換える必要がありますので。

対策4: 新しい状態の画面全体ではなく画面の差分のみをレンダリングする

Canvasでは描画したグラフィックにオブジェクトの概念がないため、前に描画したグラフィックをclearRectメソッドなどで消去して、少しだけ色や位置をずらしたグラフィックを再描画し、それを繰り返すことによりアニメーションを表現します。ClickableCanvasではどうしているかというと、更新のたびにCanvas要素の画面全体をclearRectメソッドで消去して再描画する一般的な方法をとっています。この項目の要点というのは、更新のために直前の図形を消去するのにも(つまりclearRectメソッドを実行するのにも)コストがかかるということです。たとえば画面上に小さな丸い図形しか描かれていないのに、それをいちいち更新するたびに画面全体を消去して再描画するのは無駄ということです。これは是非自分のプラグインにも取り入れたいところですが、消去すべき描画領域を図形ごとに計算しなければならず、コードの追加と書き直しがかなり増えそうな気がします。

対策5: 複雑なシーンには複数の CANVAS をレイヤーにして使用する

ClickableCanvasはバージョンから複数のCanvas要素に効果を適用できるようになりました。なので複数のレイヤーを使ってアニメーションを表現することができます。この手法はプラグイン自体のパフォーマンス改善に使えるというよりは、ユーザーがプラグインを利用時にパフォーマンス改善策として使える方法といえます。重要なことは、更新頻度の少ない背景グラフィックなどを下層のレイヤー(Canvas要素)にして、更新頻度の高い図形などと一緒のレイヤーにしないようにすることです。

対策6: SHADOWBLUR の使用を控える

図形に影をつける(ぼかしを入れる)効果はCanvasであまり最適化が進んでいないもようで、この効果を乱用することはパフォーマンス低下につながるとしています。また、この対策を選択するかどうか(つまりぼかしを利用するかどうか)はユーザー次第となります。しかし、ぼかし効果は図形を立体的にして見栄えをよくする非常に効果的な技術なので、パフォーマンスをよほど気にする場合以外では、最小限のぼかしにとどめる程度でよいと思います。

対策7: 浮動小数点座標の使用を控える

CanvaslineWidthといったプロパティは、値に整数値のみならず少数の指定ができます。そして、小数値で指定した場合にも無視されることなく、アンチエイリアスがかかる仕様になっていて「なんとなく」グラフィックに反映されるようになっています。ただ、浮動小数点を指定すると、アンチエイリアス効果にコストを使うことになるので、パフォーマンスを気にする場合はMath.floor(切り捨て)やMath.round(四捨五入)で整数にすることをすすめています。これは自分のプラグインでもまだ導入していないので、テストしてみて次のバージョン更新時にも導入してみたいと思います。

対策8: REQUESTANIMATIONFRAME を使ってアニメーションを最適化する

恐ろしいことに、この記事を見るまでこのメソッドの存在を忘れていました。これはもっと早く試すべきだったかもしれません。しかし、メソッドが実装されているのがモダンブラウザ限定であり、ベンダーによって挙動が違うかもしれない感じがそこはかとなくしていたため、導入を見送りそのまま忘却してしまったのです。FPSが60に固定されるなど、何となく使い勝手がよくない感じがしますが、 よーしおまえらー、アニメーションにsetInterval使うなよー - 「くろまほうさいきょうでんせつ」より こちらのサイトで、requestAnimationFrameメソッドの使用によって、アニメーション描写処理の最適化、不必要にアニメーションループを行わずCPUなどに負荷をかけないなどメリットが多いことがわかったので、次回以降のバージョンでさっそくrequestAnimationFrameメソッドを取り入れてみたいと思います。

まとめ

項目ごとにパフォーマンス改善策を解説してきましたが、ClickableCanvasに導入できる方法がいくつもあるのが分かりました。いずれも根本的な改善策というよりはチューンアップといった感じの効果になるかもしれませんが、CanvasFlashなどに比べて明らかにパフォーマンスで劣っていることや、ハードウェアアクセラレータを実装していないIE8以下のシェアがいまだに4割近くあることを考慮すると、やはりした方がましだと感じます。今回参考にした記事はもともと英文記事で、幸運にも邦訳されたものを読めたのですが、Web関連の最新記事は多くが海外のものなので、こういう数少ない翻訳記事は見逃さないでいきたいところです。

 - JavaScript/Ajax, ブラウザ , ,