add by zhj:
HTML5的地理定位返回的應該都是GPS坐標,即WGS-84坐標,參見Map Types - Google Maps JavaScript API v3
本文使用的是Chrome瀏覽器,經緯度是由Google返回的,使用的坐標是WGS-84,而高德使用的是火星坐標系(GCJ-02),本文中沒有將WGS-84轉換為
GCJ-02就直接去查詢了,查詢結果是有偏差的。在原文的評論中,有些博友也提到了這個問題。
這里有一篇文章:利用HTML5定位功能,實現在百度地圖上定位,才是正確的,在手機上測試(用微信內置瀏覽器打開),無論使用WIFI還是移動4G聯網,
定位精度都是蠻高的,誤差在幾十米內。
要想獲取地理位置,分成兩步,先獲取經緯度,這是html5的新功能,具體實現各個瀏覽器自己想辦法,比如chrome和firefox就是用的google的位置服務,對於firefox,
參見firefox geolocation說明文檔,對於手機QQ瀏覽器,通過抓包,發現它訪問的是騰訊自己的服務器。另外,高德地圖,百度地圖,在沒有開GPS的情況下,都能實現比較
准確的定位(手機端和電腦端)。拿到了經緯度,再調用經緯度轉地理位置的接口(html5沒有這個標准),
Geolocation
HTML5 的 geolocation
是一個令人興奮的 API,通過這套 API,Javascript 代碼就能夠訪問到用戶的當前位置。當然,訪問之前必須得到用戶的明確認可,即同意在頁面共享位置。如果頁面嘗試訪問地理位置信息,瀏覽器就會顯示一個對話框,請求用戶許可共享其地理位置信息,比如這樣:
用戶同意(允許)之后,Geolocation 的 api 就能起作用了。
getCurrentPosition() 方法
Geolocation API 在瀏覽器中的實現是 navigator.geolocation
對象,這個對象包含 3 個方法。第一個方法是 getCurrentPosition(),調用這個方法就會觸發請求用戶共享地理定位信息的對話框。這個方法接收 3 個參數:成功回調函數,可選的失敗回調函數和可選的選項對象。
其中,成功回調函數會接收到一個 Position 對象參數,該對象有兩個屬性:coords 和 timestamp。而 coords 對象中將包含下列與位置相關的信息。
- latitude:以十進制度數表示的維度
- longtitude:以十進制度數表示的經度
- accuracy:經緯度坐標的精度,以米為單位
有些瀏覽器可能會在 coords 對象中提供如下屬性。
- altitude:以米為單位的海拔高度,如果沒有相關數據則值為 null
- altitudeAccuracy:海拔高度的精度,以米為單位,數值越大越不精確
- heading:指南針的方向,0°表示正北,值為 NaN 表示沒有檢測到數據
- speed:速度,即每秒移動多少米,如果沒有相關數據則值為 null
說了這么多,我們來簡單應用下,寫一段代碼獲取當前的經緯度,然后輸出:
navigator.geolocation.getCurrentPosition(geo_success, geo_error);
function geo_success(position) { console.log(position.coords.latitude, position.coords.longitude); } function geo_error(msg) { console.log(msg.code, msg.message); }
代碼很簡單,如果請求成功了就執行 geo_success() 函數,打印經緯度,如果失敗了,輸出一些信息(失敗回調)。
getCurrentPosition() 的第二個參數,即失敗回調函數,在被調用的時候也會接收到一個參數。這個參數是一個對象,包含兩個屬性:message 和 code。其中,message 屬性中保存着給人看的文本消息,解釋為什么會出錯,而 code 屬性中保存着一個數值,表示錯誤的類型:用戶拒絕共享(1),位置無效(2)或者超時(3)。實際開發中,大多數 Web 應用只會講錯誤消息保存到日志文件中,而不一定會修改用戶界面。
我們在 PC 端的 chrome 瀏覽器中執行這段代碼,結果是令人遺憾的:
掐指一算,估計是被牆了... 事實上,以 Chrome 瀏覽器為例,如果您允許 Chrome 瀏覽器與網站共享您的位置,Chrome 瀏覽器會向 Google 位置服務(此環節被牆)發送本地網絡信息,估計您所在的位置。然后,瀏覽器會與請求使用您位置的網站共享您的位置。
接着在 Android 機上測試了下,沒被牆,畢竟谷歌是 Android 的親爹啊。打印出來的信息如下:
31.188199 121.632919
當然只是知道經緯度或許不太那么直觀,如果能把位置顯示在地圖上那就直觀多了!這里我用了高德地圖的API(猛戳這里看效果):
<!doctype html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width"> <title>地圖顯示</title> <link rel="stylesheet" href="http://cache.amap.com/lbs/static/main.css?v=1.0" /> <script src="http://webapi.amap.com/maps?v=1.3&key=您申請的key值"></script> </head> <body> <div id="mapContainer"></div> <script> navigator.geolocation.getCurrentPosition(geo_success, geo_error); function geo_success(position) { var map = new AMap.Map('mapContainer', { // 設置中心點 center: [position.coords.longitude, position.coords.latitude], // 設置縮放級別 zoom: 13 }); var marker = new AMap.Marker({ //復雜圖標 icon: new AMap.Icon({ //圖標大小 size: new AMap.Size(28, 37), //大圖地址 image: "http://webapi.amap.com/images/custom_a_j.png", imageOffset: new AMap.Pixel(-28, 0) }), //在地圖上添加點 position: [position.coords.longitude, position.coords.latitude] }); marker.setMap(map); } function geo_error(msg) { console.log(msg.code, msg.message); } </script> </body> </html>
在手機上打開后:
我的天哪!實在是太准了!如果我把代碼里的 zoom 參數再加大點,能精確到小區了...當然,這並不奇怪,因為這本來就是高德地圖百度地圖定位的一部分嘛。
事實上,getCurrentPosition() 還有第三個參數,該參數是一個選項對象,用於設定信息的類型。可以設置的選項有三個:enableHighAccuracy 是一個布爾值,表示必須盡可能使用最精確的位置信息;timeout 是以毫秒數表示的等待位置信息的最長時間;maximumAge 表示上一次取得的坐標信息的有效時間,以毫秒表示,如果時間到則重新取得新坐標信息。
除非確實需要非常精確的信息,否則建議保持 enableHighAccuracy 的 false 值(默認值)。將這個選項設置為 true 需要更長的時候,而且在移動設備上更耗電。類似的,如果不需要頻繁更新用戶的位置信息,那么可以將 maximumAge 設置為 Infinity,從而始終都使用上一次的坐標信息。
navigator.geolocation.getCurrentPosition(locationSuccess, locationError, {
// 指示瀏覽器獲取高精度的位置,默認為false enableHighAcuracy: true, // 指定獲取地理位置的超時時間,默認不限時,單位為毫秒 timeout: 5000, // 最長有效期,在重復獲取地理位置時,此參數指定多久再次獲取位置。 maximumAge: 3000 });
watchPosition() 方法
如果要跟蹤用戶的位置,那么可以使用 watchPosition() 方法。這個方法的使用和 getCurrentPosition() 完全相同。實際上 watchPosition() 與定時調用 getCurrentPosition() 能得到相同效果。在第一次調用 watchPosition() 方法后,會取得當前位置,執行成功回調或者錯誤回調。然后,watchPosition() 就地等待系統發出位置已改變的信號。
調用 watchPosition() 會返回一個數值標識符,用於跟蹤監控的操作。基於這個返回值可以取消監控操作,只要將其傳遞給 clearWatch() 方法即可(與使用 setTimeout() 和 clearTimeout() 類似),例如:
var watchId = navigator.geolocation.watchPosition(geo_success, geo_error); clearWatch(watchId);
Geolocation 定位原理
作者:Jesion Wang
鏈接:http://www.zhihu.com/question/20473051/answer/24069580
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
Geolocation API 的數據來源可能是 GPS、IP 地址、RFID、WiFi、藍牙 MAC 地址、GSM/CDMA 卡 ID 等。因為 Geolocation API 是運行在你本地設備上的。所以,在使用 VPN 或代理的情況下,Geo API 仍能獲得你准確的 IP 地址信息(除非因為某些因素瀏覽器獲取不到這些信息)。
The Geolocation API defines a high-level interface to location information associated only with the device hosting the implementation, such as latitude and longitude. The API itself is agnostic of the underlying location information sources. Common sources of location information include Global Positioning System (GPS) and location inferred from network signals such as IP address, RFID, WiFi and Bluetooth MAC addresses, and GSM/CDMA cell IDs, as well as user input. No guarantee is given that the API returns the device's actual location.
在HTML5的實現中,手機等移動設備當然優先使用GPS定位,而筆記本和部分平板,最准的定位是WIFI,至於網線上網的台式機,一般就只能使用IP來定位了,這個准確度最低。
首先來看chrome,很明顯,肯定是google自己提供的服務。通過chrome自帶的抓包方法(chrome://net-internals/)可以看到,在使用geolocation時,chrome向 www.googleapis.com/geolocation/v1/geolocate的接口發送了請求,由於請求用spdy加密過,所以看不出具體內容,只有一點可以確定,即wifi上網時,是post方式傳數據,而使用網線時,使用的是get。
firefox使用的也是google的服務,但是和chrome用的接口不同,這個是 https://maps.googleapis.com/maps/api/browserlocation/json
請求數據是:browser=firefox&sensor=true&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-43&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-43&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-43&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-44&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-60&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-61&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-62&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-63&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-63&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-67&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-67&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-67&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-67&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-74&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-82&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-84&wifi=mac:xx-xx-xx-xx-xx-xx%7Cssid:xxxxxxx%7Css:-85
這個就很清晰了,是周邊wifi設備的ssid、mac地址,以及信號強度。(公司網絡,路由名和mac地址隱去。)
對於不支持geolocation的瀏覽器,本來可以調用google的gears項目提供的接口來查詢地理位置,但是該服務目前2011年已經停止,暫時也沒有出現更好的替代方案。
參考資料
下面的參考資料非常有價值,
HTML5 中 Geolocation 獲取地理位置的原理是什么?
使用 HTML5 Geolocation 構建基於地理位置的 Web 應用
How HTML5 Geolocation Feature Works?