記事検索

検索ワードを入力してください。
Sky Tech Blog
アプリ開発に​おいて​描画UIを​実装する​際の​ viewport の​考え方

アプリ開発に​おいて​描画UIを​実装する​際の​ viewport の​考え方

ズーム機能を持つUIで「クリック位置がズレる」問題は、座標空間の「viewport」を考慮していないことが原因かもしれません。本記事では、座標を「world」「viewport」「screen」の3層で整理する考え方を解説します。viewportはworld(データ)を書き換えずに見え方だけを変える強力な仕組みであり、この構造を理解することで、ズームやパンの実装における座標変換の問題を解決し、描画処理の役割を明確化できます。

ズーム機能を持つ描画UIでは、ズーム後にオブジェクトをクリックできない、オブジェクトの位置が変わった、といった問題が発生することがあります。
その原因の一つが、「viewport」を考慮できていないことです。

1. オブジェクトの​座標と、​見えている​オブジェクトに​ズレが​生じてしまう

画面上でオブジェクトを描画・操作できるキャンバス(描画領域)を実装している際の事例です。

描画したオブジェクトをズームした状態で操作しようとすると、クリックしている位置と、実際に判定されるオブジェクトの位置が一致せず、選択できなくなることがありました。

クリックイベントで取得した座標と、オブジェクトが保持している座標をそれぞれログに出して確認すると、一致していないことは分かりましたが、なぜズレが生じるのかが分かりませんでした。

計算ロジックを疑い、何度も見直したところ、原因は、viewportを考慮できていなかったことでした。
次の章では、そのviewportの考え方を整理していきます。

2. 座標は​「3つの​層」で​整理できる​(world / viewport / screen)

viewport」とは、worldのどの範囲を、どの倍率で表示するかを定義する虫眼鏡のようなものです。

虫眼鏡を動かせば表示される範囲が変わり、倍率を変えれば拡大・縮小された状態で表示されます。
viewportは、worldの一部を切り出し、その結果をscreen上に描画します。

ズームやパンを行うと、「world上の座標が変わった」ように感じることがあります。
しかし実際には、worldの座標を書き換えているのではなく、viewportの拡大率や位置を変更しているだけの場合があります。
今回の実装でも、viewportを操作することでズームを実現していました。※パンは、画面を上下左右に移動させる操作のことです。

  • worldはそのまま
  • viewportが動く(ズーム・パン)
  • screenの見え方が変わる

viewportがある最大の利点は、world(データ)をいじらずに、見え方だけを変えられることです。

もしviewportがなく、ズームやパンをworldの座標そのもので表現しようとすると、表示を変えるたびに「すべてのオブジェクト」を書き換える必要が出てきます。

  • 座標(x, y)やサイズを更新し続ける
  • 当たり判定も同じだけ更新する
  • 表示を戻すときも、元の値に戻す必要がある

見せ方(表示範囲や倍率)を変えたいだけであれば、worldの座標を書き換える必要はありません。
ズームやパンで変えるのはviewportだけです。

3. viewportと​変換の​正体

viewportは、worldをどの範囲・倍率・位置で表示するかを定義する概念です。

これはアフィン変換[1]と呼ばれるもので、多くの環境では配列として管理されています。

[ scaleX, skewY, skewX, scaleY, translateX, translateY]

  • scaleX / scaleY
    拡大・縮小(zoom)
  • translateX / translateY
    移動(pan)
  • skewX / skewY
    傾き(斜め方向の変形)

worldの座標そのものは変わりませんが、そこにこの配列の値を適用すると、screen上の座標が計算されます

2D:アフィン変換行列
Canvas / SVG / 地図 / エディタ など

3D:行列変換
ゲームエンジン / 3DCG / WebGL / AR / VR など

4. viewportを​知った​結果

ズームを行うと、screen上の座標はviewportの影響を受けて変化します。
しかし当初は、そのscreen座標をそのままworld座標と比較していました。

その結果、本来一致しているはずの位置でも、基準が異なるため選択判定が失敗していました。

クリック位置の座標を、viewportの拡大率や移動量を考慮してworld座標へ変換するように修正すると、選択判定は正しく機能するようになりました。

当初は「ズーム後に選択できない」という不具合の解消が目的でしたが、この整理により、

  • worldは不変の座標空間として保持する
  • 表示の拡大・移動はviewportで制御する
  • 判定時は必ず座標の層を揃える

という構造が明確になりました。

さらに、この構造にしたことで、キャンバスのサイズそのものを意識する必要がなくなりました。

作業領域を広げたい場合も、詳細を確認したい場合も、worldのデータを変更せず、viewportを変更するだけで対応できます。

worldは変わらない。
変わっているのはviewportだけ。

viewportは単なるズーム機能ではなく、描画処理の役割を整理するための構造を提供します。


  1. ここまでの説明は、CanvasやSVGのような2Dの描画環境を想定したものでした。
    参考までになりますが、この座標変換の考え方自体は、より広い分野で使用されています。 ↩︎


\シェアをお願いします!/
  • X
  • Facebook
  • LINE
キャリア採用募集中!

入社後にスキルアップを目指す若手の方も、ご自身の経験を幅広いフィールドで生かしたいベテランの方も、お一人おひとりの経験に応じたキャリア採用を行っています。

Sky株式会社のソフトウェア開発や製品、採用に関するお問い合わせについては、下記のリンクをご確認ください。
お問い合わせ
ホーム