Googleマップ上でPowerPointのように図形を操作したい!回転・変形自在なエリアエディタを自作してみた

投稿者: | 2026年4月16日

少し前、とある案件で「Googleマップ上で、PowerPointみたいに図形を回転させたり変形させたりして、直感的にエリアを指定したい」という要望がありました。

標準の Google Maps JavaScript API では、矩形(Rectangle)の描画はサポートされていますが、常に東西南北と平行になってしまう仕様です。そのため、「斜めに回転させる」といった操作を標準機能だけで実現するのは難しいという壁がありました。

そこで、球面幾何学の計算を駆使して(…なんてことはなくベクトル演算などとAPIを組み合わせているだけですが)、完全に自由な変形・回転が可能なエディタコンポーネントを自作してみました。備忘録を兼ねて、実装のポイントなどをまとめておきます。

実際の動作デモ

🎮 操作方法

  • 描画:「Add Usual」などのボタンを押し、地図上をマウスでドラッグすると矩形が描けます。
  • 選択・移動:描画済みのエリアをクリックすると編集モードになり、エリア全体をドラッグして移動できます。
  • 変形・回転:編集モードで表示される四隅の丸印をドラッグするとリサイズ、上部の二重丸ハンドルをドラッグすると回転します。
  • 削除・切替:「Remove」で選択中のエリアを削除、「Prev」「Next」で編集対象を切り替えられます。
  • 保存・復元:下部のテキストエリアから、配置データをJSON形式で書き出し(Export)たり、読み込んだり(Import)できます。

標準APIの壁と実装のポイント

このエディタを実現するにあたり、緯度経度という「球体上の座標」ならではの工夫が必要でした。

1. 図形の定義に Polygon を使用

標準の Rectangle クラスは回転をサポートしていません。そのため、4つの頂点の座標を都度計算して Polygon クラスで描画することで、擬似的に「回転可能な矩形」を表現しています。

2. ベクトル演算と球面幾何学

地球という球体の上で形を保つため、中心座標からの方位角と距離を用いて頂点を算出する spherical.computeOffset 等のメソッドを組み合わせています。また、独自のベクトル演算クラス(math.js)を用意し、回転ハンドルやリサイズ時のマウス挙動を座標に落とし込んでいます。

3. モダンな技術の採用

今回は Vanilla JS(ESモジュール)で構築し、操作用のマーカーには最新の AdvancedMarkerElement を採用しました。※これを使用するには地図初期化時に mapId の指定が必須となります。

使い方(GitHubでの公開)

このコンポーネントは、他のプロジェクトでも手軽にコピペして利用できるよう GitHub にて MITライセンスで公開しています。

GitHub – hiroyukashi/google-maps-area-editor

import { AreaEditor, AreaType } from './AreaEditor.js';

const map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 35.681236, lng: 139.767125 },
    zoom: 18,
    mapId: 'DEMO_MAP_ID',
    isFractionalZoomEnabled: false
});

const editor = await AreaEditor.create(map, {
    types: [new AreaType("usual", "#00bbdd")]
});

editor.setAreaType(editor.types[0]);

※注意: ESモジュール仕様のため、ローカルで index.html を直接開いても動作しません。VS Codeの Live Server 等のローカルサーバー経由で確認してください。

まとめ

一見シンプルに見える図形操作も、地図の上で実現するには意外と幾何学計算が詰まっていて、なかなか歯ごたえのある実装でした。同じような要望で悩んでいる方の助けになれば幸いです。カスタマイズ等、自由に使ってみてください!


(おまけ)
コードのリファインとデモの構築は頑張った…ということで、この記事はAIくんに丸投げしてみました。(ほんのちょっとだけ手直しはしました。 恥ずかしいくらいにべた褒めしてきますよね…彼ら。)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


reCaptcha の認証期間が終了しました。ページを再読み込みしてください。