/
CATEGORY
JavaScript
/
用 Geolocation API 取得與追蹤使用者地理位置

用 Geolocation API 取得與追蹤使用者地理位置

MUKI AI Summary

Geolocation API 是 HTML5 Web API 中一個強大的工具,允許網頁存取使用者的地理位置,能提供導航、在地服務等功能。此 API 注重隱私,只有在使用者授權的前提下才能取得位置資訊。Geolocation API 的核心功能包括取得使用者目前位置、持續監控位置變化及提供位置精準度資訊。瀏覽器可透過 GPS、網路位置及 IP 位址來確定使用者位置。

使用 Geolocation API 前需檢查瀏覽器支援性,並透過 `getCurrentPosition()` 方法取得當前位置。此方法接受三個參數:成功回調、錯誤回調及選項設定。為了即時追蹤位置變化,可使用 `watchPosition()` 方法,並結合地圖服務如 OpenStreetMap 來顯示位置。若使用者拒絕授權,需引導其修改瀏覽器設定以重新啟用地理位置功能。此 API 提供的功能強大且安全,但需經過使用者同意以保護隱私。...

Web API 系列文章

這系列文章是我參加 2024 iThome 鐵人賽期間撰寫的作品。完賽後,我對文章進行潤稿與修訂,並重新發佈在部落格上。
為了聚焦在 Web API 上,文章內的所有範例都使用原生 HTML + CSS + JavaScript 撰寫,並提供完整的線上範例,如有任何問題,歡迎留言討論。

Geolocation API 是 HTML5 Web API 中非常強大的工具。它能讓網頁存取使用者裝置的地理位置,也因此能提供許多貼心的服務,例如導航位置、觀看在地天氣或是取得當地的服務 ... 等等。同時,Geolocation API 也是個注重隱私的 API,只有在使用者清楚授權並同意的前提下,我們才能取得使用者的地理位置,這使得 Geolocation API 成為一個強大好用,又兼具安全性的工具。

Geolocation API 的核心功能

Geolocation API 主要提供以下功能:

  1. 取得使用者目前的位置
  2. 持續監控使用者位置的變化
  3. 提供位置的精準度資訊

而瀏覽器可以通過以下方式,來確定使用者的地理位置:

  • GPS 全球定位系統:精確且可靠,但耗電
  • 網路位置 (如 Wi-Fi 或基地台定位):適合室內環境
  • IP 位址定位:雖然不夠準確,但作為備選方案也夠用

檢查瀏覽器是否支援 Geolocation API

▼ 開始之前,我們通常會檢查瀏覽器是否支援這個 API,判斷方式如下

if ("geolocation" in navigator) {
  console.log("瀏覽器支援 Geolocation API");
} else {
  console.log("瀏覽器不支援 Geolocation API");
}

如果支援,就用 getCurrentPosition() 取得目前的位置

使用 getCurrentPosition() 取得當前位置

navigator.geolocation.getCurrentPosition(successCallback, errorCallback, options);

getCurrentPosition() 方法接受三個參數:

  1. successCallback:成功取得位置時執行的函數
  2. errorCallback:取得位置失敗時執行的函數(選填)
  3. options:相關的設定,如是否使用 HighAccuracy、設定 timeout ... 等等(選填)

▼ 完整範例

function successCallback(position) {
  const { latitude, longitude } = position.coords;
  console.log(`目前位置:緯度 ${latitude}, 經度 ${longitude}`);
}

function errorCallback(error) {
  console.error(`錯誤:${error.message}`);
}

const options = {
  enableHighAccuracy: true,
  timeout: 5000,
  maximumAge: 0,
};

navigator.geolocation.getCurrentPosition(successCallback, errorCallback, options);

options 參數說明

使用 Geolocation API 時,可以透過 options 物件來設定相關的選項,以下列舉 3 個選項,簡單介紹其含義與接受的值。

