はじめに
Google Maps JavaScript APIを利用して、以下の条件で 現在値をリアルタイム追跡(watchPosition) するボタンを実装したので、まとめる。
- 「現在値取得」ボタンを押すと現在値の追跡を開始する
- 再度押すと追跡を停止する
- 現在値にマーカー+誤差の円(Circle)を表示する
- ボタンのON/OFFをCSSで切り替える
スマホアプリのような「現在値追跡」をWEBで実現する。
完成イメージ
- 「現在値取得」ボタンを押すと追跡開始
- 現在地が動くと、マーカーと円が追従する
- 「取得解除」で追跡停止する
GoogleMaps JavaSCript APIを利用して作成した地図の左下にボタンを表示する
実装
1.Google Maps JavaScript API
GoogleMapsAPIのcontrolsは、通常のHTMLとは別レイヤで管理されるため、UIボタンを地図の任意位置に配置。
今回は、LEFT_BOTTOMに「現在値取得」ボタンを追加している。
-
document.createElement("button")で DOM を生成 -
map.controls[ControlPosition]に push することで、Google Maps の UI に統合 -
Maps API のコントロールは通常の DOM と違い、地図の上に固定配置される
const locationButton = document.createElement("button"); //ボタンを生成
locationButton.textContent = "現在地取得";
locationButton.classList.add("custom-map-control-button");
map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(locationButton);
2.Geolocation API(位置情報の取得)+状態管理
GeolocationAPIのwatchPosition()を使うことで、GPSの変化に応じてコールバックが実行され、リアルタイム追跡を実装
また、追跡の開始・停止を正しく制御するためには、watchIDとisTrackingの2つで状態を管理する。これにより、ボタンのON/OFFと位置追跡の同期がとれる。
-
getCurrentPosition()は単発で実行 -
watchPosition()は位置が変わるたびにコールバックされる - スマホアプリのような位置追跡がWEBで実現可能
-
isTrackingでボタンのON/OFFを制御 -
watchIDを保持しなければ、clearWatch()ができない - マーカ―と円は毎回更新するので、変数で保持して都度削除
locationButton.addEventListener("click", () => { //取得ボタンをクリック
if (!isTracking) {
setCurrentLocationTracking(map);
locationButton.textContent = "取得解除";
locationButton.classList.remove("tracking-off");
locationButton.classList.add("tracking-on");
isTracking = true;
} else {
if (watchId !== null) {
navigator.geolocation.clearWatch(watchId);
watchId = null;
}
if (currentMarker) currentMarker.map = null;
if (currentCircle) currentCircle.setMap(null);
locationButton.textContent = "現在地取得";
locationButton.classList.remove("tracking-on");
locationButton.classList.add("tracking-off");
isTracking = false;
}
});
//~略
watchId = navigator.geolocation.watchPosition(
(position) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
// 既存のマーカーと円を削除
if (currentMarker) currentMarker.map = null;
if (currentCircle) currentCircle.setMap(null);
// 新しい円
currentCircle = new google.maps.Circle({
strokeColor: '#115EC3',
strokeOpacity: 0.2,
strokeWeight: 1,
fillColor: '#115EC3',
fillOpacity: 0.2,
map: map,
center: pos,
radius: 50
});
);
3.地図の追従
現在値が更新される度に、map.panTo()を呼び出すことで、地図が常にユーザーの位置を中心に表示する「追従モード」を実現
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
//略
map.panTo(pos);
実装コード
locationButton.classList.add("tracking-off"); // 初期状態
locationButton.addEventListener("click", () => {
if (!isTracking) {
setCurrentLocationTracking(map);
locationButton.textContent = "取得解除";
locationButton.classList.remove("tracking-off");
locationButton.classList.add("tracking-on");
isTracking = true;
} else {
if (watchId !== null) {
navigator.geolocation.clearWatch(watchId);
watchId = null;
}
if (currentMarker) currentMarker.map = null;
if (currentCircle) currentCircle.setMap(null);
locationButton.textContent = "現在地取得";
locationButton.classList.remove("tracking-on");
locationButton.classList.add("tracking-off");
isTracking = false;
}
});
let currentMarker = null;
let currentCircle = null;
let watchId = null;
function setCurrentLocationTracking(map) {
if (!navigator.geolocation) return;
// すでに追跡中なら止める
if (watchId !== null) {
navigator.geolocation.clearWatch(watchId);
}
let isFollowing = true;
watchId = navigator.geolocation.watchPosition(
(position) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
// 既存のマーカーと円を削除
if (currentMarker) currentMarker.map = null;
if (currentCircle) currentCircle.setMap(null);
// 新しい円
currentCircle = new google.maps.Circle({
strokeColor: '#115EC3',
strokeOpacity: 0.2,
strokeWeight: 1,
fillColor: '#115EC3',
fillOpacity: 0.2,
map: map,
center: pos,
radius: 50
});
// 新しいマーカー
const iconElement = document.createElement('div');
iconElement.style.width = '14px';
iconElement.style.height = '14px';
iconElement.style.backgroundColor = '#115EC3';
iconElement.style.border = '2px solid white';
iconElement.style.borderRadius = '50%';
iconElement.style.boxSizing = 'border-box';
currentMarker = new google.maps.marker.AdvancedMarkerElement({
position: pos,
map: map,
content: iconElement
});
if(isFollowing) {
map.panTo(pos);
}
},
(error) => {
console.error("位置情報の取得に失敗しました:", error);
},
{
enableHighAccuracy: true,
maximumAge: 0,
timeout: 10000
}
);
// 地図操作で追尾を止める
map.addListener('dragstart', () => {
isFollowing = false;
});
}
まとめ
- Google Maps JavaSCript API+Geolocation APIで現在地追跡が実装できる
- マーカーと円で現在地を視覚的に表示可能
- スマホのようなUXをWEbでも実現可能
本機能はGASアプリに実装しましたが、視覚的にも正確に動きました。手探り状態で行っていましたが、成功したので備忘録も兼ねて残します。
今後、精度をより上げたり、UI向上を課題として取り組みたいと思います。