Canvasで描画をしていて遅いってことはありませんか?
仕事で実際に試した方法を記載いたします。
iPadの第4世代のsafari、AndroidのChrome、Windowsのie11,Edgeで効果があることを確認しております。
1: requestAnimationFrameを使おう
requestAnimationFrameはsetTimeoutのようなAPIです。
requestAnimationFrameの使い方については、こちらを参照してください。
1-1: setTimeoutやsetIntervalの代わりにrequestAnimationFrameを使おう
これはそれほど効果ありませんが、setTimeoutやsetIntervalより、requestAnimationFrameの方が多少良いそうです。
1-2: mousemove/touchmoveなどの動作イベントでもrequestAnimationFrameを使おう
これが最も効果があると思います。
canvasに描画しているオブジェクトをドラッグするプログラムを考えます。
描画を mousemove / touchmove のタイミングで行うのではなく、
mousemove / touchmoveでは描画に必要な情報を更新し、
requesAnimationFrameで描画するようにすると、カクツキが無くなります。
これは、mousemove / touchmove のイベントはマウスをぐりぐり動かすと1秒に数百回発生するためです。
requesAnimationFrameで描画すると、リフレッシュレートのタイミングで描画されるので、1秒に描画する回数(FPS)が60-120ぐらいになります。
1-3: requesAnimationFrameで描画を間引こう
Webで表示するなら、FPSは30ぐらいで十分だと思いますが、1-2のようにrequesAnimationFrameで描画するようにすると、FPSが75とか120とか、結構大きくなります。
ですので、時間を測定しFPSが30になるぐらいに調整すると、1秒当たりの描画回数が減ります。
2: backBuffer(DOMに追加されないメモリ上のCanvas)を使おう
動的にCanvasを作成し、それに事前に描画しておき、最終的に表示したいCanvasにレンダリングすると表示が速くなります。
例えば、Canvas上にある位置に丸、三角、四角が表示されていて、それが3つある場合を考えてみます。
丸、三角、四角は画像であるとします。
以下のようなケースです。
普通に実装すると、画像の読み込み後、canvasに丸、三角、四角を3回ずつ描画することになります。
ですが、ここでメモリ上にcanvasを作成して(backBufferと呼ぶことにします。)、それに丸、三角、四角をまとめて描画しておけば、
そのbackBufferをcanvasに3回描画すればよいことになります。
3: クリアする矩形のサイズ又は回数を減らそう
canvasに描画する前にclearRectメソッドを呼び出してcanvas全体をクリアしていると思いますが、
全体をクリアするのではなく必要な箇所のみクリアするとパフォーマンスがよくなります。
また複数のcanvasを使用している場合、canvasをクリアする回数を減らすとパフォーマンスがよくなります。
4: WebGL使えばいいんじゃね?
正解です。書き直す工数のある方はwebGL2使いましょう。
2DのWebGLのライブラリとしてはpixi.js,createJSが有名です。
更新履歴
2024/08/21: 1-3を追記。1-2を加筆修正。