Geolocation :基于浏览器的定位服务
為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??
1. 關(guān)于 Geolocation 對象
隨著 Opera 10.6 和 Safari 5的相繼發(fā)布,截止到目前為止,W3C 中一個(gè)名為 Geolocation 的 API 規(guī)范在所有非 IE 瀏覽器中都得到了實(shí)現(xiàn)。簡單地說,Geoloaction 的作用就是通過瀏覽器感知用戶的地理位置。 如果說地理位置的感知已經(jīng)成為了一項(xiàng)成熟的技術(shù),那么緊接著的問題就是 Geolocation 存在的意義是什么?就我目前對 Geolocation 的理解,我認(rèn)為它存在的理由至少包含以下兩點(diǎn):
1. 公共數(shù)據(jù):目前的地理位置探測,其資料往往來源于服務(wù)商各自的數(shù)據(jù),而使用瀏覽器內(nèi)置的統(tǒng)一接口,將高效整合這一信息。?
2. 精確定位:無論是谷歌還是谷姐們,實(shí)現(xiàn)定位的原理無非是通過 IP 地址來探測用戶的所在位置,眾所周知,IP 的定位能力是比較差的,絕大多數(shù)情況下,它的精確度能達(dá)到數(shù)十公里就已經(jīng)不錯(cuò)了,除此之外,沒有別的任何辦法,無論是服務(wù)器端語言還是客戶端的 JavaScript 腳本,都無法從用戶那里獲取到更多對定位有所幫助的信息。然而作為用戶機(jī)器上更為底層的瀏覽器,它將有權(quán)利支配其他有助于定位的設(shè)備,比如 GPS 和 WIFI。GPS 大家都已經(jīng)很熟悉了,在信號良好的情況下,它可以精確到數(shù)米之內(nèi)。而 WIFI 在國內(nèi)基本上被廢了,對于這項(xiàng)技術(shù)普及的國家,WIFI 的定位基本上可以精確到百米左右,據(jù)說經(jīng)常可以見到一些公司的人,整天什么都不干,就開著小車到處晃,到一個(gè)熱點(diǎn)( Hot Spot ),就記錄下當(dāng)前的地理位置,然后傳回到公司的數(shù)據(jù)庫。
該對象位于我們非常熟悉的 Navigator 對象下面,可以通過 navigator.geolocation 來訪問,當(dāng)然前面也可以加上 window.。不支持 geolocation 的瀏覽器并不包含這一對象,那么可以通過下面的代碼來做能力檢測,對不同的瀏覽器做不同的處理。
if (navigator.geolocation) { alert( ' 你的瀏覽器支持 geolocation ' ); }else{ alert( ' 你的瀏覽器不支持 geolocation ' ) }在訪問 geolocation 對象時(shí),即調(diào)用 geolocation 下面的方法時(shí),瀏覽器會(huì)彈出提示,詢問用戶是否許可網(wǎng)站提供的位置服務(wù),只有在得到用戶許可過后,服務(wù)才會(huì)繼續(xù),否則將被停止,在稍后你將會(huì)了解到,我們能夠捕獲到用戶拒絕服務(wù)的動(dòng)作。下面這張圖分別是 Chrome , Firefox 和 Opera 在初次訪問 geolocation 時(shí),給用戶的提示:
2. 獲取當(dāng)前地理位置 --- getCurrentPosition
當(dāng)獲得用戶的許可過后,便一切就緒。我們將通過 geolocation 下的 getCurrentPosition 方法來獲取用戶的信息,這個(gè)方法是今天整篇文章的核心部分,也是 geolocation 一個(gè)非常重要的方法。
navigator.geolocation.getCurrentPosition( getPositionSuccess , getPositionError );在上面的代碼中,我們調(diào)用了 getCurrentPosition 方法,并為其傳遞了兩個(gè)參數(shù),事實(shí)上這個(gè)方法可以接受三個(gè)參數(shù),前兩個(gè)參數(shù)是函數(shù),最后一個(gè)是對象:第一個(gè)參數(shù)是成功獲取位置信息的回調(diào)函數(shù),它是方法唯一必須的參數(shù);第二個(gè)參數(shù)用于捕獲獲取位置信息出錯(cuò)的情況,第三個(gè)參數(shù)是配置項(xiàng)。
當(dāng)瀏覽器成功獲取到用戶的位置信息時(shí),getCurrentPosition 的第一個(gè)函數(shù)類型的參數(shù)將被調(diào)用,一個(gè) position 對象會(huì)被傳入到調(diào)用的函數(shù)中,這個(gè)對象中包含了瀏覽器傳回的數(shù)據(jù),這非常重要。
function getPositionSuccess( position ){ var lat = position.coords.latitude; var lng = position.coords.longitude; document.write( "您所在的位置: 經(jīng)度" + lat + ",緯度" + lng ); }是的,position 對象包含了用戶的地理位置信息,該對象下面的 coords 子對象包含了用戶所在的緯度和經(jīng)度信息,通過 position.coords.latitude 可以訪問緯度,而 position.coords.longitude 中存放了經(jīng)度的信息,用戶的位置信息越精確,這兩個(gè)數(shù)字后面的小數(shù)點(diǎn)越長。事實(shí)上,在?Firefox?中,position 對象下還附帶有另一個(gè) address 對象,這個(gè)對象包含這個(gè)經(jīng)緯度下的國家名,城市名甚至街道名。
function getPositionSuccess( position ){ var lat = position.coords.latitude; var lng = position.coords.longitude; alert( "您所在的位置: 經(jīng)度" + lat + ",緯度" + lng ); if(typeof position.address !== "undefined"){ var country = position.address.country; var province = position.address.region; var city = position.address.city; alert(' 您位于 ' + country + province + '省' + city +'市'); } }錯(cuò)誤捕獲:上面都是成功獲取到用戶位置信息的處理,但是出現(xiàn)問題的情況在所難免,當(dāng)獲取用戶的位置信息出錯(cuò)時(shí),傳遞到 getCurrentPosition 的第二個(gè)函數(shù)類型參數(shù)被調(diào)用,一個(gè)包含具體出錯(cuò)信息的對象會(huì)被傳遞進(jìn)去,錯(cuò)誤將被捕獲。
function getPositionError(error){ switch(error.code){ case error.TIMEOUT : alert( " 連接超時(shí),請重試 " ); break; case error.PERMISSION_DENIED : alert( " 您拒絕了使用位置共享服務(wù),查詢已取消 " ); break; case error.POSITION_UNAVAILABLE : alert( " 親愛的火星網(wǎng)友,非常抱歉,我們暫時(shí)無法為您所在的星球提供位置服務(wù) " ); break; } } error 對象下面,存放了3個(gè)常量:
TIMEOUT?表示獲取信息超時(shí)。
PERMISSION_DENIED?表示用戶選擇了拒絕了位置服務(wù)。
POSITION_UNAVAILABLE?表示位置不可知。
而每一次出錯(cuò)時(shí) error.code 將指向3個(gè)常量之中的一個(gè)。
配置項(xiàng):getCurrentPosition 方法的第三個(gè)參數(shù)是一個(gè)對象,該對象影響了獲取位置時(shí)的一些細(xì)節(jié)。
enableHighAccuracy,它將告訴瀏覽器是否啟用高精度設(shè)備,所謂的高精度設(shè)備包含但不局限于前面所提到的 GPS 和 WIFI,值為 true 的時(shí)候,瀏覽器會(huì)嘗試啟用這些設(shè)備,默認(rèn)指為 true,在這種情況下,瀏覽器會(huì)盡可能地進(jìn)行更為精確的查詢,簡單地說,如果用戶有可用的 GPS 設(shè)備,會(huì)返回 GPS 設(shè)備的查詢結(jié)果,IP 是最后的選擇,對于移動(dòng)設(shè)備來說,網(wǎng)絡(luò)接入點(diǎn)(基站)或許成為另一個(gè)選擇,對此我還沒有完全了解,但根據(jù)測試,即時(shí)沒有任何額外功能的手機(jī),也能夠得到更為精確的查詢結(jié)果。
timeout,超時(shí),獲取位置信息時(shí)超出設(shè)定的這個(gè)時(shí)長,將會(huì)觸發(fā)錯(cuò)誤,捕獲錯(cuò)誤的函數(shù)將被調(diào)用,并且錯(cuò)誤碼指向TIMEOUT。
這樣我們嘗試修改調(diào)用 getCurrentPosition 時(shí)傳遞的參數(shù)
3. 持續(xù)追蹤位置 --- watchPosition
對于使用移動(dòng)設(shè)備的用戶來說,位置并不是固定的,W3C 當(dāng)然也考慮到了這一點(diǎn),watchPosition 是一個(gè)專門用來處理這一情況的方法,watchPosition 被調(diào)用后,瀏覽器會(huì)跟蹤設(shè)備的位置,每一次位置的變化,watchPosition 中的代碼都將會(huì)被執(zhí)行。對于致力于移動(dòng)設(shè)備 web 開發(fā)的同學(xué)來說,這個(gè)方法是及其重要的,它也許將會(huì)改變 web 移動(dòng)客戶端的格局。
navigator.geolocation.watchPosition( refreshPosition );上面的代碼表示,但設(shè)置位置發(fā)生改變時(shí),refreshPosition 將會(huì)被調(diào)用。事實(shí)上 watchPosition 和 getCurrentPosition 幾乎一模一樣,同樣包含了一個(gè)成功獲取位置的回調(diào)函數(shù),一個(gè)獲取失敗的回調(diào)函數(shù)和一個(gè)配置項(xiàng),區(qū)別僅僅是在觸發(fā)的時(shí)機(jī)上。所以具體的方法就不再重復(fù)了。上面的代碼表示在每一次位置發(fā)生改變時(shí),調(diào)用 refreshPosition 函數(shù)。
4. 實(shí)例 --- 與 Google Map 交互
接下來,我們通過一個(gè)實(shí)例,來具體應(yīng)用一下 Geolocation ,實(shí)例的最終效果是,獲取用戶的位置,并通過 Google Map 在地圖上標(biāo)記出來,當(dāng)用戶的位置發(fā)生改變后,更新之前在地圖上的標(biāo)記到新的位置。首先我們準(zhǔn)備好 DOM,并加載 Google Map
<!-- 按鈕,被點(diǎn)擊時(shí)開始獲取用戶位置信息 --> <input type="button" id="getPos" value="獲取我的位置" /> <!-- 用來存放反饋給用戶信息的 div --> <div id="info"></div> <!-- 為 Google Map 準(zhǔn)備 --> <div id="map"></div> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false" ></script>接下來我們在 JavaScript 中獲取這些 DOM,并為 Google Map 提供一個(gè)對象用來存放地圖和標(biāo)記。這些都是準(zhǔn)備工作,很煩,但是不得不做。
var dom = { btn : document.getElementById('getPos'), info : document.getElementById('info'), map : document.getElementById('map') }; var gmap = { map : null, marker : null }接下來監(jiān)聽按鈕的事件,當(dāng)按鈕被點(diǎn)擊的時(shí)候,將觸發(fā)獲取用戶的位置信息。在這里我們對瀏覽器進(jìn)行了檢測,如果不支持 Geolocation 接口,將提示用戶,并停止進(jìn)一步的動(dòng)作。
dom.btn.onclick = function(){ if (navigator.geolocation) { dom.info.innerHTML = "請等待查詢結(jié)果返回"; dom.info.className = "warn"; navigator.geolocation.getCurrentPosition(getPositionSuccess,getPositionError,{timeout:5000}); }else { dom.info.innerHTML = "抱歉,您所使用的瀏覽器不支持 Geolocation 接口"; dom.info.className = "warn"; } }在上面我們向 getCurrentPosition 傳遞了兩個(gè)函數(shù),現(xiàn)在我們來具體寫這兩個(gè)函數(shù),首先是 getPositionSuccess ,當(dāng)成功獲取到用戶的位置信息時(shí),這個(gè)函數(shù)被調(diào)用,我們將在這時(shí)更新頁面上的顯示值,并配置追蹤用戶的位置的函數(shù),最后調(diào)用 Google Map 的 API 在 id 為 map 的 div 中顯示地圖,并在地圖上標(biāo)記出用戶的當(dāng)前位置。
function getPositionSuccess(position){ var lat = position.coords.latitude; var lng = position.coords.longitude; dom.info.innerHTML = "您所在的位置: 經(jīng)度" + lat + ",緯度" + lng; navigator.geolocation.watchPosition(refreshPosition); // 載入 Google 地圖 var latlng = new google.maps.LatLng(lat, lng); var myOptions = { zoom : 16, center : latlng, mapTypeId : google.maps.MapTypeId.ROADMAP }; gmap.map = new google.maps.Map(document.getElementById("map"), myOptions); // 向地圖中添加標(biāo)記 gmap.marker = new google.maps.Marker({ position: latlng, map: gmap.map }); }對于錯(cuò)誤處理的函數(shù),則非常簡單,可以參看前面的內(nèi)容。我們來關(guān)注一下追蹤位置的函數(shù),在這個(gè)函數(shù)中,我們實(shí)時(shí)更新顯示信息,并更新地圖到用戶所處的位置。
function refreshPosition(position){ var lat = position.coords.latitude; var lng = position.coords.longitude; var latlng = new google.maps.LatLng(lat, lng); // 重設(shè)地圖位置 gmap.map.setCenter(latlng); dom.info.innerHTML = '您所在的位置: 經(jīng)度' + lat ' + ',緯度' + lng; // 重設(shè)標(biāo)記位置 gmap.marker.setOptions({ position: new google.maps.LatLng(lat, lng) }); }以上關(guān)于 Google Map 的代碼不是很了解的同學(xué)可以到 Google Code 去看一下 手冊,這里只是很簡單的應(yīng)用,有興趣的同學(xué)可以進(jìn)一步延伸。下面是這個(gè) Demo 的最終效果。
轉(zhuǎn)載于:https://my.oschina.net/lisn/blog/129549
總結(jié)
以上是生活随笔為你收集整理的Geolocation :基于浏览器的定位服务的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 游戏id取名鬼才好听又搞笑名字798个
- 下一篇: React 中的不可变数据 — Imme