摘要:如果應(yīng)用程序不再需要接受有關(guān)用戶的持續(xù)位置更新,則只需調(diào)用函數(shù),如下所示表示一個(gè)唯一的監(jiān)視請求以便將來取消監(jiān)視。
GeolocationAPI學(xué)習(xí),我寫的挺枯燥的,直接跳到最后看示例。
5.1 位置信息HTML5 Geolocation API的使用方法相當(dāng)簡單。請求一個(gè)位置信息,如果用戶同意,瀏覽器就會(huì)返回位置信息,該位置信息是通過支持HTML5地理定位功能的底層設(shè)備(手機(jī)、筆記本電腦等)提供給瀏覽器的。位置信息由維度、經(jīng)度坐標(biāo)和其他一些元數(shù)據(jù)組成。
5.1.1 經(jīng)度和維度坐標(biāo)位置信息主要有一對維度和經(jīng)度坐標(biāo)組成。
例如坐標(biāo):維度:39.17222、維度:-120.13778
其中維度(距離赤道以北或以南的數(shù)值表示)是39.17222,經(jīng)度(距離英國格林威治以東或以西的數(shù)值表示)是-120.13778。
經(jīng)緯度可以用以下兩種方式表示:
十進(jìn)制格式(例如:39.17222); DMS(Degree Minute Second,角度)格式(例如,66°33" 38" )
除了經(jīng)緯度,HTML5 Geolocation還提供了位置坐標(biāo)的準(zhǔn)確度,以及根據(jù)瀏覽器的硬件設(shè)備是否能夠提供海拔、海拔準(zhǔn)確度、形式方向和速度等元數(shù)據(jù),若無法提供則返回null。
5.1.2 位置的由來Geolocation僅是檢索設(shè)備提供位置信息的API,并且通過該API檢索到的數(shù)據(jù)只具有某種程度的準(zhǔn)確性。并不能保證設(shè)備返回的實(shí)際位置是精確的。
設(shè)備可以使用的數(shù)據(jù)源:
IP地址 三維坐標(biāo) GPS(Global Positioning System,全球定位系統(tǒng)) 從RFID,Wi-Fi和藍(lán)牙到Wi-Fi的MAC地址: GSM或CDMA手機(jī)的ID 用戶自定義數(shù)據(jù)5.1.3 IP地址地理定位數(shù)據(jù)
基于IP地址的地理定位的實(shí)現(xiàn)方式是:自動(dòng)查詢用戶的IP地址,然后檢索器注冊的物理地址。因此,如果用戶的IP地址是ISP提供的,其位置往往是由服務(wù)供應(yīng)商的物理地址決定的,該地址可能距離用戶數(shù)千米。
表5-1 基于IP地址的地理位置數(shù)據(jù)的優(yōu)缺點(diǎn) 優(yōu)點(diǎn) 缺點(diǎn) 任何地方都可用 不精確 在服務(wù)器端處理 運(yùn)算代價(jià)大5.1.4 GPS地理定位數(shù)據(jù)
只要可以看到天空的地方,GPS就可以提供非常精確的定位。GPS定位是通過手機(jī)運(yùn)行在地球周圍的多個(gè)GPS衛(wèi)星的信號實(shí)現(xiàn)的。但是,他的定位時(shí)間可能較長,因此它不適合需要快速響應(yīng)的應(yīng)用程序。
表5-2 基于GPS的地理定位數(shù)據(jù)的優(yōu)缺點(diǎn) 優(yōu)點(diǎn) 缺點(diǎn) 很精確 定位時(shí)間長,用戶耗電量大 室內(nèi)效果不好 需要額外硬件設(shè)備5.1.5 Wi-Fi地理定位數(shù)據(jù)
基于WiFi的地理定位信息是通過三角距離計(jì)算得出的,這個(gè)三角距離值得是用戶當(dāng)前位置到一只的多個(gè)WiFi接入點(diǎn)的距離。不同于GPS,WiFi在室內(nèi)也非常準(zhǔn)確。
表5-3 基于Wi-Fi的地理定位的優(yōu)缺點(diǎn) 優(yōu)點(diǎn) 缺點(diǎn) 精確 在鄉(xiāng)村這些無線接入點(diǎn)較少的地區(qū)效果不好 可在室內(nèi)使用 可以簡單、快捷定位5.1.6 手機(jī)地理定位數(shù)據(jù)
基于手機(jī)的地理定位信息是通過用戶到一些基站的三角距離確定的。這種方法可提供相當(dāng)準(zhǔn)確的位置結(jié)果。這種方法通常同基于Wi-Fi和基于GPS的地理定位信息結(jié)合使用。表5-4是基于手機(jī)的地理定位數(shù)據(jù)的優(yōu)缺點(diǎn)。
表5-4 基于手機(jī)的地理定位數(shù)據(jù)的優(yōu)缺點(diǎn) 優(yōu)點(diǎn) 缺點(diǎn) 相當(dāng)準(zhǔn)確 需要能夠訪問手機(jī)或其modem的設(shè)備 可在室內(nèi)使用 在基站較少的偏遠(yuǎn)地區(qū)效果不好 可以簡單、快捷定位5.1.7 用戶自定義的地理定位數(shù)據(jù)
應(yīng)用程序可能允許用戶輸入他們的地理、郵政編碼和其他的一些詳細(xì)信息。應(yīng)用程序可以利用這些信息來提供位置感知服務(wù)。
表5-5 用戶自定義的地理定位數(shù)據(jù)的優(yōu)缺點(diǎn) 優(yōu)點(diǎn) 缺點(diǎn) 用戶可以獲得比程序定位服務(wù)更準(zhǔn)確的位置數(shù)據(jù) 可能很不準(zhǔn)確,特別是當(dāng)用戶位置變更后 允許地理定位服務(wù)結(jié)果作為備用位置信息 用戶自行輸入可能比自動(dòng)檢測更快5.2 Geolocation的瀏覽器支持情況
目前主流瀏覽器都支持。
5.4 使用HTML5 Geolocation API 5.4.1 瀏覽器支持檢查function loadDemo(){ if(navigator.geolocation){ document.getElementById("support").innerHTML = "Geolocation supported"; }else{ document.getElementById("support").innerHTML = "Geolocation is not supported in your browser."; } }5.4.2 位置請求
有兩種類型的位置要求:
1 單次定位的請求
2 重復(fù)性的位置更新請求
1 只檢索或請求一次用戶位置即可。例如,如果要查詢在接下來的一個(gè)小時(shí)內(nèi)放映某大片的最近的電影院。就可以使用代碼清單5-2所示的簡單HTML5 Geolocation API.
單次定位請求
void getCurrentPosition(in PositionCallback successCallback, in optional PositionErrorCallback errorCallback, in optional PositionOptions options);
這個(gè)函數(shù)接受一個(gè)必須參數(shù)和兩個(gè)可選參數(shù)
函數(shù)參數(shù)successCallback為瀏覽器指明位置數(shù)據(jù)可用時(shí)調(diào)用的函數(shù)。因?yàn)橄瘾@取位置數(shù)據(jù)這樣的操作可能需要較長的時(shí)間才能完成,所以這個(gè)參數(shù)很重要。沒有用戶希望在檢索位置時(shí)瀏覽器被鎖定,也沒有開發(fā)人員希望它的程序無限期被暫停(特別是要成功取得位置信息,經(jīng)常必須等待用戶的許可)。successCallback是收到實(shí)際位置信息并進(jìn)行處理的地方。
跟絕大多數(shù)編程場景一樣,最好提前準(zhǔn)備出錯(cuò)處理。位置信息請求很可能因?yàn)橐恍┎豢煽匾蛩厥?,對于這些情況,你可能需要提供一個(gè)跟用戶解釋或者提示其重試的errorCallback函數(shù)。雖然此參數(shù)是可選的,不過建議選用。
最后,options對象可以調(diào)整HTML5 Geolocation服務(wù)的數(shù)據(jù)收集方式。這是一個(gè)可選參數(shù),隨后在論。
假設(shè)在頁面上已經(jīng)創(chuàng)建了一個(gè)名為updateLocation()的Javascript函數(shù),它使用最新的位置數(shù)據(jù)更新頁面內(nèi)容,同樣的,也創(chuàng)建了一個(gè)handleLocationError()函數(shù)來處理錯(cuò)誤情況。而請求訪問用戶位置的核心代碼如下所示:
navigator.geoocation.getCurrentPosition(updateLocation,handleLocationError);
updateLocation()函數(shù):
只要瀏覽器具備訪問位置信息的條件,就會(huì)調(diào)用updateLocation()函數(shù),該函數(shù)只接受一個(gè)參數(shù):位置對象.這個(gè)對象包含坐標(biāo)(coords特性)和一個(gè)獲取位置數(shù)據(jù)時(shí)的時(shí)間戳。在實(shí)際開發(fā)中不一定需要時(shí)間戳,重要位置數(shù)據(jù)都包含在了coords特性中。
以下是前三個(gè)特性:
latitude(緯度)
logitude(經(jīng)度)
accuracy(準(zhǔn)確度)
latitude和longitude將包含HTML5Geolocaiton服務(wù)測定的最佳十進(jìn)制用戶位置。accuracy將以m指定維度和經(jīng)度值與實(shí)際位置的差距,置信度為95%。
function updateLocation(position){ var latitude = position.coords.latitude; var longitude = position.coords.longitude; var accuracy = position.coords.accuracy; var timestamp = position.timestamp; document.getElementById("latitude").innerHTML = latitude; document.getElementById("longitude").innerHTML = longitude; document.getElementById("accuracy").innerHTML = accuracy; document.getElementById("timestamp").innerHTML = timestamp; }handleLocationError()函數(shù)
因?yàn)槲恢糜?jì)算服務(wù)很可能出錯(cuò),對于HTML5 Geolocation應(yīng)用程序來說處理錯(cuò)誤非常重要。而該API定義了所有需要處理的錯(cuò)誤情況的編號。錯(cuò)誤編號設(shè)置在錯(cuò)誤對象中,錯(cuò)誤對象作為code參數(shù)傳遞給錯(cuò)誤處理程序。這些錯(cuò)誤編號為:
PERMISSION_DENIED(錯(cuò)誤編號為1)---用戶選擇拒絕瀏覽器獲得其位置信息。
POSITION_UNAVAILABLE(錯(cuò)誤編號為2)---嘗試獲取用戶位置數(shù)據(jù),但失敗了。
TIMEOUT(錯(cuò)誤編號為3)--設(shè)置了可選的timeout值。嘗試確定用戶位置的過程超時(shí)。
function hadleLocationError(error){ switch(error.code){ case 0: updateStatus("There was an error while retrieving your location" + error.message); break; case 1: updateStatus("The user prevented this page from retrieving a location"); break; case 2: updateStatus("The browser was unable to determine your location" + error.message); break; case 3: updateStatus("The browser timed out before retrieving the location"); break; } }
如果要同時(shí)處理正常情況和錯(cuò)誤情況,就應(yīng)該把注意力集中到三個(gè)可選參數(shù)(enableHight-Accuracy,timeout和maximumAge)上,將這三個(gè)可選參數(shù)傳遞給HTML5 Geolocation服務(wù)以調(diào)整數(shù)據(jù)收集方式。請注意,這三個(gè)參數(shù)可以使用JSON對象傳遞,這樣更便于添加到HTML5Geolocation請求調(diào)用中。
enableHighAccuracy:啟用該參數(shù),則通知瀏覽器啟用HTML5 Geolocation服務(wù)的高精度模式。參數(shù)的默認(rèn)值為false。如果啟用該參數(shù),可能沒有任何差別,也可能會(huì)導(dǎo)致機(jī)器花費(fèi)更多的時(shí)間和資源來確定位置,所以請謹(jǐn)慎。 timeout:可選值,單位為ms,告訴瀏覽器計(jì)算當(dāng)前位置所允許的最長時(shí)間。如果在這個(gè)時(shí)間內(nèi)未完成計(jì)算,就會(huì)調(diào)用錯(cuò)誤處理程序。其默認(rèn)值為Infinity,即無窮大或無限制。 maximumAge : 這個(gè)值表示瀏覽器重新計(jì)算位置的時(shí)間間隔。它是一個(gè)以ms為單位的值。此值默認(rèn)為0,這意味著瀏覽器每次請求超時(shí)時(shí)必須立即重新計(jì)算位置。
注意:地理定位API不允許我們?yōu)闉g覽器指定多長時(shí)間重新計(jì)算一次位置信息。這是完全由瀏覽器的實(shí)現(xiàn)所決定的。我們能做的就是告訴瀏覽器maximumAge的返回值是什么。實(shí)際頻率是我們一個(gè)無法控制的細(xì)節(jié)。
現(xiàn)在更新我們的位置請求,讓其包含一個(gè)使用JSON對象表示的可選參數(shù),如下所示:
navigator.geolocation.getCurrentPostion(updateLocation,handleLocationError ,{timeout:10000});
這個(gè)新調(diào)用告訴HTML5 Geolocation,任何處理時(shí)間超過10s的位置請求都應(yīng)該調(diào)用handleLocationError函數(shù)處理編號對應(yīng)的TIMEOUT的錯(cuò)誤。
2 重復(fù)性的位置更新請求有時(shí)候,僅更新一次是不夠的。還好,Geolocation服務(wù)的設(shè)計(jì)者使應(yīng)用程序可以在單詞請求用戶定位和以既定時(shí)間間隔多次請求用戶位置間相互轉(zhuǎn)換。事實(shí)上,轉(zhuǎn)換的方式很簡單,只需要變換函數(shù)請求即可,如下所示:
一次更新:
navigator.geolocation.getCurrentPosition(updateLocation,handleLocationError);
重復(fù)更新:
navigator.geolocation.wathcPosition(updateLocation,handleLocationError); // 只要用戶的位置發(fā)生變化,Geolocation服務(wù)就會(huì)調(diào)用updateLocaiton處理程序,它的效果就像是程序在監(jiān)視用戶的位置,并會(huì)在其變化時(shí)及時(shí)通知用戶一樣。
重復(fù)更新的好處:如有一個(gè)頁面,隨著觀察者在城鎮(zhèn)周圍移動(dòng),網(wǎng)頁上的方向指示也隨之改變,再假設(shè)關(guān)于一個(gè)加油站的頁面,隨著用戶開車在高速公路上持續(xù)行駛,頁面不斷更新顯示最近的加油站。另外,還可以在一個(gè)頁面中記錄和傳送用戶位置來實(shí)現(xiàn)回溯已走的路線。如果位置信息一發(fā)生改變,就能傳遞給應(yīng)用程序,那么前面所假設(shè)的所有服務(wù)都會(huì)變得很容易實(shí)現(xiàn)。
如果應(yīng)用程序不再需要接受有關(guān)用戶的持續(xù)位置更新,則只需調(diào)用clearWatch()函數(shù),如下所示:
navigator.geolocation.clearWatch(watchId);
watchId表示一個(gè)唯一的監(jiān)視請求以便將來取消監(jiān)視。所以,如果應(yīng)用程序要停止接收位置更新信息,可以參照以下代碼。
var watchId = navigator.geolocation.watchPosition(updateLocation,handleLocationError); // 基于持續(xù)更新的位置信息的一些功能 //...... // ok,現(xiàn)在我們可以停止接收位置更新信息了 navigator.geolocation.clearWatch(watchId);4.5 使用HTML5 Geolocation構(gòu)建實(shí)時(shí)應(yīng)用
接下來我們使用多次請求特性構(gòu)建一個(gè)簡單有用的Web應(yīng)用程序---距離跟蹤器。
基于HTML5 Geolocation提供的強(qiáng)大定位服務(wù),開發(fā)人員可以創(chuàng)建一個(gè)網(wǎng)頁來跟蹤從網(wǎng)頁被加載的地方到目前所在位置所經(jīng)過的距離。雖然它在臺(tái)式機(jī)上不大實(shí)用,但是對于手機(jī)是很理想的,只要在手機(jī)瀏覽器中打開這個(gè)示例頁面并授予其位置訪問的權(quán)限,每隔幾秒鐘,應(yīng)用程序就會(huì)根據(jù)剛才走過的距離更新,并將其增加到總距離中。
距離計(jì)算公式使用Haversine公式來實(shí)現(xiàn),這個(gè)公式能夠根據(jù)經(jīng)緯度來計(jì)算地球兩點(diǎn)距離。代碼如下(這個(gè)公式后面看看有沒有時(shí)間研究一下,有就后續(xù)補(bǔ)上):
Number.prototype.toRadians = function() { return this * Math.PI / 180; } function distance(latitude1, longitude1, latitude2, longitude2) { // R is the radius of the earth in kilometers var R = 6371; var deltaLatitude = (latitude2-latitude1).toRadians(); var deltaLongitude = (longitude2-longitude1).toRadians(); latitude1 = latitude1.toRadians(), latitude2 = latitude2.toRadians(); var a = Math.sin(deltaLatitude/2) * Math.sin(deltaLatitude/2) + Math.cos(latitude1) * Math.cos(latitude2) * Math.sin(deltaLongitude/2) * Math.sin(deltaLongitude/2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); var d = R * c; return d; }4.5.1 編寫HTML顯示代碼
以簡單的表格進(jìn)行展示,分行顯示緯度、經(jīng)度、準(zhǔn)確度和以ms為單位的時(shí)間戳。
HTML5 Geolocation Distance Tracker
HTML5 Geolocation is not supported in your browser.
Current Position:
Latitude |
? |
---|---|
Longitude | ? |
Accuracy | ? |
Last Timestamp | ? |
在Geolocation數(shù)據(jù)處理部分,第一段Javascript代碼應(yīng)該看起來很熟悉了。之前我們設(shè)置過一個(gè)處理程序loadDemo(),它會(huì)在頁面加載完成時(shí)候執(zhí)行。這個(gè)腳本會(huì)檢測瀏覽器是否支持HTML5 Geolocation,然后將檢測結(jié)果顯示在頁面上。最后,代碼會(huì)請求檢測用戶位置。
var totalDistance = 0.0; var lastLat; var lastLong; function updateStatus(message){ document.getElementById("status").innerHTML = message; } function loadDemo(){ if(navigator.geolocation){ updateStatus.geolocation(){ updateStatus("HTML5 Geolocation is supported in your browser"); navigator.geolocation.watchPosition(updateLocation,handleLocationError,{maximumAge:20000}); } } } window.addEventListener("load",loadDemo,true);
對于錯(cuò)誤處理,我們使用之前提到過的那段代碼,我們將檢查收到的所有錯(cuò)誤編號,并更新頁面上的狀態(tài)信息。
添加錯(cuò)誤代碼function handleLocationError(error) { switch(error.code) { case 0: updateStatus("There was an error while retrieving your location: " + error.message); break; case 1: updateStatus("The user prevented this page from retrieving a location."); break; case 2: updateStatus("The browser was unable to determine your location: " + error.message); break; case 3: updateStatus("The browser timed out before retrieving the location."); break; } }
而我們大部分工作都將在updateLocation()函數(shù)中實(shí)現(xiàn),此函數(shù)中我們將使用最新數(shù)據(jù)來更新頁面并計(jì)算路程。代碼如下:
function updateLocation(position) { var latitude = position.coords.latitude; var longitude = position.coords.longitude; var accuracy = position.coords.accuracy; var timestamp = position.timestamp; document.getElementById("latitude").innerHTML = latitude; document.getElementById("longitude").innerHTML = longitude; document.getElementById("accuracy").innerHTML = accuracy; document.getElementById("timestamp").innerHTML = timestamp; // sanity test... don"t calculate distance if accuracy // value too large if (accuracy >= 500) { updateStatus("Need more accurate values to calculate distance."); return; } // calculate distance 計(jì)算距離 if ((lastLat != null) && (lastLong != null)) { var currentDistance = distance(latitude, longitude, lastLat, lastLong); document.getElementById("currDist").innerHTML = "Current distance traveled: " + currentDistance.toFixed(4) + " km"; totalDistance += currentDistance; document.getElementById("totalDist").innerHTML = "Total distance traveled: " + currentDistance.toFixed(4) + " km"; } lastLat = latitude; lastLong = longitude; updateStatus("Location successfully updated."); }
首先獲取坐標(biāo)數(shù)據(jù)后,記錄所有信息。即收集經(jīng)緯度,準(zhǔn)確度和時(shí)間戳,然后將這些數(shù)據(jù)更新到表格中。
時(shí)間戳對于用戶而言沒有意義,主要是提供程序使用,可以將時(shí)間戳替換成便于用戶識別的時(shí)間指示器,或者將其完全刪除。
準(zhǔn)確度是以米為單位的,顯示不準(zhǔn)確的值會(huì)向用戶提供錯(cuò)誤的位置信息,因此,需要將過濾掉有所有低經(jīng)度的位置更新數(shù)據(jù)。
if (accuracy >= 500) { updateStatus("Need more accurate values to calculate distance."); return; }
完整代碼如下
HTML5 Geolocation Odometer HTML5 Geolocation Distance Tracker
HTML5 Geolocation is not supported in your browser.
Current Position:
Latitude |
? |
---|---|
Longitude | ? |
Accuracy | ? |
Last Timestamp | ? |