19
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【HTML】Canvasの高速化【JavaScript】

Last updated at Posted at 2018-05-29

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つある場合を考えてみます。
丸、三角、四角は画像であるとします。
以下のようなケースです。
frontbuffer.png
普通に実装すると、画像の読み込み後、canvasに丸、三角、四角を3回ずつ描画することになります。

ですが、ここでメモリ上にcanvasを作成して(backBufferと呼ぶことにします。)、それに丸、三角、四角をまとめて描画しておけば、
そのbackBufferをcanvasに3回描画すればよいことになります。

backbuffer.png

3: クリアする矩形のサイズ又は回数を減らそう

canvasに描画する前にclearRectメソッドを呼び出してcanvas全体をクリアしていると思いますが、
全体をクリアするのではなく必要な箇所のみクリアするとパフォーマンスがよくなります。
また複数のcanvasを使用している場合、canvasをクリアする回数を減らすとパフォーマンスがよくなります。

4: WebGL使えばいいんじゃね?

正解です。書き直す工数のある方はwebGL2使いましょう。
2DのWebGLのライブラリとしてはpixi.js,createJSが有名です。

WebGLを使うということはGPUを使うということです。
GPUはコア数がとても多く並列処理に向いているため、3D描画に利用されています。(2Dももちろんできます。)
普通の Canvas API を使った描画では、CPUしか使われません。

ちなみに今は webgpu というAPI(webgl2の後継)を使えば GPU に並列計算させることもできます。
通常の計算早くできないかなって思ったら、GPUのマルチスレッドの方がCPUのマルチスレッドより断然早いです。だってコア数が違うので。

5:頻繁に更新しないのであればdebounce処理を行う

debounceとは?
一定時間イベントが発生し続けている間は処理を実行せず、最後のイベントから指定時間が経過したら処理を実行するという仕組みです。

例えば 1/200s 間隔で mousemove event が10個発生しているとしましょう。最後の mousemove から 1/10s 経過したときに描画を行えばよいわけです。そうすれば、イベントは10回来ているのに描画は1回で済みます。
こういった処理はよく見かけます。canvasの描画以外では、Windowのリサイズとか。split window の枠とかメニューとかやや描画に負担がかかるときに使われる手法で、今後CPUやGPUがどれだけ早くなろうとも使われる技術だと思います。

更新履歴

2024/08/21: 1-3を追記。1-2を加筆修正。
2025/07/10: 5を追記。4を加筆修正。

19
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?