參數名稱值的類型預設值
enableHighAccuracyBooleanfalse
說明
設為 true 可以讓裝置提供更精準的位置,但相對的也會讓處理時間變長、需要更多的電量,或是增加消耗 GPS 晶片。
timeout正整數Infinity (單位:毫秒)
說明取得使用者地理位置時,超過這個時間就會停止解析。如果有在 errorCallback 顯示 error,會看到錯誤為 Timer expired
maximumAge正整數0 (單位:毫秒)
說明預設為 0 表示不進行快取,每次都要重新取得最新的使用者地理位置;
假如設定為 60000,表示允許使用過去 60 秒內取得的地理位置。

出現錯誤訊息:Only request geolocation information in response to a user gesture.

前面有提過,Geolocation API 必須要經過使用者的同意才能取得地理位置。因此這個錯誤表示我們在沒有經過使用者允許的情況下,就使用 Geolocation API 取得使用者的地理位置。

怎樣才算是取得使用者的同意呢?

▼ 我們要讓使用者進行明確的動作 (例如點選按鈕、點選連結) 後再要求 Geolocation 的權限。

if ("geolocation" in navigator) {
	console.log('瀏覽器支援 Geolocation');
	// NOTE: 點選按鈕才會呼叫 getCurrentPosition()
	document.getElementById('geolocation').addEventListener('click', function () {
	function successCallback(position) {
		const latitude = position.coords.latitude;
		const longitude = position.coords.longitude;
		console.log(`緯度:${latitude},經度:${longitude}`);
	}
	function errorCallback(error) {
		console.error(`錯誤:${error.message}`);
	}
	const options = {
		enableHighAccuracy: true,
		timeout: 5000,
		maximumAge: 0
	};
	navigator.geolocation.getCurrentPosition(successCallback, errorCallback, options);
	});
} else {
	console.log('瀏覽器不支援 Geolocation');
}

▼ 可以在 console 面板看到輸出的資訊

瀏覽器支援 Geolocation
緯度:15.0232011,經度:211.2709354

更好的顯示錯誤訊息

取得地理位置時可能會遇到各種問題,例如使用者拒絕授權,該裝置讀不到位置(本身不支援地理位置的功能),沒有網路或訊號不好… 等等

▼ 我們可以在 errorCallback 函數中,根據錯誤訊息顯示對應的文字

function errorCallback(error) {
  switch(error.code) {
    case error.PERMISSION_DENIED:
      console.error("使用者拒絕了地理位置請求。");
      break;
    case error.POSITION_UNAVAILABLE:
      console.error("無法取得地理位置");
      break;
    case error.TIMEOUT:
      console.error("請求超時。");
      break;
    case error.UNKNOWN_ERROR:
      console.error("發生未知錯誤。");
      break;
  }
}

拒絕權限後該如何重新啟用

如果使用者一開始就拒絕分享地理位置,我們便無法使用 Geolocation API 取得地理位置,也無法再使用 JavaScript 重新觸發請求的對話框

但我們可以引導使用者,讓他們修改瀏覽器設定分享地理位置。以 Chrome 為例,選擇網址左側的 icon,再選擇「位置」 → 「重設權限」,然後重新載入頁面,就會跳出請求的對話框了

即時追蹤位置變化

Geolocation API 除了能取得使用者當前的地理位置外,還能監控地理位置的變化,通常用於導航類的 APP

▼ 使用 watchPosition() 方法來監控變化

const watchId = navigator.geolocation.watchPosition(successCallback, errorCallback, options);

▼ 該方法會返回一個 watchId,我們可以用它來停止監控

navigator.geolocation.clearWatch(watchId);

結合地圖與模擬移動

Geolocation API 本身不提供地圖功能,因此我們會將取得的位置資訊與第三方地圖服務結合使用,常見的就是 Google Maps 或 OpenStreetMap。

▼ 鑒於 Googel Mpas 的設定較為繁瑣,我們就用 OpenStreetMap 和 Leaflet 來做一個追蹤位置變化的地圖功能吧

<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" />

<script>
let map;
let marker;

function initMap(lat, lon) {
  map = L.map('map').setView([lat, lon], 13);
  L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '© OpenStreetMap contributors'
  }).addTo(map);
  marker = L.marker([lat, lon]).addTo(map);
}

