我們已於 2021 年 5 月 26 日停止提供 Maps JavaScript API 第 2 版。因此,您網站的 2 版地圖會停止運作,並傳回 JavaScript 錯誤。如要繼續在您的網站上使用地圖,請遷移至 Maps JavaScript API 3 版。本指南將協助您完成整個程序。
總覽
每個應用程式的遷移程序略有不同,但以下幾個步驟適用於所有專案:
- 取得新的金鑰。Maps JavaScript API 現在會使用 Google Cloud 控制台管理金鑰。如果您仍在使用第 2 版的金鑰,請務必取得新的 API 金鑰再開始遷移。
- 更新 API Bootstrap。大多數應用程式會使用下列程式碼載入 Maps JavaScript API 第 3 版:
<script src="//maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
- 更新程式碼。需要變更的幅度主要取決於應用程式。常見的變更包括:
- 一律參照 google.maps 命名空間。在第 3 版中,所有 Maps JavaScript API 程式碼都會儲存在
google.maps.*
命名空間,而非全域命名空間。在這項程序中,大多數的物件也已重新命名。舉例來說,您現在可以載入 google.maps.Map
,而不是 GMap2
。
- 移除過時方法的所有參照。已移除多個一般用途的公用程式方法,例如
GDownloadURL
和 GLog
。請將這項功能替換為第三方公用程式庫,或是從程式碼中移除這些參照。
- (選用) 在程式碼中新增程式庫。許多功能已外部化為公用程式庫,因此每個應用程式只需載入要使用的 API 部分。
- (選用) 將專案設為使用第 3 版的外部值。第 3 版外部程式庫可用來透過 Closure Compiler 來驗證程式碼,或在 IDE 中觸發自動完成功能。進一步瞭解
進階編譯與 Externs。
- 反覆測試。此時您還需完成一些工作,但好消息是,您已經能順利使用新的第 3 版地圖應用程式了!
Maps JavaScript API 第 3 版中的變更
規劃遷移作業前,請先花點時間瞭解 Maps JavaScript API 第 2 版與 Maps JavaScript API 第 3 版之間的差異。最新版 Maps JavaScript API,經過重新設計,著重於現代 JavaScript 程式設計技術、增加程式庫的使用率,以及簡化的 API。API 也加入許多新功能,並變更或甚至移除幾項熟悉的功能。本節重點介紹兩個版本之間的部分主要差異。
第 3 版 API 中的部分變更包括:
- 簡化的核心程式庫。許多補充函式已移至「程式庫」,以縮短 Core API 的載入和剖析時間,因此地圖可在任何裝置上快速載入。
- 改善多項地圖項目的效能,例如多邊形算繪和標記位置。
- 全新的用戶端用量限制方法,能更好地因應行動 Proxy 和公司防火牆所用的共用位址。
- 新增多種新式瀏覽器的支援和行動瀏覽器。已停止支援 Internet Explorer 6。
- 移除許多一般用途的輔助類別 (
GLog
或
GDownloadUrl
)。現在有許多優秀的 JavaScript 程式庫提供類似功能,例如 Closure 或 jQuery。
- 街景服務導入了 HTML5 技術,因此在任何行動裝置上都能載入這項服務。
- 自訂街景服務全景圖,可讓您分享滑雪坡道、待售房屋或其他有趣地點的全景。
- 樣式化地圖自訂項目可讓您變更基本地圖元素的顯示方式,以配合您的獨特視覺風格。
- 支援多種新服務,例如 ElevationService 和距離矩陣。
- 改良版路線規劃服務提供了替代路線、路線最佳化服務 (有關
旅行銷售員問題的概略解決方案)、單車路線 (包含
單車圖層)、大眾運輸路線和
可拖曳的路線。
- 更新地理編碼格式,提供比 Geocoding API 第 2 版
accuracy
值更準確的類型資訊。
- 支援單一地圖上的多個資訊視窗
新的金鑰
Maps JavaScript API 第 3 版採用第 2 版的新金鑰系統。您可能已在應用程式中使用 v3 金鑰,因此不必進行任何變更。如要確認,請查看您載入 Maps JavaScript API 的網址,確認是否包含 key
參數。如果鍵/值的開頭是「ABQIAA」,表示使用的是第 2 版金鑰。如果您有第 2 版的金鑰,必須在遷移期間升級至 v3 金鑰,這項操作會:
- 您可以在 Google Cloud 控制台中監控 API 用量。
- 如有需要,您也可以購買額外配額。
- 方便 Google 就您的應用程式相關問題與您聯絡。
系統會在載入 Maps JavaScript API 第 3 版時傳送金鑰。進一步瞭解如何產生 API 金鑰。
請注意,如果您是 Google Maps API for Work 客戶,那麼您也許會將用戶端 ID 與 client
參數搭配使用,而非使用 key
參數。Maps JavaScript API 第 3 版仍支援用戶端 ID,無須執行金鑰升級程序。
載入 API
您必須對程式碼進行的第一次修改涉及載入 API 的方式。在第 2 版中,您可以透過傳送至 http://maps.google.com/maps
的要求載入 Maps JavaScript API。如要載入 Maps JavaScript API 第 3 版,請務必進行下列變更:
- 從「
//maps.googleapis.com/maps/api/js
」載入 API
- 移除
file
參數。
- 使用新的 v3 金鑰更新
key
參數。Google Maps API for Work 客戶應使用 client
參數。
- (僅限 Google 地圖平台付費方案) 請務必按照《
Google 地圖平台付費方案開發人員指南》中的說明提供
client
參數。
- 移除
v
參數以要求最新版本,或根據 v3 版本管理配置變更其值。
- (選用) 將
hl
參數替換為 language
,並保留其值。
- (選用) 新增
libraries
參數,以便載入選用程式庫。
在最單純的情況下,第 3 版的 Bootstrap 只會指定 API 金鑰參數:
<script src="//maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
下方範例會要求德文的最新版 Maps JavaScript API 第 2 版:
<script src="//maps.google.com/maps?file=api&v=2.x&key=YOUR_API_KEY&hl=de"></script>
下方範例針對第 3 版提出相同要求。
<script src="//maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&language=de"></script>
導入 google.maps 命名空間
在 Maps JavaScript API 第 3 版中,最明顯的差異應該就是 google.maps
命名空間的簡介。根據預設,第 2 版 API 會將所有物件放在全域命名空間中,因此可能導致命名衝突。在 v3 中,所有物件都位於 google.maps
命名空間中。
將應用程式遷移至第 3 版時,您必須變更程式碼才能使用新的命名空間。很抱歉,搜尋「G」並取代為「google.maps.」並無法完全正常運作。不過,在檢查程式碼時,請務必以經驗法則為準。以下是第 2 版和第 3 版中相同類別的範例。
v2 |
v3 |
GMap2 |
google.maps.Map |
GLatLng |
google.maps.LatLng |
GInfoWindow |
google.maps.InfoWindow |
GMapOptions |
google.map.MapOptions |
G_API_VERSION |
google.maps.version |
GPolyStyleOptions |
google.maps.PolygonOptions or
google.maps.PolylineOptions |
移除過時的程式碼
Maps JavaScript API 第 3 版在第 2 版大部分的功能皆有平行運作,但有些類別已不受支援。遷移時,請將這些類別換成第三方公用程式庫,或是從程式碼中移除這些參照。目前有許多優秀的 JavaScript 程式庫提供類似功能,例如 Closure 或 jQuery。
在 Maps JavaScript API 第 3 版中,下列類別沒有平行:
GBounds | GLanguage |
GBrowserIsCompatible | GLayer |
GControl | GLog |
GControlAnchor | GMercatorProjection |
GControlImpl | GNavLabelControl |
GControlPosition | GObliqueMercator |
GCopyright | GOverlay |
GCopyrightCollection | GPhotoSpec |
GDownloadUrl | GPolyEditingOptions |
GDraggableObject | GScreenOverlay |
GDraggableObjectOptions | GStreetviewFeatures |
GFactualGeocodeCache | GStreetviewLocation |
GGeoAddressAccuracy | GStreetviewOverlay |
GGeocodeCache | GStreetviewUserPhotosOptions |
GGoogleBar | GTileLayerOptions |
GGoogleBarAdsOptions | GTileLayerOverlayOptions |
GGoogleBarLinkTarget | GTrafficOverlayOptions |
GGoogleBarListingTypes | GUnload |
GGoogleBarOptions | GXml |
GGoogleBarResultList | GXmlHttp |
GInfoWindowTab | GXslt |
GKeyboardHandler |
|
比較程式碼
接著來比較使用第 2 版和第 3 版 API 編寫的兩個較簡單應用程式。
<!DOCTYPE html>
<html>
<head>
<script src="//maps.google.com/maps?file=api&v=2&key=YOUR_API_KEY"></script>
<style>
html, body, #map { height: 100%; margin: 0; }
</style>
<script>
function initialize() {
if (GBrowserIsCompatible()) {
var map = new GMap2(
document.getElementById('map'));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
map.setUIToDefault();
map.addOverlay(new GMarker(new GLatLng(37.4419, -122.1419)));
}
}
</script>
</head>
<body >
<div id="map"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script src="//maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
<style>
html, body, #map { height: 100%; margin: 0; }
</style>
<script>
function initialize() {
var map = new google.maps.Map(
document.getElementById('map'), {
center: new google.maps.LatLng(37.4419, -122.1419),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var marker = new google.maps.Marker({
position: new google.maps.LatLng(37.4419, -122.1419),
map: map
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>
如您所見,這兩個應用程式之間有一些差異。明顯的改變包括:
- 載入 API 的位址已變更。
- 第 3 版不再需要
GBrowserIsCompatible()
和 GUnload()
方法,且已從 API 中移除。
GMap2
物件會由 google.maps.Map
取代,做為 API 中的中心物件。
- 屬性現在是透過 Options 類別載入。在上述範例中,我們透過內嵌的
MapOptions
物件設定載入地圖所需的三個屬性,包括 center
、zoom
和 mapTypeId
。
- 根據預設,第 3 版會啟用預設使用者介面。如要停用此功能,您可以在
MapOptions
物件中將 disableDefaultUI
屬性設為 true。
摘要
現階段,您已經瞭解從 Maps JavaScript API 第 2 版遷移至第 3 版時考量的一些重點。您可能還需要知道其他資訊,但這取決於您的應用程式。以下各節針對您可能遇到的特定情況,提供了遷移操作說明。另外,在升級過程中,還有一些資源可能對您有所幫助。
如果您對這篇文章有任何疑問或疑問,請點選本頁頂端的「提供意見」連結。
本節詳細比較 Maps JavaScript API 第 2 版和第 3 版最常用的功能。參考資料中的每個區段都設計為可供單獨閱讀。建議您不要完整閱讀本參考資料,而是視情況使用這些內容來協助您完成遷移作業。
- 事件 - 註冊及處理事件。
- 控制項 - 操控地圖上顯示的導覽控制項。
- 疊加層 - 在地圖上新增及編輯物件。
- 地圖類型 - 構成基本地圖的圖塊。
- 圖層:以群組的形式新增和編輯內容,例如 KML 或路況圖層。
- 服務 - 使用 Google 的地理編碼、路線或街景服務。
活動
Maps JavaScript API 第 3 版的事件模型與第 2 版相似,但實際上已有部分變更。
支援 MVC 的新事件
第 3 版 API 添加了一個新的事件類型,以反映 MVC 狀態變更。事件分為兩種類型:
- 使用者事件 (例如「點擊」滑鼠事件) 會從 DOM 傳播至 Maps JavaScript API。這些事件與標準 DOM 事件不同。
- MVC 狀態變更通知會反映 Maps API 物件的變更,並採用
property_changed
慣例命名。
每個 Maps API 物件匯出一系列具名的事件。對特定事件感興趣的應用程式應為這些事件註冊事件監聽器,並在接收到這些事件時執行程式碼。這項事件導向機制與 Maps JavaScript API 第 2 版和第 3 版相同,只是命名空間已從 GEvent
變更為 google.maps.event
:
GEvent.addListener(map, 'click', function() {
alert('You clicked the map.');
});
google.maps.event.addListener(map, 'click', function() {
alert('You clicked the map.');
});
移除事件監聽器
基於效能考量,如果不再需要事件監聽器,最好將其移除。移除事件監聽器的運作方式與第 2 版和第 3 版相同:
- 建立事件監聽器時,系統會傳回不透明物件 (第 2 版中的 GEventListener,第 3 版中的 MapsEventListener)。
- 如要移除事件監聽器,請將這個物件傳遞至
removeListener()
方法 (第 2 版中的 GEvent.removeListener()
在第 3 版中的 google.maps.event.removeListener()
) 以移除事件監聽器。
監聽 DOM 事件
如要擷取及回應 DOM (文件物件模型) 事件,v3 會提供 google.maps.event.addDomListener()
靜態方法,相當於第 2 版的 GEvent.addDomListener()
方法。
在事件中使用傳遞的引數
UI 事件通常會傳遞事件引數,以便事件監聽器存取該引數。第 3 版中的多數事件引數已經過簡化,讓 API 中的物件更加一致。(詳情請參閱 v3 參考資料)。
v3 事件監聽器中不存在 overlay
引數。如果在第 3 版地圖中登錄 click
事件,只有在使用者點選基本地圖時,系統才會發出回呼。如果您需要回應這類點擊,可以在可點擊的疊加層上註冊其他回呼。
// Passes an overlay argument when clicking on a map
var map = new GMap2(document.getElementById('map'));
map.setCenter(new GLatLng(-25.363882, 131.044922), 4);
map.setUIToDefault();
GEvent.addListener(map,'click', function(overlay, latlng) {
if (latlng) {
var marker = new GMarker(latlng);
map.addOverlay(marker);
}
});
// Passes only an event argument
var myOptions = {
center: new google.maps.LatLng(-25.363882, 131.044922),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map'),
myOptions);
google.maps.event.addListener(map, 'click', function(event) {
var marker = new google.maps.Marker({
position: event.latLng,
map: map
});
});
控制項
Maps JavaScript API 會顯示 UI 控制項,讓使用者能與地圖互動。您可以使用 API 自訂這些控制項的顯示方式。
控制項類型的變更
第 3 版 API 已對 control
類型進行部分變更。
- 第 3 版 API 支援其他地圖類型,包括地形地圖和新增自訂地圖類型的功能。
- 第 2 版階層式控制項
GHierarchicalMapTypeControl
已無法使用。只要使用 google.maps.MapTypeControlStyle.HORIZONTAL_BAR
控制項,就能達到類似的效果。
- 第 2 版中
GMapTypeControl
提供的水平版面配置不適用於第 3 版。
在地圖中加入控制項
在 Maps JavaScript API 第 2 版中,您可以透過地圖物件的 addControl()
方法,在地圖中加入控制項。在第 3 版中,您可以修改相關聯的 MapOptions
物件,不必直接存取或修改控制項。以下範例說明如何自訂地圖,並新增下列控制項:
var map = new GMap2(document.getElementById('map'));
map.setCenter(new GLatLng(-25.363882, 131.044922), 4);
// Add controls
map.addControl(new GMapTypeControl());
map.addControl(new GScaleControl());
var myOptions = {
center: new google.maps.LatLng(-25.363882, 131.044922),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP,
// Add controls
mapTypeControl: true,
scaleControl: true
};
var map = new google.maps.Map(document.getElementById('map'),
myOptions);
在地圖上放置控制項
放置控制項功能在第 3 版中有大幅變更。在第 2 版中,addControl()
方法使用選用的第二個參數,讓您指定控制項相對於地圖角落的位置。
在第 3 版中,您可以透過控制項選項的 position
屬性設定控制項的位置。這些控制項並沒有固定位置,API 會聰明地安排這些控制項在指定限制內 (例如地圖大小) 周圍,巧妙地在現有地圖元素周圍「流動」。這可確保預設控制項與您的控制項相容。
詳情請參閱「在第 3 版中控制位置」。
下列程式碼重新設定上述範例的控制項位置:
var map = new GMap2(document.getElementById('map'));
map.setCenter(new GLatLng(-25.363882, 131.044922), 4);
// Add map type control
map.addControl(new GMapTypeControl(), new GControlPosition(
G_ANCHOR_TOP_LEFT, new GSize(10, 10)));
// Add scale
map.addControl(new GScaleControl(), new GControlPosition(
G_ANCHOR_BOTTOM_RIGHT, new GSize(20, 20)));
var myOptions = {
center: new google.maps.LatLng(-25.363882, 131.044922),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP,
// Add map type control
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.TOP_LEFT
},
// Add scale
scaleControl: true,
scaleControlOptions: {
position: google.maps.ControlPosition.BOTTOM_RIGHT
}
};
var map = new google.maps.Map(document.getElementById('map'),
myOptions);
自訂控制項
Maps JavaScript API 可讓您建立自訂導覽控制項。如要使用第 2 版 API 自訂控制項,您需要將 GControl
類別設為子類別,並定義 initialize()
和 getDefaultPosition()
方法的處理常式。第 3 版中沒有對應的 GControl
類別。而會以 DOM 元素表示。如要使用第 3 版 API 新增自訂控制項,請在建構函式中為控制項建立 DOM 結構,做為 Node
的子項 (例如 <div>
元素),並新增事件監聽器以處理任何 DOM 事件。將 Node
推送至地圖的 controls[position]
陣列,將自訂控制項的例項新增至地圖。
導入 HomeControl
類別,且該類別符合上述介面規定 (詳情請參閱「自訂控制項」說明文件),以下程式碼範例將說明如何在地圖中加入自訂控制項。
map.addControl(new HomeControl(),
GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10, 10)));
var homeControlDiv = document.createElement('DIV');
var homeControl = new HomeControl(homeControlDiv, map);
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(
homeControlDiv);
重疊說明
疊加層會反映您在地圖中加入的物件,用以指派點線、區域或物件集合。
新增與移除疊加層
疊加層表示的物件類型在第 2 版和第 3 版相同,但兩者的處理方式不同。
在第 2 版 API 中,系統會使用 GMap2
物件的 addOverlay()
和 removeOverlay()
方法,在地圖上加入或移除疊加層。在第 3 版中,您可以透過關聯疊加層選項類別的 map
屬性,將地圖指派給疊加層。您也可以呼叫疊加層物件的 setMap()
方法,然後指定所需的地圖,直接新增或移除疊加層。將地圖屬性設為 null
即可移除疊加層。
第 3 版中沒有任何 clearOverlays()
方法。如要管理一組疊加層,應建立陣列來存放疊加層。使用這個陣列後,您就可以在陣列中的每個疊加層上呼叫 setMap()
(如需移除,請傳遞 null
)。
可拖曳的標記
根據預設,標記可供點擊但不可拖曳。以下兩個範例說明如何新增可拖曳標記:
var myLatLng = new GLatLng(-25.363882, 131.044922);
var map = new GMap2(document.getElementById('map'));
map.setCenter(myLatLng, 4);
var marker = new GMarker(latLng, {
draggable: true
});
map.addOverlay(marker);
var myLatLng = new google.maps.LatLng(-25.363882, 131.044922);
var map = new google.maps.Map(
document.getElementById('map'), {
center: myLatLng,
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var marker = new google.maps.Marker({
position: myLatLng,
draggable: true,
map: map
});
圖示
您可以定義要顯示的自訂圖示,以取代預設標記。如要在第 2 版中使用自訂映像檔,您可以從 G_DEFAULT_ICON type
建立 GIcon
例項並進行修改。如果您的圖片大於或小於預設圖示,您必須使用 GSize
執行個體來指定圖片。第 3 版 API 則將這個程序略微簡化。
只要將標記的 icon
屬性設為自訂圖片的網址,API 就會自動調整圖示大小。
Maps JavaScript API 也支援複雜圖示。複雜的圖示可以包含多個圖塊、複雜的形狀,或指定圖片相對於其他疊加層的顯示方式「堆疊順序」。如要在第 2 版的標記中加入形狀,您必須在每個 GIcon
例項中指定額外屬性,並以選項的形式傳遞至 GMarker
建構函式。在第 3 版中,用這種方式指定的圖示應將其 icon
屬性設為 Icon
類型的物件。第 3 版不支援標記陰影。
以下範例顯示澳洲邦迪海灘 (Bondi Beach) 的海灘旗幟,圖示的透明部分不可點擊:
var map = new GMap2(document.getElementById('map'));
map.setCenter(new GLatLng(-25.363882, 131.044922), 4);
map.setUIToDefault();
var flagIcon = new GIcon(G_DEFAULT_ICON);
flagIcon.image = '/images/beachflag.png';
flagIcon.imageMap = [1, 1, 1, 20, 18, 20, 18 , 1];
var bbLatLng = new GLatLng(-33.890542, 151.274856);
map.addOverlay(new GMarker(bbLatLng, {
icon: flagIcon
}));
var map = new google.maps.Map(
document.getElementById('map'), {
center: new google.maps.LatLng(-25.363882, 131.044922),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var shape = {
coord: [1, 1, 1, 20, 18, 20, 18 , 1],
type: 'poly'
};
var bbLatLng = new google.maps.LatLng(-33.890542, 151.274856);
var bbMarker = new google.maps.Marker({
icon: '/images/beachflag.png'
shape: shape,
position: bbLatLng,
map: map
});
折線
折線包含 LatLng
的陣列,以及一組依序連接這些地點的一系列線段。在第 3 版建立並顯示 Polyline
物件,與在第 2 版使用 GPolyline
物件類似。下列範例可繪製從蘇黎世到雪梨到新加坡的半透明測地折線 3 像素寬且半透明折線:
var polyline = new GPolyline(
[
new GLatLng(47.3690239, 8.5380326),
new GLatLng(1.352083, 103.819836),
new GLatLng(-33.867139, 151.207114)
],
'#FF0000', 3, 0.5, {
geodesic: true
});
map.addOverlay(polyline);
var polyline = new google.maps.Polyline({
path: [
new google.maps.LatLng(47.3690239, 8.5380326),
new google.maps.LatLng(1.352083, 103.819836),
new google.maps.LatLng(-33.867139, 151.207114)
],
strokeColor: '#FF0000',
strokeOpacity: 0.5,
strokeWeight: 3,
geodesic: true
});
polyline.setMap(map);
編碼折線
v3 不支援直接從編碼折線建立 Polyline
物件。相反地,幾何圖形程式庫提供了折線的編碼及解碼方法。請參閱 Maps API 第 3 版的「程式庫」,進一步瞭解如何載入這個程式庫。
下列範例可繪製相同的編碼折線;第 3 版程式碼會使用 google.maps.geometry.encoding
命名空間的 decodePath()
方法。
var polyline = new GPolyline.fromEncoded({
points: 'kwb`Huqbs@ztzwGgvpdQbw}uEoif`H',
levels: 'PPP',
zoomFactor: 2,
numLevels: 18,
color: '#ff0000',
opacity: 0.8,
weight: 3
});
map.addOverlay(polyline);
var polyline = new google.maps.Polyline({
path: google.maps.geometry.encoding.decodePath(
'kwb`Huqbs@ztzwGgvpdQbw}uEoif`H'),
strokeColor: '#FF0000',
strokeOpacity: 0.5,
strokeWeight: 3,
});
polyline.setMap(map);
多邊形
「多邊形」指的是頭尾相連的多角線段所構成的封閉型區塊。與 Polyline
物件類似,Polygon
物件由一系列點依序組成。第 3 版 Polygon
類別與第 2 版 GPolygon
類別大致相同,但有一項明顯的例外:您不再需要在路徑結尾重複起始頂點來關閉迴圈。第 3 版 API 會繪製一段筆劃將最後一個座標連回第一個座標,自動關閉任何多邊形。下列程式碼片段會建立代表百慕達三角洲的多邊形:
var map = new GMap2(document.getElementById('map'));
map.setCenter(new GLatLng(24.886436, -70.268554), 5);
var bermudaTriangle = new GPolygon(
[
new GLatLng(25.774252, -80.190262),
new GLatLng(18.466465, -66.118292),
new GLatLng(32.321384, -64.75737),
new GLatLng(25.774252, -80.190262)
],
'#FF0000', 2, 0.8, '#FF0000', 0.35);
map.addOverlay(bermudaTriangle);
var map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(24.886436, -70.268554),
mapTypeId: google.maps.MapTypeId.TERRAIN,
zoom: 5
});
var bermudaTriangle = new google.maps.Polygon({
paths: [
new google.maps.LatLng(25.774252, -80.190262),
new google.maps.LatLng(18.466465, -66.118292),
new google.maps.LatLng(32.321384, -64.75737)
],
strokeColor: '#FF0000',
strokeWeight: 2,
strokeOpacity: 0.8,
fillColor: '#FF0000',
fillOpacity: 0.35
});
bermudaTriangle.setMap(map);
使用者可編輯的形狀
您可將折線和多邊形設為允許使用者編輯。下列程式碼片段會相等:
map.addOverlay(polyline);
polyline.enableEditing();
polyline.setMap(map);
polyline.setEditable(true);
如需更多進階繪圖功能,請參閱第 3 版說明文件中的繪圖程式庫。
資訊視窗
InfoWindow
會在地圖上方的浮動視窗中顯示內容。第 2 版和第 3 版資訊視窗的主要差異如下:
- 第 2 版 API 對每張地圖僅支援
GInfoWindow
,第 3 版 API 則在每個地圖上支援多個並行的 InfoWindow
。
- 您點選地圖時,第 3 版
InfoWindow
會保持開啟狀態,點擊地圖時,第 2 版 GInfoWindow
會自動關閉。您可以在 Map
物件中新增 click
事件監聽器,藉此模擬第 2 版的行為。
- v3 API 並未原生支援分頁式
InfoWindow
。
區域疊加層
如要在地圖上放置圖片,應使用 GroundOverlay
物件。GroundOverlay
的建構函式在第 2 版和第 3 版大致相同:這個建構函式會指定圖片網址,並將圖片的邊界指定為參數。
下例將紐澤西州紐華克的古董地圖加進地圖做為疊加層:
var bounds = new GLatLngBounds(
new GLatLng(40.716216, -74.213393),
new GLatLng(40.765641, -74.139235));
var overlay = new GGroundOverlay(
'http://lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
bounds);
map.addOverlay(overlay);
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(40.716216, -74.213393),
new google.maps.LatLng(40.765641, -74.139235));
var overlay = new google.maps.GroundOverlay(
'http://lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
bounds);
overlay.setMap(map);
地圖類型
第 2 版和第 3 版提供的地圖類型略有不同,但這兩種 API 版本都提供所有基本地圖類型。根據預設,第 2 版會使用標準「繪製」道路地圖圖塊。不過,第 3 版規定建立 google.maps.Map
物件時必須指定特定的地圖類型。
常用地圖類型
第 2 版和第 3 版皆提供下列 4 種基本地圖類型:
MapTypeId.ROADMAP
(取代 G_NORMAL_MAP
) 會顯示道路地圖檢視。
MapTypeId.SATELLITE
(取代 G_SATELLITE_MAP
) 顯示 Google 地球衛星影像。
MapTypeId.HYBRID
(取代 G_HYBRID_MAP
) 會顯示一般檢視和衛星檢視的混合畫面。
MapTypeId.TERRAIN
(取代 G_PHYSICAL_MAP
) 會根據地形資訊顯示實際地圖。
下方範例顯示在第 2 版和第 3 版中如何將地圖設定為地形檢視:
map.setMapType(G_PHYSICAL_MAP);
map.setMapTypeId(google.maps.MapTypeId.TERRAIN);
Maps JavaScript API 第 3 版也對較不常用的地圖類型進行了幾項變更:
- 在第 3 版 API 中,地球以外的天體地圖圖塊無法用做自訂地圖類型,但如這個範例所示。
- 第 3 版中沒有特殊的地圖類型,可取代第 2 版的
G_SATELLITE_3D_MAP
類型。您可以改用這個程式庫,在第 3 版地圖中整合 Google 地球外掛程式。
最大縮放圖像
並非所有衛星圖像都具備高倍縮放能力。如想在設定縮放等級前,先瞭解可用的最高縮放等級,請使用 google.maps.MaxZoomService
類別。這個類別取代第 2 版的 GMapType.getMaxZoomAtLatLng()
方法。
var point = new GLatLng(
180 * Math.random() - 90, 360 * Math.random() - 180);
var map = new GMap2(document.getElementById("map"));
map.setUIToDefault();
map.setCenter(point);
map.setMapType(G_HYBRID_MAP);
map.getCurrentMapType().getMaxZoomAtLatLng(point,
function(response) {
if (response.status) {
map.setZoom(response.zoom);
} else {
alert("Error in Max Zoom Service.");
}
});
var myLatlng = new google.maps.LatLng(
180 * Math.random() - 90, 360 * Math.random() - 180);
var map = new google.maps.Map(
document.getElementById("map"),{
zoom: 0,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.HYBRID
});
var maxZoomService = new google.maps.MaxZoomService();
maxZoomService.getMaxZoomAtLatLng(
myLatlng,
function(response) {
if (response.status == google.maps.MaxZoomStatus.OK) {
map.setZoom(response.zoom);
} else {
alert("Error in Max Zoom Service.");
}
});
空照透視圖像
在第 3 版啟用空照圖像時,控制項與第 2 版 GLargeZoomControl3D
控制項類似,但會額外提供插頁式「旋轉」控制項,以便透過支援的方向旋轉。
你可以追蹤這張地圖目前提供 45° 圖像的城市。如果有 45° 圖像,Maps API 衛星按鈕會新增子選單選項。
圖層
「圖層」是指地圖上由一或多個疊加層組成的物件。這可以視為單一單元加以操作,通常會反映多個物件集合。
支援的圖層
第 3 版 API 提供幾種不同圖層的使用。這些圖層與第 2 版 GLayer
類別在下列區域重疊:
-
KmlLayer
物件會將 KML 和 GeoRSS 元素算繪成第 3 版疊加層,提供與第 2 版 GeoXml
圖層相同的效果。
TrafficLayer
物件會算繪描繪路況的圖層,與第 2 版的 GTrafficOverlay
疊加層類似。
這些圖層與第 2 版的圖層不同,
以下說明兩者的差異。如要將這些元素加入地圖,請呼叫 setMap()
,並向其傳遞要顯示圖層的 Map
物件。
如要進一步瞭解支援的圖層,請參閱圖層說明文件。
KML 與 GeoRSS 圖層
Maps JavaScript API 支援以 KML 和 GeoRSS 資料格式顯示地理資訊。如要在地圖中加入 KML 或 GeoRSS 檔案,這些檔案都必須設為可公開存取。在第 3 版中,這些資料格式會透過 KmlLayer
的執行個體顯示,而後者會取代第 2 版的 GGeoXml
物件。
第 3 版 API 算繪 KML 時,更具彈性,可讓您隱藏 InfoWindows 並修改點擊回應。詳情請參閱第 3 版的 KML 與 GeoRSS 圖層說明文件。
算繪 KmlLayer
時會受到大小和複雜度限制,詳情請參閱 KmlLayer 說明文件。
下列範例比較 KML 檔案的載入方式。
geoXml = new GGeoXml(
'https://googlearchive.github.io/js-v2-samples/ggeoxml/cta.kml');
map.addOverlay(geoXml);
var layer = new google.maps.KmlLayer(
'https://googlearchive.github.io/js-v2-samples/ggeoxml/cta.kml', {
preserveViewport: true
});
layer.setMap(map);
路況圖層
在第 3 版中,您可以使用 TrafficLayer
物件在地圖中加入即時車流量資訊 (如有支援)。系統會根據要求提出要求的時間提供路況資訊。以下示例顯示洛杉磯的路況資訊:
var map = new GMap2(document.getElementById('map'));
map.setCenter(new GLatLng(34.0492459, -118.241043), 13);
map.setUIToDefault();
var trafficOptions = {incidents:false};
trafficInfo = new GTrafficOverlay(trafficOptions);
map.addOverlay(trafficInfo);
var map = new google.maps.Map(
document.getElementById('map'), {
center: new google.maps.LatLng(34.0492459, -118.241043),
mapTypeId: google.maps.MapTypeId.ROADMAP,
zoom: 13
});
var trafficLayer = new google.maps.TrafficLayer();
trafficLayer.setMap(map);
與第 2 版不同,第 3 版中的 TrafficLayer
建構函式沒有任何選項。第 3 版不支援事件。
服務
Geocoding
Maps JavaScript API 提供 geocoder
物件,可針對使用者輸入的地址以動態方式進行地址地理編碼。如要對已知靜態地址進行地理編碼,請參閱 Geocoding API 說明文件。
Geocoding API 已大幅升級並強化,並新增了多項功能及變更資料呈現方式。
第 2 版 API 中的 GClientGeocoder
提供兩種正向和反向地理編碼方法,以及會影響地理編碼執行方式的其他方法。相對地,第 3 版的 Geocoder
物件則只提供 geocode()
方法,該方法採用包含輸入字詞 (以地理編碼要求物件形式) 的物件常值和回呼方法。視要求包含文字 address
屬性或 LatLng
物件而定,Geocoding API 會傳回正向或反向地理編碼回應。您可以將其他欄位傳遞至地理編碼要求,以影響地理編碼的執行方式:
- 加入文字
address
可觸發向前地理編碼,這相當於呼叫 getLatLng()
方法。
- 加入
latLng
物件可觸發反向地理編碼,相當於呼叫 getLocations()
方法。
- 加入
bounds
屬性可啟用可視區域自訂調整,相當於呼叫 setViewport()
方法。
- 加入
region
屬性可啟用區域代碼自訂調整,相當於呼叫 setBaseCountryCode()
方法。
第 3 版中的地理編碼回應與第 2 版回應大不相同。第 3 版 API 會將 v2 使用的巢狀結構取代為更容易剖析的扁平結構。此外,第 3 版回應更詳細:每項結果都有數個地址元件,有助於您更全面瞭解每項結果的「解析度」。
下列程式碼會採用文字地址,並顯示地理編碼的第一個結果:
var geocoder = new GClientGeocoder();
var infoPanel;
var map;
var AccuracyDescription = [
'Unknown accuracy', 'country level accuracy',
'region level accuracy', 'sub-region level accuracy',
'town level accuracy', 'post code level accuracy',
'street level accuracy', 'intersection level accuracy',
'address level accuracy', 'premise level accuracy',
];
function geocode_result_handler(response) {
if (!response || response.Status.code != 200) {
alert('Geocoding failed. ' + response.Status.code);
} else {
var bounds = new GLatLngBounds(new GLatLng(
response.Placemark[0].ExtendedData.LatLonBox.south,
response.Placemark[0].ExtendedData.LatLonBox.west
), new GLatLng(
response.Placemark[0].ExtendedData.LatLonBox.north,
response.Placemark[0].ExtendedData.LatLonBox.east
));
map.setCenter(bounds.getCenter(),
map.getBoundsZoomLevel(bounds));
var latlng = new GLatLng(
response.Placemark[0].Point.coordinates[1],
response.Placemark[0].Point.coordinates[0]);
infoPanel.innerHTML += '<p>1st result is <em>' +
// No info about location type
response.Placemark[0].address +
'</em> of <em>' +
AccuracyDescription[response.Placemark[0].
AddressDetails.Accuracy] +
'</em> at <tt>' + latlng + '</tt></p>';
var marker_title = response.Placemark[0].address +
' at ' + latlng;
map.clearOverlays();
var marker = marker = new GMarker(
latlng,
{'title': marker_title}
);
map.addOverlay(marker);
}
}
function geocode_address() {
var address = document.getElementById('input-text').value;
infoPanel.innerHTML = '<p>Original address: ' + address + '</p>';
geocoder.getLocations(address, geocode_result_handler);
}
function initialize() {
map = new GMap2(document.getElementById('map'));
map.setCenter(new GLatLng(38, 15), 2);
map.setUIToDefault();
infoPanel = document.getElementById('info-panel');
}
var geocoder = new google.maps.Geocoder();
var infoPanel;
var map;
var marker;
function geocode_result_handler(result, status) {
if (status != google.maps.GeocoderStatus.OK) {
alert('Geocoding failed. ' + status);
} else {
map.fitBounds(result[0].geometry.viewport);
infoPanel.innerHTML += '<p>1st result for geocoding is <em>' +
result[0].geometry.location_type.toLowerCase() +
'</em> to <em>' +
result[0].formatted_address + '</em> of types <em>' +
result[0].types.join('</em>, <em>').replace(/_/, ' ') +
'</em> at <tt>' + result[0].geometry.location +
'</tt></p>';
var marker_title = result[0].formatted_address +
' at ' + latlng;
if (marker) {
marker.setPosition(result[0].geometry.location);
marker.setTitle(marker_title);
} else {
marker = new google.maps.Marker({
position: result[0].geometry.location,
title: marker_title,
map: map
});
}
}
}
function geocode_address() {
var address = document.getElementById('input-text').value;
infoPanel.innerHTML = '<p>Original address: ' + address + '</p>';
geocoder.geocode({'address': address}, geocode_result_handler);
}
function initialize() {
map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(38, 15),
zoom: 2,
mapTypeId: google.maps.MapTypeId.HYBRID
});
infoPanel = document.getElementById('info-panel');
}
規劃路線
在計算路線時,Maps JavaScript API 第 3 版會將第 2 版的 GDirections
類別替換為 DirectionsService
類別。
第 3 版的 route()
方法會取代第 2 版 API 的 load()
和 loadFromWaypoints()
方法。這個方法採用單一 DirectionsRequest
物件常值,其中包含輸入字詞,以及收到回應後要執行的回呼方法。這個物件常值提供的選項可能與第 2 版的 GDirectionsOptions
物件常值類似。
在 Maps JavaScript API 第 3 版中,提交路線要求的工作已與算繪要求工作分開,而該工作現在是透過 DirectionsRenderer
類別處理。您可以透過其 setMap()
和 setDirections()
方法,將DirectionsRenderer
物件與任何地圖或DirectionsResult
物件結合。由於轉譯器為 MVCObject
,因此會偵測其屬性的任何變更,並在相關聯的路線有異動時更新地圖。
下列程式碼示範如何使用從地址輸入的人行路徑,要求前往特定地點的步行路線。請注意,只有第 3 版能在都柏林動物園的人行道中提供步行路線。
var map;
var directions;
var directionsPanel;
function initialize() {
var origin = new google.maps.LatLng(53.348172, -6.297285);
var destination = new google.maps.LatLng(53.355502, -6.30557);
directionsPanel = document.getElementById("route");
map = new GMap2(document.getElementById('map'));
map.setCenter(origin, 10);
map.setUIToDefault();
directions = new GDirections(map, directionsPanel);
directions.loadFromWaypoints(
[origin, destination], {
travelMode: 'G_TRAVEL_MODE_WALKING',
});
}
var map;
var directionsRenderer;
var directionsService = new google.maps.DirectionsService();
function initialize() {
var origin = new google.maps.LatLng(53.348172, -6.297285);
var destination = new google.maps.LatLng(53.355502, -6.30557);
directionsRenderer = new google.maps.DirectionsRenderer();
map = new google.maps.Map(
document.getElementById('map'), {
center: origin,
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
directionsRenderer.setPanel(document.getElementById("route"));
directionsRenderer.setMap(map);
directionsService.route({
origin: origin,
destination: destination,
travelMode: google.maps.DirectionsTravelMode.WALKING
}, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsRenderer.setDirections(result);
}
});
}
街景服務
Google 街景服務可讓您在其涵蓋範圍區域內的指定地點,提供 360 度互動式環景。第 3 版 API 直接在瀏覽器中支援街景服務,有別於第 2 版需要 Flash® 外掛程式才能顯示街景服務圖像。
您可以使用第 3 版的 StreetViewPanorama
物件或在第 2 版中的 GStreetviewPanorama
物件,支援街景服務圖片。這些類別的介面不同,但其作用相同:連結 div
容器與街景服務圖像,並指定街景服務全景的位置和視角 (視角)。
function initialize() {
var fenwayPark = new GLatLng(42.345573, -71.098326);
panoramaOptions = {
latlng: fenwayPark,
pov: {
heading: 35,
pitch: 5,
zoom: 1
}
};
var panorama = new GStreetviewPanorama(
document.getElementById('pano'),
panoramaOptions);
GEvent.addListener(myPano, "error", handleNoFlash);
}
function handleNoFlash(errorCode) {
if (errorCode == FLASH_UNAVAILABLE) {
alert('Error: Your browser does not support Flash');
return;
}
}
function initialize() {
var fenway = new google.maps.LatLng(42.345573, -71.098326);
var panoramaOptions = {
position: fenway,
pov: {
heading: 35,
pitch: 5,
zoom: 1
}
};
var panorama = new google.maps.StreetViewPanorama(
document.getElementById('pano'),
panoramaOptions);
}
您可以透過第 3 版的 StreetViewService
物件,或第 2 版的類似 GStreetviewClient
物件,直接存取街景服務資料。這兩者都提供類似的介面,可用於擷取或檢查街景服務資料的可用性,並讓您依照位置或全景 ID 進行搜尋。
在第 3 版中,街景服務是預設啟用的服務。地圖就會顯示「街景服務衣夾人」控制項,而 API 會重複使用地圖 div 來顯示街景服務全景。下方程式碼說明如何將街景服務全景分為獨立的 div,藉此模擬第 2 版的行為。
var marker;
var panoClient = new GStreetviewClient();
function initialize() {
if (GBrowserIsCompatible()) {
var myPano = new GStreetviewPanorama(
document.getElementById('pano'));
GEvent.addListener(myPano, 'error', handleNoFlash);
var map = new GMap2(document.getElementById('map'));
map.setCenter(new GLatLng(42.345573, -71.098326), 16);
map.setUIToDefault();
GEvent.addListener(map, 'click', function(overlay, latlng) {
if (marker) {
marker.setLatLng(latlng);
} else {
marker = new GMarker(latlng);
map.addOverlay(marker);
}
var nearestPano = panoClient.getNearestPanorama(
latlng, processSVData);
});
function processSVData(panoData) {
if (panoData.code != 200) {
alert("Panorama data not found for this location.");
}
var latlng = marker.getLatLng();
var dLat = latlng.latRadians()
- panoData.location.latlng.latRadians();
var dLon = latlng.lngRadians()
- panoData.location.latlng.lngRadians();
var y = Math.sin(dLon) * Math.cos(latlng.latRadians());
var x = Math.cos(panoData.location.latlng.latRadians()) *
Math.sin(latlng.latRadians()) -
Math.sin(panoData.location.latlng.latRadians()) *
Math.cos(latlng.latRadians()) * Math.cos(dLon);
var bearing = Math.atan2(y, x) * 180 / Math.PI;
myPano.setLocationAndPOV(panoData.location.latlng, {
yaw: bearing
});
}
function handleNoFlash(errorCode) {
if (errorCode == FLASH_UNAVAILABLE) {
alert('Error: Your browser does not support Flash');
return;
}
}
}
}
// Load the API with libraries=geometry
var map;
var marker;
var panorama;
var sv = new google.maps.StreetViewService();
function radians(degrees) { return Math.PI * degrees / 180.0 };
function initialize() {
panorama = new google.maps.StreetViewPanorama(
document.getElementById("pano"));
map = new google.maps.Map(
document.getElementById('map'), {
center: new google.maps.LatLng(42.345573, -71.098326),
mapTypeId: google.maps.MapTypeId.ROADMAP,
zoom: 16
});
google.maps.event.addListener(map, 'click', function(event) {
if (!marker) {
marker = new google.maps.Marker({
position: event.latLng,
map: map
});
} else {
marker.setPosition(event.latLng);
}
sv.getPanoramaByLocation(event.latLng, 50, processSVData);
});
}
function processSVData(panoData, status) {
if (status == google.maps.StreetViewStatus.OK) {
alert("Panorama data not found for this location.");
}
var bearing = google.maps.geometry.spherical.computeHeading(
panoData.location.latLng, marker.getPosition());
panorama.setPano(panoData.location.pano);
panorama.setPov({
heading: bearing,
pitch: 0,
zoom: 1
});
panorama.setVisible(true);
marker.setMap(panorama);
}