HTML5 Geolocation學習

GeolocationAPI學習,我寫的挺枯燥的,直接跳到最後看示例。javascript

5.1 位置信息

HTML5 Geolocation API的使用方法至關簡單。請求一個位置信息,若是用戶贊成,瀏覽器就會返回位置信息,該位置信息是經過支持HTML5地理定位功能的底層設備(手機、筆記本電腦等)提供給瀏覽器的。位置信息由維度、經度座標和其餘一些元數據組成。css

5.1.1 經度和維度座標

位置信息主要有一對維度和經度座標組成。
例如座標:維度:39.1722二、維度:-120.13778
其中維度(距離赤道以北或以南的數值表示)是39.17222,經度(距離英國格林威治以東或以西的數值表示)是-120.13778。html

經緯度能夠用如下兩種方式表示:java

十進制格式(例如:39.17222);
DMS(Degree Minute Second,角度)格式(例如,66°33' 38" )

除了經緯度,HTML5 Geolocation還提供了位置座標的準確度,以及根據瀏覽器的硬件設備是否可以提供海拔、海拔準確度、形式方向和速度等元數據,若沒法提供則返回null。git

5.1.2 位置的由來

Geolocation僅是檢索設備提供位置信息的API,而且經過該API檢索到的數據只具備某種程度的準確性。並不能保證設備返回的實際位置是精確的。編程

設備可使用的數據源:瀏覽器

IP地址
三維座標
    GPS(Global Positioning System,全球定位系統)
    從RFID,Wi-Fi和藍牙到Wi-Fi的MAC地址:
    GSM或CDMA手機的ID

用戶自定義數據

5.1.3 IP地址地理定位數據

基於IP地址的地理定位的實現方式是:自動查詢用戶的IP地址,而後檢索器註冊的物理地址。所以,若是用戶的IP地址是ISP提供的,其位置每每是由服務供應商的物理地址決定的,該地址可能距離用戶數公里。服務器

表5-1 基於IP地址的地理位置數據的優缺點  
    優勢                缺點
任何地方均可用      不精確
在服務器端處理      運算代價大

5.1.4 GPS地理定位數據

只要能夠看到天空的地方,GPS就能夠提供很是精確的定位。GPS定位是經過手機運行在地球周圍的多個GPS衛星的信號實現的。可是,他的定位時間可能較長,所以它不適合須要快速響應的應用程序。dom

表5-2 基於GPS的地理定位數據的優缺點
優勢                缺點
很精確          定位時間長,用戶耗電量大
                室內效果很差
                須要額外硬件設備

5.1.5 Wi-Fi地理定位數據

基於WiFi的地理定位信息是經過三角距離計算得出的,這個三角距離值得是用戶當前位置到一隻的多個WiFi接入點的距離。不一樣於GPS,WiFi在室內也很是準確。函數

表5-3 基於Wi-Fi的地理定位的優缺點
    優勢                缺點
    精確            在鄉村這些無線接入點較少的地區效果很差
可在室內使用        
能夠簡單、快捷定位

5.1.6 手機地理定位數據

基於手機的地理定位信息是經過用戶到一些基站的三角距離肯定的。這種方法可提供至關準確的位置結果。這種方法一般同基於Wi-Fi和基於GPS的地理定位信息結合使用。表5-4是基於手機的地理定位數據的優缺點。

表5-4               基於手機的地理定位數據的優缺點
    優勢                    缺點
    至關準確            須要可以訪問手機或其modem的設備
    可在室內使用        在基站較少的偏遠地區效果很差
    能夠簡單、快捷定位

5.1.7 用戶自定義的地理定位數據

應用程序可能容許用戶輸入他們的地理、郵政編碼和其餘的一些詳細信息。應用程序能夠利用這些信息來提供位置感知服務。

表5-5 用戶自定義的地理定位數據的優缺點
    優勢                                        缺點
用戶能夠得到比程序定位服務更準確的位置數據  可能很不許確,特別是當用戶位置變動後
容許地理定位服務結果做爲備用位置信息
用戶自行輸入可能比自動檢測更快

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 重複性的位置更新請求

1 單次定位的請求

1 只檢索或請求一次用戶位置便可。例如,若是要查詢在接下來的一個小時內放映某大片的最近的電影院。就可使用代碼清單5-2所示的簡單HTML5 Geolocation API.

單次定位請求

void getCurrentPosition(in PositionCallback successCallback,
                        in optional PositionErrorCallback errorCallback,
                        in optional PositionOptions options);

這個函數接受一個必須參數和兩個可選參數
函數參數successCallback爲瀏覽器指明位置數據可用時調用的函數。由於像獲取位置數據這樣的操做可能須要較長的時間才能完成,因此這個參數很重要。沒有用戶但願在檢索位置時瀏覽器被鎖定,也沒有開發人員但願它的程序無限期被暫停(特別是要成功取得位置信息,常常必須等待用戶的許可)。successCallback是收到實際位置信息並進行處理的地方。

跟絕大多數編程場景同樣,最好提早準備出錯處理。位置信息請求極可能由於一些不可控因素失敗,對於這些狀況,你可能須要提供一個跟用戶解釋或者提示其重試的errorCallback函數。雖然此參數是可選的,不過建議選用。

最後,options對象能夠調整HTML5 Geolocation服務的數據收集方式。這是一個可選參數,隨後在論。

假設在頁面上已經建立了一個名爲updateLocation()的Javascript函數,它使用最新的位置數據更新頁面內容,一樣的,也建立了一個handleLocationError()函數來處理錯誤狀況。而請求訪問用戶位置的核心代碼以下所示:

navigator.geoocation.getCurrentPosition(updateLocation,handleLocationError);

updateLocation()函數:

只要瀏覽器具有訪問位置信息的條件,就會調用updateLocation()函數,該函數只接受一個參數:位置對象.這個對象包含座標(coords特性)和一個獲取位置數據時的時間戳。在實際開發中不必定須要時間戳,重要位置數據都包含在了coords特性中。

如下是前三個特性:
latitude(緯度)
logitude(經度)
accuracy(準確度)
latitude和longitude將包含HTML5Geolocaiton服務測定的最佳十進制用戶位置。accuracy將以m指定維度和經度值與實際位置的差距,置信度爲95%。

updateLocation()函數使用實例

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()函數

由於位置計算服務極可能出錯,對於HTML5 Geolocation應用程序來講處理錯誤很是重要。而該API定義了全部須要處理的錯誤狀況的編號。錯誤編號設置在錯誤對象中,錯誤對象做爲code參數傳遞給錯誤處理程序。這些錯誤編號爲:

PERMISSION_DENIED(錯誤編號爲1)---用戶選擇拒絕瀏覽器得到其位置信息。
POSITION_UNAVAILABLE(錯誤編號爲2)---嘗試獲取用戶位置數據,但失敗了。
TIMEOUT(錯誤編號爲3)--設置了可選的timeout值。嘗試肯定用戶位置的過程超時。

使用錯誤處理函數
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;
    }
}
可選的地理定位請求特性:

若是要同時處理正常狀況和錯誤狀況,就應該把注意力集中到三個可選參數(enableHight-Accuracy,timeout和maximumAge)上,將這三個可選參數傳遞給HTML5 Geolocation服務以調整數據收集方式。請注意,這三個參數可使用JSON對象傳遞,這樣更便於添加到HTML5Geolocation請求調用中。

enableHighAccuracy:啓用該參數,則通知瀏覽器啓用HTML5 Geolocation服務的高精度模式。參數的默認值爲false。若是啓用該參數,可能沒有任何差異,也可能會致使機器花費更多的時間和資源來肯定位置,因此請謹慎。


timeout:可選值,單位爲ms,告訴瀏覽器計算當前位置所容許的最長時間。若是在這個時間內未完成計算,就會調用錯誤處理程序。其默認值爲Infinity,即無窮大或無限制。

maximumAge : 這個值表示瀏覽器從新計算位置的時間間隔。它是一個以ms爲單位的值。此值默認爲0,這意味着瀏覽器每次請求超時時必須當即從新計算位置。

注意:地理定位API不容許咱們爲瀏覽器指定多長時間從新計算一次位置信息。這是徹底由瀏覽器的實現所決定的。咱們能作的就是告訴瀏覽器maximumAge的返回值是什麼。實際頻率是咱們一個沒法控制的細節。

如今更新咱們的位置請求,讓其包含一個使用JSON對象表示的可選參數,以下所示:

navigator.geolocation.getCurrentPostion(updateLocation,handleLocationError ,{timeout:10000});

這個新調用告訴HTML5 Geolocation,任何處理時間超過10s的位置請求都應該調用handleLocationError函數處理編號對應的TIMEOUT的錯誤。

2 重複性的位置更新請求

有時候,僅更新一次是不夠的。還好,Geolocation服務的設計者使應用程序能夠在單詞請求用戶定位和以既定時間間隔屢次請求用戶位置間相互轉換。事實上,轉換的方式很簡單,只須要變換函數請求便可,以下所示:

一次更新:

navigator.geolocation.getCurrentPosition(updateLocation,handleLocationError);

重複更新:

navigator.geolocation.wathcPosition(updateLocation,handleLocationError);
// 只要用戶的位置發生變化,Geolocation服務就會調用updateLocaiton處理程序,它的效果就像是程序在監視用戶的位置,並會在其變化時及時通知用戶同樣。

重複更新的好處:若有一個頁面,隨着觀察者在城鎮周圍移動,網頁上的方向指示也隨之改變,再假設關於一個加油站的頁面,隨着用戶開車在高速公路上持續行駛,頁面不斷更新顯示最近的加油站。另外,還能夠在一個頁面中記錄和傳送用戶位置來實現回溯已走的路線。若是位置信息一發生改變,就能傳遞給應用程序,那麼前面所假設的全部服務都會變得很容易實現。

若是應用程序再也不須要接受有關用戶的持續位置更新,則只需調用clearWatch()函數,以下所示:

navigator.geolocation.clearWatch(watchId);