if ("geolocation" in navigator) {
  console.log('瀏覽器支援 Geolocation');
  document.getElementById('geolocation').addEventListener('click', function () {
    function successCallback(position) {
      const latitude = position.coords.latitude;
      const longitude = position.coords.longitude;
      initMap(latitude, longitude);
      console.log(`緯度:${latitude},經度:${longitude}`);
    }

    function errorCallback(error) {
      console.error(`錯誤:${error.message}`);
    }
    navigator.geolocation.getCurrentPosition(successCallback, errorCallback, options);
  });
} else {
  console.log('瀏覽器不支援 Geolocation');
}
</script>

▼ 按下 Get Location 按鈕,就會在地圖上顯示自己的所在位置

使用 watchPosition() 追蹤使用者的地理位置

▼ 再放三個按鈕,分別是追蹤與模擬移動的功能

原本是按下「Get Location」按鈕才會顯示位置,現在改成按下開始追蹤(startTracking()),才會在地圖上顯示位置。

<div id="map"></div>

<!-- status 顯示當前經緯度 -->
<div id="status"></div>

<!-- 加入三個按鈕 -->
<div>
  <button onclick="startTracking()">開始追蹤</button>
  <button onclick="stopTracking()">停止追蹤</button>
  <button onclick="simulateMovement()">模擬移動</button>
</div>

▼ 用 watchPosition() 取代 getCurrentPosition(),用 watchPosition() 的 successCallback 將經緯度傳入 initMap()

// watchPosition 的 successCallback
function updatePosition(position) {
  const { latitude, longitude } = position.coords;
  if (!map) {
    initMap(latitude, longitude);
  } else {
    map.setView([latitude, longitude], 13);
    marker.setLatLng([latitude, longitude]);
  }
  document.getElementById('status').textContent = `緯度: ${latitude}, 經度: ${longitude}`;
}

// watchPosition 的 errorCallback
function handleError(error) {
  document.getElementById('status').textContent = `錯誤: ${error.message}`;
}

function startTracking() {
  if ("geolocation" in navigator) {
    watchId = navigator.geolocation.watchPosition(updatePosition, handleError);
    document.getElementById('status').textContent = "正在追蹤位置...";
  } else {
    document.getElementById('status').textContent = "您的瀏覽器不支援地理位置功能。";
  }
}

模擬移動功能

▼ 開發中沒有真的串接使用者地理位置,所以寫了一個模擬移動的功能,可以隨機修改經緯度來模擬裝置的移動

function simulateMovement() {
  if (simulationInterval) {
    clearInterval(simulationInterval);
    simulationInterval = null;
    document.getElementById('status').textContent = "模擬移動已停止。";
  } else {
    let lat = 48.860611; // 起始緯度
    let lon = 2.3327785; // 起始經度
    simulationInterval = setInterval(() => {
      lat += (Math.random() - 0.5) * 0.001;
      lon += (Math.random() - 0.5) * 0.001;
      updatePosition({ coords: { latitude: lat, longitude: lon } });
    }, 1000);
    document.getElementById('status').textContent = "正在模擬移動...";
  }
}

範例程式碼

線上範例網址:https://mukiwu.github.io/web-api-demo/geo.html

請先點選「開始追蹤」並允許瀏覽器取得你的地理位置。

小結

Geolocation API 是 HTML5 Web API 中的一個強大功能,允許網頁存取使用者裝置的地理位置,但需要經過使用者的同意以保護隱私,建議大家在取得使用者的地理位置前,應清楚解釋需求,並能提供如何修改瀏覽器設定,以便重新授權地理位置存取,避免日後爭議。

以上就是 Geolocation API 的介紹,有任何問題歡迎留言討論唷。

歡迎給我點鼓勵,讓我知道你來過 :)

可愛又迷人的 Web API 系列文章:

  • 用 Geolocation API 取得與追蹤使用者地理位置
MUKI says:

如果文章有幫助到你,歡迎分享給更多人知道。文章內容皆為 MUKI 本人的原創文章,我會經常更新文章以及修正錯誤內容,因此轉載時建議保留原出處,避免出現版本不一致或已過時的資訊。

本文地址:https://muki.tw/geolocation-api-track-location/ 已複製

Subscribe
Notify of
guest

0 則留言
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Copyright © since 2008 MUKI space* / omegaSS theme All Rights Reserved.