13

私は現在、HTML5 キャンバス上に多くの 2D パス (数百、数千の小さなセグメントで構成されている)を表示するアプリケーションを作成しています。通常、数百万ポイントです。これらのポイントは、サーバーからバイナリにダウンロードされますArrayBuffer

現実の世界ではおそらくそれほど多くのポイントを使用することはないでしょうが、パフォーマンスを向上させる方法にちょっと興味があります. 必要に応じて、それを好奇心と呼ぶことができます ;)

とにかく、私は次の解決策をテストしました:

  1. gl.LINESまたはWebGLを使用gl.LINE_STRIPして、GPU 上のシェーダーですべてを計算します。現在最速で、Macbook Air でひるむことなく最大10M のセグメントを表示できます。しかし、速度の遅い JavaScript での処理を避けたい場合、バイナリ形式には非常に厳しい制約があります。

  2. Canvas2Dを使用して、1 回の呼び出しですべてのセグメントを含む巨大なパスを描画しstroke()ます。100kポイントを超えると、キャンバスが更新される前にページが数秒間フリーズします。だから、ここで働いていません。

  3. Canvas2Dを使用しますが、各パスを独自のstroke()呼び出しで描画します。他の人がインターネットで言っていることにもかかわらず、これは 1 回の呼び出しですべてを描画するよりもはるかに高速ですが、それでも WebGL よりもはるかに低速です。約500k セグメントに達すると、状況が悪化し始めます。

2 つの Canvas2D ソリューションでは、JavaScript のすべてのパスのすべてのポイントをループする必要があるため、これは非常に遅くなります。ArrayBuffer での JavaScript の反復速度、または一般的な処理速度を向上させる方法を知っていますか?

しかし、奇妙なことに、すべてのキャンバス ドロー コールが終了した直後に画面が更新されません。パフォーマンスの限界に達し始めると、描画呼び出しの終了とキャンバスの更新の間に顕著な遅延が生じます。それがどこから来ているのか、それを減らす方法はありますか?

4

1 に答える 1

8

まず、WebGL は素晴らしく誇大なアイデアでしたが、バイナリ データをデコードして表示するために必要な処理量は、シェーダーではまったく機能しないため、除外しました。

これが私が遭遇した主なボトルネックです。それらのいくつかは、一般的なプログラミングでは非常に一般的ですが、それらを覚えておくことをお勧めします:

  • 複数の小さなforループを使用することをお勧めします
  • 可能な限り高いレベルで変数とクロージャを作成し、for ループ内で作成しないでください
  • データをチャンクでレンダリングsetTimeoutし、数ミリ秒後に次のチャンクをスケジュールするために使用します:そうすれば、ユーザーは引き続き UI を使用できます
  • JavaScript のオブジェクトと配列は高速で安価なので、それらを使用してください。最初から最後まで、順番に読み書きするのが最善です。
  • 配列にデータをシーケンシャルに書き込まない場合は、オブジェクトを使用し (非シーケンシャルな読み書きはオブジェクトにとって安価であるため)、インデックスをインデックス配列にプッシュします。ここで見つけたインデックスをソートしたままにするために、SortedList実装を使用しました。オーバーヘッドは最小限 (レンダリング時間の約 10 ~ 20%) であり、最終的にはそれだけの価値がありました。

それは私が覚えているすべてについてです。他に何か見つけたら、この回答を更新します。

于 2012-06-21T18:20:35.313 に答える