この記事では無限キャンバスの実装について、基本的なUIの組み合わせで実現するための概要を説明します
記事中の表現は WinUI を前提としていますが、描写とオフスクリーンな画像を扱えるグラフィック機能が利用できれば任意の環境に置き換えた上で実装できると思います
なお、複数人で一枚のキャンバスに描きこむ用途については考慮しません。利用者1名のお絵描きアプリを作る際のヒントとしてお読みいただければと思います
無限キャンバスの土台となる3要素
- キャンバスの描き込み機能を担う描写UI(InkCanvas)
- 描写された内容を表示する画像UI(CanvasControl)
- 描写内容をプールしておくオフスクリーン画像(RenderTargetBitmap)
※ カッコ内はWinUIで実装する場合の参考となるコントロール名
また、補足として
- キャンバスの原点は画面の中心とする
- 画像UI、及びオフスクリーン画像の原点は画像の左上とする
- 描写先領域のキャンバス中心からの移動量と、作業用キャンバスの変形を合成してオフセット座標として扱います
無限キャンバスを表現する処理の流れ
- 描き込み先となる描写UIを画面いっぱいに表示する
- 描き込みを受け取ったら、描き込み領域(Rect)をキャンバス中心座標からオフセット座標を計算してオフスクリーン画像に転写する
- 転写する際、オフスクリーン画像の領域外にはみ出す場合は、オフスクリーン画像のサイズを拡張し、オフスクリーン画像の原点座標もサイズ変化に応じて補正する
- オフスクリーン画像を更新したら画像UIに反映する
- 描写UIの表示情報をクリア
- (任意のタイミングで)オフスクリーン画像とオフセット座標を永続化
ポイント1:描写コントロールとオフスクリーン画像を分けて考える
描写UIはあくまで描写情報を受け取る窓口であって、描写UIに生成された描写情報はオフスクリーン画像に焼き付けます。描写と描き込み先を分離することで、描写UIは大きくても表示画面のサイズだけ描写機能をカバーする能力があれば足ります
ポイント2:作業用キャンバスの変形は画像UIに適用する
- 描写UIは変形(Transform)させない(=常に画面全体に配置)
- キャンバス表示用の画像UIのみを変形させる
- 描写UIからオフスクリーン画像に描きこむ際、作業用キャンバスに対する変形操作を考慮して転写する
- Xamlであれば
var transform = 描写UI.TransformToVisual(画像UI);を基に変形計算すれば十分です
- Xamlであれば