markdown

はじめに (対象読者・この記事でわかること)

この記事は、Webフロントエンド開発者や位置情報サービスに興味があるプログラマーを対象にしています。
Google Maps JavaScript API をすでに読み込んだことがある前提で、2つの座標とそれぞれの半径から円が重なるか(重複領域があるか)を判定するロジック を実装できるようになります。
背景として、ジオフェンスや近接検索、ユーザー同士の距離比較といったシナリオで頻繁に求められる判定です。実装例と共に、ハマりやすいポイントとその対処法も掲載します。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。
- HTML と JavaScript の基本的な文法
- Google Maps JavaScript API のロード方法と基本的なマップ表示
- 緯度・経度・距離計算の概念(球面三角法など)

Google Maps API と円の概念:概要と背景

Google Maps API では、google.maps.Circle オブジェクトで「中心座標」と「半径(メートル単位)」を指定した円を描画できます。円同士が重なるかどうかは、2点間の直線距離各円の半径の合計以下 かどうかで判定できます。
この判定は、次のようなケースで有用です。

  1. ジオフェンス: ユーザーが指定エリアに入ったかどうか。
  2. 近接検索: ある施設がユーザーの設定した検索半径に入っているか。
  3. イベント通知: 複数のデバイスが互いに近づいたときにリアルタイムでアラートを出す。

本稿では、Google Maps API の LatLngcomputeDistanceBetweengoogle.maps.geometry.spherical 名前空間) を利用し、純粋な JavaScript ロジック に落とし込む手順を解説します。

具体的な手順や実装方法

ステップ1:Google Maps API と Geometry ライブラリの読み込み

Html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>円の重なり判定デモ</title> <style>#map { height: 500px; }</style> </head> <body> <div id="map"></div> <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry"></script> <script src="app.js"></script> </body> </html>
  • libraries=geometry を付与することで google.maps.geometry.spherical.computeDistanceBetween が利用可能になります。
  • YOUR_API_KEY は自身の API キーに置き換えてください。

ステップ2:マップと円オブジェクトの作成

app.js(抜粋):

Javascript
// マップ初期化 function initMap() { const map = new google.maps.Map(document.getElementById('map'), { center: { lat: 35.681236, lng: 139.767125 }, // 東京駅付近 zoom: 13 }); // 円A(赤)と円B(青)の中心座標と半径 const circleA = new google.maps.Circle({ map, center: { lat: 35.6895, lng: 139.6917 }, // 新宿 radius: 2000, // メートル strokeColor: '#FF0000', fillColor: '#FFCCCC', fillOpacity: 0.35 }); const circleB = new google.maps.Circle({ map, center: { lat: 35.6735, lng: 139.7100 }, // 霞が関 radius: 1500, strokeColor: '#0000FF', fillColor: '#CCCCFF', fillOpacity: 0.35 }); // 判定結果をコンソールに出力 const overlap = circlesOverlap(circleA, circleB); console.log('円Aと円Bは重なりますか?', overlap); } // 円同士が重なるか判定する関数(次章で詳細解説) function circlesOverlap(c1, c2) { // 1. 中心間距離を計算 const centerDist = google.maps.geometry.spherical.computeDistanceBetween( c1.getCenter(), c2.getCenter() ); // 2. 半径の合計と比較 const radiusSum = c1.getRadius() + c2.getRadius(); return centerDist <= radiusSum; } // マップロード完了時に initMap を呼び出す google.maps.event.addDomListener(window, 'load', initMap);

解説ポイント

  • google.maps.geometry.spherical.computeDistanceBetween(p1, p2) は、2 つの LatLng 間の大円距離(メートル)を返す便利関数です。自前でハーヴァーサイン式を実装する必要はありません。
  • c.getRadius() はメートル単位で半径を取得します。
  • centerDist <= radiusSumtrue なら円は重なります。等号も含めて判定すれば「接触」も重なりとみなせます。

ステップ3:動的に円を更新し再判定する例

実務では、ユーザーがドラッグで円の中心や半径を変えるケースがあります。その際は、circle.setCenter()circle.setRadius() を呼び出すだけで判定ロジックを再利用できます。

Javascript
// 例:マウスドラッグで円Aの中心を変更 map.addListener('drag', function(event) { const newCenter = event.latLng; circleA.setCenter(newCenter); const nowOverlap = circlesOverlap(circleA, circleB); console.log('ドラッグ後の判定:', nowOverlap); });

ハマった点やエラー解決

1. Geometry ライブラリが未ロードで google.maps.geometry が undefined

  • 原因: API URL に libraries=geometry を付け忘れた。
  • 解決策: スクリプトタグのクエリパラメータに正しく libraries=geometry を追加し、ブラウザのコンソールで google.maps.geometry が存在するか確認。

2. 半径単位の取り違え(km と m の混同)

  • 原因: Circleradius プロパティはメートル指定が必須なのに、キロメートルで数値を渡した。
  • 解決策: radius: 2 * 1000 など、必ずメートルに換算して設定。距離計算結果もメートルで返ってくるため、単位を統一。

3. 画面リサイズ後にマップが正しく表示されない

  • 原因: initMap が実行された直後に CSS が適用されていないことがある。
  • 解決策: google.maps.event.trigger(map, "resize"); をリサイズイベントで呼び出すか、setTimeout で遅延させてから fitBounds を実行。

解決策まとめ

問題 原因 対策
google.maps.geometry が undefined Geometry ライブラリ未指定 libraries=geometry を付与
半径単位が合わない km 表記をそのまま使用 メートルへ換算
マップ描画不具合 CSS 読み込みタイミング resize イベントを手動トリガー

まとめ

本記事では、Google Maps JavaScript API と google.maps.geometry.spherical.computeDistanceBetween を活用し、2 つの円(中心座標と半径)が重なるかどうかを判定する手順 を解説しました。

  • 円同士の重なり判定は、中心間距離 ≤ 半径の合計 でシンプルに判定できる
  • Geometry ライブラリの関数で球面距離計算を正確に行える
  • 動的更新やドラッグ操作でも同じロジックを再利用でき、インタラクティブに活用できる

これにより、ジオフェンス、近接検索、リアルタイム位置通知といったシナリオで正確かつ高速に距離判定が実装可能です。次回は、複数円の重なり合いを可視化するレイヤーや、サーバー側での同様判定ロジック(Node.js)について掘り下げる予定です。

参考資料