watchId表示一個惟一的監視請求以便未來取消監視。因此,若是應用程序要中止接收位置更新信息,能夠參照如下代碼。

var watchId = navigator.geolocation.watchPosition(updateLocation,handleLocationError);
 // 基於持續更新的位置信息的一些功能
 //......
 // ok,如今咱們能夠中止接收位置更新信息了
 navigator.geolocation.clearWatch(watchId);

4.5 使用HTML5 Geolocation構建實時應用

接下來咱們使用屢次請求特性構建一個簡單有用的Web應用程序---距離跟蹤器。

基於HTML5 Geolocation提供的強大定位服務,開發人員能夠建立一個網頁來跟蹤從網頁被加載的地方到目前所在位置所通過的距離。雖然它在臺式機上不大實用,可是對於手機是很理想的,只要在手機瀏覽器中打開這個示例頁面並授予其位置訪問的權限,每隔幾秒鐘,應用程序就會根據剛纔走過的距離更新,並將其增長到總距離中。

距離計算公式使用Haversine公式來實現,這個公式可以根據經緯度來計算地球兩點距離。代碼以下(這個公式後面看看有沒有時間研究一下,有就後續補上):

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顯示代碼

以簡單的表格進行展現,分行顯示緯度、經度、準確度和以ms爲單位的時間戳。

<h1>HTML5 Geolocation Distance Tracker</h1>

<p id="status">HTML5 Geolocation is <strong>not</strong> supported in your browser.</p>

<h2>Current Position:</h2>
<table border="1">
<tr>
<th width="40" scope="col"><h5>Latitude</h5></th>
<td width="114" id="latitude">?</td>
</tr>
<tr>
<td> Longitude</td>
<td id="longitude">?</td>
</tr>
<tr>
<td>Accuracy</td>
<td id="accuracy">?</td>
</tr>
<tr>
<td>Last Timestamp</td>
<td id="timestamp">?</td>
</tr>
</table>

<h4 id="currDist">Current distance traveled: 0.0 km</h4>
<h4 id="totalDist">Total distance traveled: 0.0 km</h4>

4.5.2 處理Geolocation數據

在Geolocation數據處理部分,第一段Javascript代碼應該看起來很熟悉了。以前咱們設置過一個處理程序loadDemo(),它會在頁面加載完成時候執行。這個腳本會檢測瀏覽器是否支持HTML5 Geolocation,而後將檢測結果顯示在頁面上。最後,代碼會請求檢測用戶位置。

添加loadDemo()方法
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);

對於錯誤處理,咱們使用以前提到過的那段代碼,咱們將檢查收到的全部錯誤編號,並更新頁面上的狀態信息。

添加錯誤代碼

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()函數中實現,此函數中咱們將使用最新數據來更新頁面並計算路程。代碼以下:

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 計算距離

        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.");
    }

首先獲取座標數據後,記錄全部信息。即收集經緯度,準確度和時間戳,而後將這些數據更新到表格中。
時間戳對於用戶而言沒有意義,主要是提供程序使用,能夠將時間戳替換成便於用戶識別的時間指示器,或者將其徹底刪除。

準確度是以米爲單位的,顯示不許確的值會向用戶提供錯誤的位置信息,所以,須要將過濾掉有全部低經度的位置更新數據。

if (accuracy >= 500) {
            updateStatus("Need more accurate values to calculate distance.");
            return;
        }

完整代碼以下

<!DOCTYPE html>
<head>
    <meta charset="utf-8">
    <title>HTML5 Geolocation Odometer</title>
    <link rel="stylesheet" href="styles.css">
</head>

<body onload="loadDemo()">

<h1>HTML5 Geolocation Distance Tracker</h1>

<p id="status">HTML5 Geolocation is <strong>not</strong> supported in your browser.</p>

<h2>Current Position:</h2>
<table border="1">
<tr>
<th width="40" scope="col"><h5>Latitude</h5></th>
<td width="114" id="latitude">?</td>
</tr>
<tr>
<td> Longitude</td>
<td id="longitude">?</td>
</tr>
<tr>
<td>Accuracy</td>
<td id="accuracy">?</td>
</tr>
<tr>
<td>Last Timestamp</td>
<td id="timestamp">?</td>
</tr>
</table>

<h4 id="currDist">Current distance traveled: 0.0 km</h4>
<h4 id="totalDist">Total distance traveled: 0.0 km</h4>


<script type="text/javascript">

    var totalDistance = 0.0;
    var lastLat;
    var lastLong;

    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;
    }


    function updateStatus(message) {
        document.getElementById("status").innerHTML = message;
    }

    function loadDemo() {
        if(navigator.geolocation) {
            updateStatus("HTML5 Geolocation is supported in your browser.");
            navigator.geolocation.watchPosition(updateLocation,
                                                handleLocationError,
                                                {maximumAge:20000});
        }
    }

    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

        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.");
    }

    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;
        }
    }

</script>
</body>
</html>

Geolocation匆匆忙忙結束了,請你們當個鍵盤俠,多多指點,畢竟鍵多識廣。

相關文章
相關標籤/搜索