答客問-使用google.maps.Geocoder()轉換地址
11 |
前幾天談了Google Maps API地址轉換,Ammon提醒其實Google Maps API也有提供從Javascript端進行地理編碼的做法,可以全部在Client端處理完成,不需動用ashx。另外,chester希望能有使用純Javascript進行地址轉換的範例,所以,範例來了!
本次的程式幾乎跟上次完全相同,只改寫了geocodeAjax()函數而已。原本的做法是呼叫ashx,這次則改用goole.maps.Geocoder(),透過Geocoder.geocode(request, callbackFunction)進行地理編碼。由於是透過callbackFunction以非同步方式傳回結果,因此要仿效$.ajax()傳回Deferred.promise()以實現全部結果都傳回後才開始繪製地圖的效果。
另外,實測時發現Geocoder()似乎會管控使用量,如果不間斷地連續呼叫一陣子後便會停擺,為此我加入setTimeout模擬延遲,讓每次查詢時間間隔一秒,最後才順利把44筆都查完。
程式碼如下: (其實只要看geocodeAjax()就好,其他的沒改)
<!DOCTYPE html>
<html>
<head runat="server">
<title>Geocoding Test</title>
<script type='text/javascript'
src='http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.js'></script>
<script src="https://maps.google.com/maps/api/js?sensor=true"></script>
<script src="DynaMarkerIcon.js" type="text/javascript"></script>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style>
body,input { font-size: 9pt; }
html { height: 100% }
body { height: 100%; margin: 0px; padding: 0px }
#map_canvas { height: 100% }
</style>
<script>
$(function () {
var markers = [];
geocoder = new google.maps.Geocoder();
var c = 0;
//透過Google Geocoder將地址轉為經緯座標
function geocodeAjax(name, addr) {
//利用Deferred物件協助非同步呼叫全部完成的時機
var def = new jQuery.Deferred();
//geocoder似乎有使用量管控,若快速連續呼叫會停止運作
//在此使用setTimeout節流,每次查詢間隔一秒鐘
setTimeout(function() {
//呼叫decode(),傳入參數及Callback函數
geocoder.geocode({ address: addr }, function (results, status) {
//檢查執行結果
if (status == google.maps.GeocoderStatus.OK) {
var loc = results[0].geometry.location;
markers.push({
title: name + "@" + addr,
latlng: new google.maps.LatLng(loc.lat(), loc.lng())
});
//呼叫Deferred.resolve(),表示執行成功
def.resolve();
}
else
{
//呼叫Deferred.reject(),表示執行失敗
def.reject();
}
});
}, c++ * 1000);
//傳回Promise物件,以協調非同步呼叫結果
return def.promise();
}
$.get("AddrList.txt", {}, function (list) {
var lines = list.replace(/\r/g, "").split('\n');
var deferredArray = [];
//lines[i]格式如下:
//中正中隊-華山分隊,(02)23412668,中正區北平東路1號
for (var i = 0; i < lines.length; i++) {
var parts = lines[i].split(',');
//以AJAX進行地址轉換,並將$.ajax() deferred物件放入陣列中
deferredArray.push(geocodeAjax(parts[0], parts[2], lines[i]));
}
//利用Deferred特性,在所有地址轉換呼叫完畢後,繪製地圖
$.when.apply(null, deferredArray).then(function () {
//設定地圖參數
var mapOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP //正常2D道路模式
};
//在指定DOM元素中嵌入地圖
var map = new google.maps.Map(
document.getElementById("map_canvas"), mapOptions);
//使用LatLngBounds統計檢視範圍
var bounds = new google.maps.LatLngBounds();
//加入標示點(Marker)
for (var i = 0; i < markers.length; i++) {
var m = markers[i];
//將此座標納入檢視範圍
bounds.extend(m.latlng);
var marker = new google.maps.Marker({
position: m.latlng,
title: m.title,
map: map
});
}
//調整檢視範圍
map.fitBounds(bounds);
});
});
});
</script>
</head>
<body>
<div id="map_canvas" style="width:100%; height:100%"></div>
</body>
</html>
執行結果如下圖,還順便用HttpWatch偷窺了查詢過程的網路封包,發現Geocoder()背後在呼叫maps/api/js/GeocodeService.Search?…進行查詢,而傳回結果中的"_xdc_._fw7f14 && _xdc_._wf7f14({ … })"明白地告訴我們,Google也是用JSONP處理跨網域API結果傳遞需求的啦! (筆記)
Comments
# by chester
Great!非常感謝!學習了!
# by Ammon
之前為了某案上千筆資料查詢寫了個批次處理,放到 jsFiddler 上供大家使用。 http://goo.gl/O6fxW
# by ray
你好,我是初學的,我試將以上的copy在網頁上,但失敗, 請問可否寄給我完整的demo檔案?謝謝 ray453523@gmail.com
# by Jeffrey
to ray, 我放了一個線上展示(http://www.darkthread.net/miniajaxlab/googlemap/lab5.htm),因為每一秒只查一筆的闗係(加上我偷懶沒寫查詢進度顯示),要有點耐心等幾十秒結果才會出現。程式用到的DynaMarkerIcon.js跟AddrList.txt可以由該網址下載。
# by Liou
我複製了你的展示上的程式碼 可是我執行後卻說 36行29字元 必須要有識別項!! 怎麼會這樣?
# by Jeffrey
to Liou, 原來的程式寫法在IE7執行有問題,請將"latlng: new google.maps.LatLng(loc.lat(), loc.lng()), "最後方的","刪除,應可解決問題。本文的程式碼已修改,感謝回饋。
# by Wolf
謝謝大大的文章~ 受益良多!
# by 謝尚明
想學習能自動取得經緯度後將以圖面及中文地址呈現,能否教導指點
# by Jeffrey
to 謝尚明, 我找到一個呈現中文地址的範例:http://kuro.tw/posts/2015/04/27/address-information-is-obtained-through-google-map-geocoder-with-the-latitude-and-longitude
# by 大鼻子
您好 最近在找尋座標轉為門牌地址的方式,並在網上看到您寫的這篇文章。想請問一下,不知您近期您是否還有使用過MAP API相關服務?是否現在使用此類功能均須要先申請API KEY的權限呢?如果說我想要批次將手上座標轉為門牌地址是否相關功能呢!!有看過您提供的這個範例,但是否無法進行批次處理呢 謝謝您 耐心看完我的提問
# by Jeffrey
to 大鼻子, 我很久沒接觸地圖應用了,依我所知 Goggle MAP API 這些年大幅改版過,對於新版 API 我沒啥經驗,恐幫不上忙。