同樣好用的地圖,再加上 SLA、支援以及廣告的控制
疊加層會與地圖的特定經緯度座標結合,因此在拖曳或縮放地圖時會跟著移動。疊加層會反應您新增至地圖上以指派點、線條或區域的物件。
地圖 API 有幾種疊加層類型:
GMarker 的物件,可使用 GIcon 類型。GPolyline 的物件。GTileLayerOverlay 修改自己專用的一組地圖方塊,甚至可使用 GMapType 建立自己的地圖類型。GInfoWindow 類型的物件。每個疊加層都採用 GOverlay 介面。您可以使用 GMap2.addOverlay() 方法在地圖上加入疊加層,而使用 GMap2.removeOverlay() 方法進行移除。(請注意,資訊視窗預設會新增至地圖。)
標記可以指定地圖上的點。按照預設,它們會使用 G_DEFAULT_ICON,不過您可以指定自訂圖示。GMarker建構函式接受 GLatLng 和選用的 GMarkerOptions物件作為引數。
標記的設計為互動式。例如,按照預設,它們會接收 "click" 之類的事件,而且事件接聽程式常常使用,以帶出資訊視窗。
var map = new GMap2(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
// Add 10 markers to the map at random locations
var bounds = map.getBounds();
var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();
var lngSpan = northEast.lng() - southWest.lng();
var latSpan = northEast.lat() - southWest.lat();
for (var i = 0; i < 10; i++) {
var point = new GLatLng(southWest.lat() + latSpan * Math.random(),
southWest.lng() + lngSpan * Math.random());
map.addOverlay(new GMarker(point));
}
標記為互動式物件,可以按下並拖曳至新位置。在此範例中,我們在地圖上放置可拖曳的標記,並接聽其簡單的幾個事件。可拖曳的標記會實作四種活動來指出其拖曳狀態:click、dragstart、drag 和 dragend。按照預設,標記可以按、但是不能拖曳,因此需要將其他標記選項 draggable 設為 true,初始化拖曳功能。當拖曳結束時,可拖曳標記預設會播放原地彈跳動畫。如果您不喜歡此行為,只要將 bouncy 選項設為 false,就可以輕鬆地將該功能取消。
var map = new GMap2(document.getElementById("map_canvas"));
var center = new GLatLng(37.4419, -122.1419);
map.setCenter(center, 13);
var marker = new GMarker(center, {draggable: true});
GEvent.addListener(marker, "dragstart", function() {
map.closeInfoWindow();
});
GEvent.addListener(marker, "dragend", function() {
marker.openInfoWindowHtml("Just bouncing along...");
});
map.addOverlay(marker);
標記可另外定義圖示來取代預設圖示。在「地圖 API」中,單一圖示是由很多不同圖片所組成,因此定義的程序很複雜。圖示至少必須定義其前景圖片、圖示大小(GSize 物件),和放置圖示所用的圖示位移。
最簡易的圖示是根據 G_DEFAULT_ICON 類型。根據此類型建立的圖示,只要修改一些 Property,就可以快速變更預設圖示。
下列範例中,我們使用 G_DEFAULT_ICON 類型建立圖示,然後加以修改、使用不同的圖片。(使用不同的圖片時請小心,設定的大小必須正確,才能正確地顯示預設圖片。)
var map = new GMap2(document.getElementById("map_canvas"));
map.addControl(new GSmallMapControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
// Create our "tiny" marker icon
var blueIcon = new GIcon(G_DEFAULT_ICON);
blueIcon.image = "http://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png";
// Set up our GMarkerOptions object
markerOptions = { icon:blueIcon };
// Add 10 markers to the map at random locations
var bounds = map.getBounds();
var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();
var lngSpan = northEast.lng() - southWest.lng();
var latSpan = northEast.lat() - southWest.lat();
for (var i = 0; i < 10; i++) {
var point = new GLatLng(southWest.lat() + latSpan * Math.random(),
southWest.lng() + lngSpan * Math.random());
map.addOverlay(new GMarker(point, markerOptions));
}
大部分圖示都有前景圖片和陰影圖片。陰影圖片建立時應與前景圖片呈 45 度角 (向右上方傾斜),陰影圖片的左下角應該與圖示前景圖片的左下角對齊。陰影圖片為 24 位元的 PNG 圖片,使用 Alpha 透明,讓圖片的邊界可以正確顯示地圖上。
此範例建立新的圖示類型,以 Google Ride Finder「迷你」標記做為範例。我們必須指定前景圖片、陰影圖片、將圖示錨定到地圖的點,以及將資訊視窗錨定到圖示的點。請注意,圖示會以 GMarkerOptions 物件中定義的選項傳送。
var map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
// Create our "tiny" marker icon
var tinyIcon = new GIcon();
tinyIcon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
tinyIcon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
tinyIcon.iconSize = new GSize(12, 20);
tinyIcon.shadowSize = new GSize(22, 20);
tinyIcon.iconAnchor = new GPoint(6, 20);
tinyIcon.infoWindowAnchor = new GPoint(5, 1);
// Set up our GMarkerOptions object literal
markerOptions = { icon:tinyIcon };
// Add 10 markers to the map at random locations
var bounds = map.getBounds();
var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();
var lngSpan = northEast.lng() - southWest.lng();
var latSpan = northEast.lat() - southWest.lat();
for (var i = 0; i < 10; i++) {
var point = new GLatLng(southWest.lat() + latSpan * Math.random(),
southWest.lng() + lngSpan * Math.random());
map.addOverlay(new GMarker(point, markerOptions));
}
請注意,GMarkerOptions物件的定義會指出「物件實字」註釋的用法。物件並非以建構函式進行列舉,而是簡單以名稱-值配對加以宣告。
GIcon 物件也有一些 Property 應該加以設定,以獲得圖示與瀏覽器的最大相容性和功能性。例如,imageMap Property 指定圖示圖片非透明部分的圖形。如果沒有在圖示中設定此 Property,則整個圖片 (包括透明部分) 在 Firefox/Mozilla 中都可以按。請參閱 GIcon 類別參考文件以取得詳細資訊。
在很多情況中,圖示可能雖然前景不同,但形狀和陰影圖片都相同。要達成此行為,最簡單的方法就是使用 GIcon 類別的 copy 建構函式,它會將所有 Property 複製到新圖示,然後您便可以進行自訂。
var map = new GMap2(document.getElementById("map_canvas"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
// Create a base icon for all of our markers that specifies the
// shadow, icon dimensions, etc.
var baseIcon = new GIcon(G_DEFAULT_ICON);
baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
baseIcon.iconSize = new GSize(20, 34);
baseIcon.shadowSize = new GSize(37, 34);
baseIcon.iconAnchor = new GPoint(9, 34);
baseIcon.infoWindowAnchor = new GPoint(9, 2);
// Creates a marker whose info window displays the letter corresponding
// to the given index.
function createMarker(point, index) {
// Create a lettered icon for this point using our icon class
var letter = String.fromCharCode("A".charCodeAt(0) + index);
var letteredIcon = new GIcon(baseIcon);
letteredIcon.image = "http://www.google.com/mapfiles/marker" + letter + ".png";
// Set up our GMarkerOptions object
markerOptions = { icon:letteredIcon };
var marker = new GMarker(point, markerOptions);
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml("Marker <b>" + letter + "</b>");
});
return marker;
}
// Add 10 markers to the map at random locations
var bounds = map.getBounds();
var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();
var lngSpan = northEast.lng() - southWest.lng();
var latSpan = northEast.lat() - southWest.lat();
for (var i = 0; i < 10; i++) {
var point = new GLatLng(southWest.lat() + latSpan * Math.random(),
southWest.lng() + lngSpan * Math.random());
map.addOverlay(createMarker(point, i));
}
新增大量標記到 Google 地圖不僅會減慢地圖顯示速度,在某些放大比例還會使視覺混亂。標記管理公用程式能同時解決這些問題,它不僅可在同一張地圖上快速顯示數百個標記,還能指定應以何種縮放比例來顯示標記。
如需標記管理公用程式,請至 GMaps 公用程式庫下載。此程式庫為開放原始碼,內含不屬於核心「Google 地圖 API」的公用程式。如果要新增內含於此程式庫中的公用程式,請使用 <script> 標記直接新增 JavaScript ·原始碼。
<script src="http://gmaps-utility-library.googlecode.com/svn/trunk/markermanager/release/src/markermanager.js">
markermanager.js 程式庫中的 MarkerManager 物件可追蹤在特定縮放比例下能於目前檢視中看到哪些標記,並只傳送基於繪圖所需的標記到地圖中,因此能減輕公用程式所登錄的標記的管理負荷。管理程式會監控地圖的目前檢視點與縮放比例,然後在適當時候動態地新增或移除地圖上的標記。此外,藉由讓標記指定其顯示時所用的縮放比例,程式開發人員可以指定標記群組。這種管理功能可大幅加速地圖顯示速度,並減少視覺混亂。
若要使用標記管理程式,請建立 MarkerManager 物件。最簡單的方法是傳送一幅地圖至標記器管理程式。
var map = new GMap2(document.getElementById("map_canvas"));
var mgr = new MarkerManager(map);
您也可以指定許多選項來微調標記管理程式的效能。這些選項會透過 MarkerManagerOptions 物件進行傳送,此物件包含下列欄位:
maxZoom:指定此標記管理程式所監控的最大縮放比例。預設值為 Google 地圖所支援的最高縮放比例。borderPadding:指定管理程式所監控的目前檢視點外側的額外填充距離 (以像素為單位)。這可以顯示超出視線範圍的標記,改善細小範圍的移動瀏覽效能。預設值為 100。trackMarkers:指定標記管理程式是否應該追蹤標記的移動。如果您想透過 setPoint() 方法來改變所管理標記的位置,請將此值設為 true。依預設,此旗標設為 false。請注意,如果您移動此值設為 false 的標記,則它們會同時出現在原始位置和新位置。MarkerManagerOptions 物件是一種物件實字,因此您可以只宣告物件而不需使用建構函式:
var map = new GMap2(document.getElementById("map_canvas"));
var mgrOptions = { borderPadding: 50, maxZoom: 15, trackMarkers: true };
var mgr = new MarkerManager(map, mgrOptions);
一旦您建立了管理程式,即可在其中新增標記:MarkerManager:支援使用 addMarker() 方法一次新增一個標記,或使用 addMarkers() 方法以陣列形式傳送一組標記。使用 addMarker() 方法新增的單一標記會在它們落於地圖的目前檢視範圍內且符合指定縮放比例限制時立即出現。
建議您使用 addMarkers() 方法同時新增一組標記,這樣做比較有效率。使用 addMarkers() 方法新增的標記不會出現在地圖上,除非您明確呼叫 MarkerManager 的 refresh() 方法,此方法會在目前檢視區及地圖邊界間隙區域內新增所有標記。在第一次顯示之後,MarkerManager 會監控地圖的「移動結束」活動,負責所有的視覺更新。
下列會建立一幅歐洲的模擬氣象圖。當縮放比例為 3 時,會顯示 20 個隨機分佈的天氣圖示。當比例為 6 時,可以輕鬆辨別人口多於 30 萬人的全部 200 個城市,此時則會顯示額外 200 個標記。最後當比例為 8 時,共顯示 1000 個標記。(附註:為了簡化範例,標記乃隨機新增至其位置。)
function setupMap() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map_canvas"));
map.addControl(new GLargeMapControl());
map.setCenter(new GLatLng(41, -98), 4);
window.setTimeout(setupWeatherMarkers, 0);
}
}
function getWeatherMarkers(n) {
var batch = [];
for (var i = 0; i < n; ++i) {
batch.push(new GMarker(getRandomPoint(), { icon: getWeatherIcon() }));
}
return batch;
}
function setupWeatherMarkers() {
mgr = new MarkerManager(map);
mgr.addMarkers(getWeatherMarkers(20), 3);
mgr.addMarkers(getWeatherMarkers(200), 6);
mgr.addMarkers(getWeatherMarkers(1000), 8);
mgr.refresh();
}
標記管理程式也可以簡單指定標記群組。如果管理程式未自動指定標記群組,您可以同時設定特定標記的最小與最大顯示縮放比例,達到所需效果。在此範例中,我們將建立北美地區的 Google 辦事處地圖。在最高縮放比例時,我們會顯示旗標以指出辦事處的所在國家/地區。當縮放比例為 3 到 7 時,我們會在有一個以上辦事處的人口集中地顯示圖示。最後當縮放比例為 8 或更高時,我們則針對每個辦事處分別顯示標記。
var officeLayer = [
{
"zoom": [0, 3],
"places": [
{ "name": "US Offices", "icon": ["us", "flag-shadow"], "posn": [40, -97] },
{ "name": "Canadian Offices", "icon": ["ca", "flag-shadow"], "posn": [58, -101] }
]
},
...
};
function setupOfficeMarkers() {
var mgr = new MarkerManager(map);
for (var i in officeLayer) {
var layer = officeLayer[i];
var markers = [];
for (var j in layer["places"]) {
var place = layer["places"][j];
var icon = getIcon(place["icon"]);
var posn = new GLatLng(place["posn"][0], place["posn"][1]);
markers.push(new GMarker(posn, { title: place["name"], icon: icon }));
}
mgr.addMarkers(markers, layer["zoom"][0], layer["zoom"][1]);
}
mgr.refresh();
}
檢視範例 (google_northamerica_offices.html)
如果要瞭解詳細資訊,請參閱開放原始碼的標記管理程式參考說明。
GPolyline 物件會在地圖上建立線性疊加層。GPolyline 由一系列的點所組成,並建立一系列的線段,依序將那些點連接在一起。
折線是由地圖上一系列直線段所繪製而成。您可以指定線條的自訂色彩、粗細以及透明度。色彩為十六進位數字 HTML 格式,例如使用 #ff0000,而非 red。GPolyline 不瞭解命名色彩。
GPolyline 物件使用瀏覽器的向量繪製功能 (若可用的話)。在 Internet Explorer 中,「Google 地圖」使用 VML (請參閱 XHTML 與 VML) 來繪製折線;而在其他瀏覽器中則使用 SVG (若可用的話)。在所有其他情況下,我們會從 Google 伺服器要求線條的圖片,並將該圖片疊加於地圖上;當縮放或拖曳地圖時,會視需要重新整理圖片。
下列程式碼片段會在兩點之間建立 10 像素寬的紅色折線:
var polyline = new GPolyline([ new GLatLng(37.4419, -122.1419), new GLatLng(37.4519, -122.1519) ], "#ff0000", 10); map.addOverlay(polyline);
地圖上顯示的折線是直線,與目前的投影一致。也就是說,雖然在地圖上看起來是直線,但實際上並不符合地球的彎曲幅度。如果您是要繪製測地線 (「大圓」的片段,表示地球表面任兩點之間的最短距離),您必須在 GPolyline 的 GPolylineOptions 引數中傳送 geodesic:true。
GPolylineOptions 物件是物件實字的範例。使用物件實字時,不需要建構物件。而是將一系列名稱/值組放在大括弧中,做為引數來傳送。物件實字經常用在物件不需要初始化的情況下。
var map = new GMap2(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(45.828799,-105.292969), 2);
// Create GPolylineOptions argument as an object literal.
// Note that we don't use a constructor.
var polyOptions = {geodesic:true};
var polyline = new GPolyline([
new GLatLng(40.65642, -73.7883),
new GLatLng(61.1699849, -149.944496)
], "#ff0000", 10, 1, polyOptions);
map.addOverlay(polyline);
Google 地圖中的 GPolyline 物件將線條表示為一系列的點,雖然容易使用,但可能並不簡潔。長且複雜的線條需要大量的記憶體,而且通常繪製耗時。再者,無論縮放解析度等級為何,未編碼折線中的個別線段也會繪製在地圖上。
「Google 地圖 API」可讓您使用地理編碼折線來表示路徑,這些地理編碼折線使用 ASCII 字元的壓縮格式來指定 GPolyline 內的一系列點。地理編碼折線也可讓您指定描繪線段時應該忽略的縮放比例群組,這樣做可讓您指定折線在特定縮放比例時的詳細顯示程度。雖然地理編碼折線設定比較困難,但可讓您更有效率地製作疊加層顯示繪圖。
例如,含有 3 點 (2 個線段) 的 GPolyline 通常表示如下:
var polyline = new GPolyline([
new GLatLng(37.4419, -122.1419),
new GLatLng(37.4519, -122.1519),
new GLatLng( 37.4619, -122.1819)
], "#FF0000", 10);
map.addOverlay(polyline);
這些相同點的編碼 GPolyline 如下所示 (現在不需再擔心編碼演算法的特殊要求了)。
var encodedPolyline = new GPolyline.fromEncoded({
color: "#FF0000",
weight: 10,
points: "yzocFzynhVq}@n}@o}@nzD",
levels: "BBB",
zoomFactor: 32,
numLevels: 4
});
map.addOverlay(encodedPolyline);
此程式碼有兩件事值得注意。
GPolyline。將這些點建立為一系列編碼 ASCII 值的演算法說明在此處。例如,如果您想透過伺服器程序來即時計算地理編碼折線,就必須使用這個演算法。但是,如果您只想依特定經緯度轉換現有的點,可以使用我們的互動公用程式。
GPolyline 中使用,在較高縮放等級中快速繪製時特別有用 (此時部分線段的細節可能不是那麼重要)。例如,當地圖已經縮小為州的等級時,紐約市到芝加哥之間的路徑就不需要注意代表 Manhattan 中特定街道的線段。
請參閱折線演算法,以取得目前所用地理編碼折線演算法的相關資訊。
GPolygon 物件與 GPolyline 物件類似,都是由一系列的點依序組成。不過,多邊形必須是由封閉曲線圍成的區域。使用折線時,您可以定義多邊形邊緣 (「線條」) 的自訂色彩、粗細以及透明度,並自訂所包含範圍之填充區域的色彩和透明度。色彩為十六進位數字 HTML 格式。
GPolygon 物件 (例如 GPolyline 物件) 會使用瀏覽器的向量繪製功能 (若可用的話)。
下列程式碼片段會圍繞著四個點,建立寬 10 個像素的方塊。請注意,請務必讓線段路徑返回其初始點,將多邊形「封閉」起來,以避免未定義的行為。
var map = new GMap2(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
map.addControl(new GSmallMapControl());
GEvent.addListener(map, 'click', function(overlay, latlng) {
var lat = latlng.lat();
var lon = latlng.lng();
var latOffset = 0.01;
var lonOffset = 0.01;
var polygon = new GPolygon([
new GLatLng(lat, lon - lonOffset),
new GLatLng(lat + latOffset, lon),
new GLatLng(lat, lon + lonOffset),
new GLatLng(lat - latOffset, lon),
new GLatLng(lat, lon - lonOffset)
], "#f33f00", 5, 1, "#ff0000", 0.2);
map.addOverlay(polygon);
});
多邊形疊加層可以呈現出任意大小的區域,但是無法顯示圖片。如果您有圖片要放在地圖上,可以使用 GGroundOverlay 物件。
GGroundOverlay 的建構函式使用圖形網址和圖形 GLatLngBounds 作為參數。
下列範例會在地圖上疊加紐約州紐華克 (Newark, NJ) 的老地圖:
var map = new GMap2(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(40.740, -74.18), 12);
// ground overlay
var boundaries = new GLatLngBounds(new GLatLng(40.716216,-74.213393), new GLatLng(40.765641,-74.139235));
var oldmap = new GGroundOverlay("http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg", boundaries);
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.addOverlay(oldmap);
檢視範例 (groundoverlay-simple.html)
「Google 地圖 API」的地圖是由一組地圖方塊所組成,這些地圖方塊涵蓋整個地球表面,並可使用每種縮放比例。各種使用中的地圖類型 (G_NORMAL_MAP、G_SATELLITE_MAP、G_HYBRID_MAP 和 G_PHYSICAL_MAP) 都有適用的地圖方塊。然而,並非所有地區的地圖方塊都可使用所有縮放比例。例如許多太平洋地區就無法顯示高縮放比例。
在最低縮放比例 (0 級) 時,一個地圖方塊就能顯示整個地球:
之後每個縮放比例則將地圖分成 4 N 個地圖方塊,其中 N 是指縮放比例。例如,當縮放比例為 1 時,「Google 地圖」會將全世界分成 2x2 格,即總共 4 個地圖方塊;當縮放比例為 2 時,「Google 地圖」會將全世界分成 4x4 格,即總共 16 個地圖方塊;以此類推。
如果您想要修改這些地圖方塊的顯示,有兩種方法可以選擇:
GTileLayerOverlay 在現有的地圖類型上進行您自己專用的地圖方塊疊加層GMapType 採用您自己專用的自訂地圖類型第一個案例簡單得多,但用途較有限,第二個案例則可讓您更易於控制應用程式內的顯示方式。以下兩種案例都將討論,但本使用說明並不會詳述如何採用自訂地圖類型。
每種案例都需要您從 GTileOverlay 介面實作三種抽象方法:
getTileUrl() 會使用特定的已傳送 GPoint 和縮放比例,將內含地圖方塊圖片的網址傳送到地圖中。isPng() 會將 Boolean 傳送到地圖中,指出圖片是否為 PNG 檔案 (此種檔案可以透明顯示)。如果為 true,便會假設圖片為 PNG 檔案。getOpacity() 會傳回介於 0.0 到 1.0 之間的值,指出顯示此圖片時所用的透明度。我們將在下兩節中討論其他方法。
如果您想在現有的地圖類型上出現疊加層,請使用 GTileLayerOverlay 物件。此物件要求您建立一個 GCopyrightCollection,並將它附加到地圖方塊圖層中,以指出您允許使用圖片。
下列程式碼會在所有縮放比例的每個地圖方塊上顯示一個簡單的透明疊加層,畫出浮動交叉線之間的地圖方塊輪廓。
// Set up the copyright information
// Each image used should indicate its copyright permissions
var myCopyright = new GCopyrightCollection("© ");
myCopyright.addCopyright(new GCopyright('Demo',
new GLatLngBounds(new GLatLng(-90,-180), new GLatLng(90,180)),
0,'©2007 Google'));
// Create the tile layer overlay and
// implement the three abstract methods
var tilelayer = new GTileLayer(myCopyright);
tilelayer.getTileUrl = function() { return "../include/tile_crosshairs.png"; };
tilelayer.isPng = function() { return true;};
tilelayer.getOpacity = function() { return 1.0; }
var myTileLayer = new GTileLayerOverlay(tilelayer);
var map = new GMap2(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
map.addOverlay(myTileLayer);
檢視範例 (tileoverlay-simple.html)
附註:這是「進階主題」
如果您認為 GTileLayerOverlay 太過侷限,您可以定義自己專用的自訂地圖類型,並發展一套全新的顯示模式。如果要這樣做,請建構一個 GMapType 物件,然後使用 GMap2.addMapType() 方法將它新增到地圖中。
從原圖建構地圖類型為全自動程序。您必須建立一套方式來定義及擷取要在地圖的給定目前座標上顯示的動態資料,且您必須自行決定如何參照及顯示地圖方塊圖片。一切做法皆取決於您,但是,我們可以解釋「Google 地圖」如何實作地圖方塊參照,進而為您提供小小幫助。
「Google 地圖 API」使用三種座標系統:
以下將討論每個系統。
「Google 地圖」內的每個地圖方塊都是由 256 x 256 個像素所組成。因此可以使用 GPoint x,y 配對來參照特定地圖方塊上的某個點。每個地圖方塊的原點 (0,0) 都是該地圖方塊的西北角。因此以代表整個地球的單一地圖方塊為例,設定其原點座落於北極圈和經度 -180 度交界處,即您所見的阿拉斯加。x (經度) 值向東遞增,y (緯度) 值則向南遞增,直至東南方的點 (255,255) 為止。
使用高一級的縮放比例時,x 和 y 方向的像素空間會變成兩倍。例如,當縮放比例為 1 時,地圖是由 4 個 256x256 像素的地圖方塊所組成,如此將導致像素空間變成 512x512。當縮放比例為 19 時,即可使用介於 0 到 219 之間的數值來參照地圖上的每個 x 和 y 像素。
想在整份地圖上參照特定一個點常常是不切實際的做法。在較高的縮放比例時,「Google 地圖 API」就無法只用一張圖檔來顯示整個地球。因此較實用的方法是先判斷正在使用哪個地圖方塊圖片,再運算出相對於該地圖方塊原點的像素座標。您所採用的任何自訂地圖都必須進行這相同估算。
「Google 地圖」的地圖方塊會從像素座標的原點開始編號,因此地圖方塊原點永遠是地圖的西北角。地圖方塊會使用距離原點的 x,y座標進行檢索。例如,當縮放比例為 2 時,地球共分成 16 個地圖方塊,則每個地圖方塊都可使用獨一無二的 x,y 配對進行參照:
因此如果要檢索特定縮放比例時的某個特定點,將會用到兩個 GPoint 值:一個參照到所使用的地圖方塊,另一個參照到地圖方塊內的 256 x 256 圖片像素座標。
地圖方塊疊加層有時候並不只是簡單的縮放等級,這時工作就十分繁複,因為您必須新增邏輯來判斷要使用哪些特定的地圖方塊圖片。「Google 地圖 API」允許您傳送 GTileLayer 引數作為物件實字,以建構一個 GTileLayerOptions。GTileLayerOptions 引數包含一個 tileUrlTemplate Property,可根據地圖方塊座標來對映地圖方塊要求與網址。疊加層的建構函式看來像這樣:
var tileLayerOverlay = new GTileLayerOverlay(
new GTileLayer(null, null, null, {
tileUrlTemplate: 'http://domain.com/myimage_{Z}_{X}_{Y}.png',
isPng:true,
opacity:1.0
})
);
map.addOverlay(tlo);
此範本配置允許您處理地圖方塊圖片的集合,圖片會以在「Google 地圖」中的地圖方塊座標來命名。
地圖通常使用向某個外部機構購買、由外部機構產生或授權使用的圖庫。這些圖片常常需要標示著作權資訊,而在特定情況下 (例如衛星資料),地圖上所使用的圖庫內容可能來自於不同地點的不同來源。為了能夠在您的自訂地圖類型上顯示動態著作權資訊,「地圖 API」提供大量物件來保留著作權資訊,並提供方法和介面以便根據目前的檢視區和縮放比例來擷取這類著作權資訊。
GCopyright 物件是用以保留基本著作權資訊的簡單物件。此物件的 minZoom 和 bounds Property 可定義在哪些限制條件下這類著作權資訊為有效的,text 則包含在那些情況下所要顯示的著作權字串。
GCopyright 物件集合收藏在 GCopyrightCollection 中。GCopyrightCollection 建構函式可讓您定義要附加至所有著作權聲明的文字首碼 (例如「Imagery © 2007」)。請注意,您不能直接在建構函式內新增著作權資訊到 GCopyrightCollection。您必須呼叫 addCopyright 方法,於建構集合之後將個別的 GCopyright 物件新增到集合中。
GTileLayer 介面要求在其建構函式中使用 copyrights 引數。負責處理這些地圖方塊圖層 (例如 GTileLayerOverlay 和 GMapType) 的類別必須事先建立 GCopyrightCollection 物件,並將該物件傳送到地圖方塊圖層的建構函式中。
「Google 地圖 API」採用下列方法來顯示著作權資訊,您可以置換以提供自訂行為:
GMapType.getCopyrights() 會在其所有子地圖方塊圖層上叫用 GTileLayer.getCopyright()。GTileLayer.getCopyright() 都會在其著作權集合中叫用 GCopyrightCollection.getCopyrightNotice()。GCopyrightCollection.getCopyrightNotice() 會傳回附加到此物件的著作權聲明,檢查其每個子 GCopyright 物件是否均已套用給定的 bounds 和 zoom。這些方法每一個都包含 bounds 和 zoom 參數,您可以置換及檢查,以決定要顯示哪種著作權資訊。
依預設,每當「Google 地圖 API」在某個地圖類型內顯示地圖方塊圖層時,會透過 GTileLayer.getCopyright() 方法擷取目前正在所使用的著作權資訊。部分地圖類型可能包含多個地圖方塊圖層,也就是說,可能必須同時顯示多個 GCopyrightCollection 物件的資訊。(例如,G_HYBRID_MAP 地圖類型會同時採用衛星圖層和地圖圖層。)這類並存資訊會連續顯示來自多個著作權集合的著作權聲明。
地球是球體,地圖則是二維平面物件。您在「Google 地圖 API」內看到的地圖全是球體對平面的「投影」。「Google 地圖 API」使用 GProjection 介面來進行投影。目前「Google 地圖 API」只採用一種投影:GMercatorProjection。簡單說來,投影可以定義為 GLatLng 值與地圖座標的一對一相應關係,而 GProjection 介面則提供轉換公用程式來達成此對應目的。
GProjection.fromLatLngToPixel() 方法會將 GLatLng 值轉換成給定縮放比例的像素座標。同樣地,GProjection.fromPixelToLatLng() 方法會將給定縮放比例的像素座標轉換成 GLatLng 值。當您採用某種地圖類型時,這些方法就很實用,因為它們可讓您決定要顯示哪些地圖方塊、如何顯示、以及顯示位移有多少。
下列範例將計算目前縮放比例的像素座標以處理點擊活動,並會同時傳回該位置的像素座標與地圖方塊座標。
如需有關採用地圖類型的詳細資訊,請參閱 GMapType 參考文件。
GLayer 物件為疊加層物件,在其中儲存一組第三方的地理資訊。「圖層」是地理相關圖徵的集合,它們會共用部分通用功能,並在地圖上顯示為群組。Google 提供這些從其他來源取得資料的集合,並在單一圖層內同時加以處理。
圖層通常由多種項目所組成,常見的有標記、折線和多邊形,只是這些項目未被視為獨立物件。圖層本身 (與其所有元件) 被視為是「地圖 API」的一個疊加層,並會透過 addOverlay() 方法新增到地圖中。圖層也可以是互動的,例如可以經由對元件的動作而開啟資訊視窗。
每個圖層都有一個唯一的命名空間 ID,因此可以輕鬆參照及精準尋找到每個圖層。目前這個命名空間 ID 是以來源圖層的網域為命名基礎。例如,英文 Geotagged Wikipedia © Articles 圖層的命名空間 ID 為「org.wikipedia.en」。
目前「Google 地圖 API」可以存取這些公開圖層。新圖層會定期新增到「地圖 API」中。我們將在這份試算表中列出這份清單並加以維護。
下列程式碼片段會將「英文維基百科」(English Wikipedia) 圖層新增到紐約市格林威治村:
function initialize() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(40.730885,-73.997383), 15);
var myLayer = new GLayer("org.wikipedia.en");
map.addOverlay(myLayer);
}
}
「Google 地圖 API」也可採用 GOverlay 介面,讓您建立自訂的疊加層物件。「Google 地圖 API」採用 GOverlay 介面而提供數種服務,例如 GTrafficOverlay、GGeoXml 和 GStreetviewPanorama 物件。(這些服務記錄於服務章節。)
GOverlay 介面要求您實作四種抽象方法:
initialize() 以回應 GMap2.addOverlay()remove() 以回應 GMap2.removeOverlay()copy() 可對新疊加層套用範本redraw() 以回應地圖內的顯示變更「Google 地圖 API」介面指派 prototype Property 給繼承物件的實例,因而能在 JavaScript 內運作。例如,使用下列程式碼可以讓 Rectangle 物件繼承 GOverlay 介面:
OverlaySubclass.prototype = new GOverlay();
只要在物件的 prototype 中指派抽象方法,即可在 GOverlay 介面中實作這些方法:
OverlaySubclass.prototype.initialize = myInitializeMethod; OverlaySubclass.prototype.remove = myRemoveMethod; OverlaySubclass.prototype.copy = myCopyMethod; OverlaySubclass.prototype.redraw = myRedrawMethod;
在下列範例中,我們將建立一個 Rectangle 疊加層,以便在地圖上畫出某個地理區域的輪廓。Rectangle 類別可定義 GOverlay 介面的四個必要方法。請特別注意 initialize() 方法和 redraw() 方法,前者可建立用以代表疊加層的 DOM 元素,後者則可根據目前的投影與縮放比例來定位疊加層並調整其大小。
「地圖窗格」中有組成疊加層所需的每個 DOM 元素,此窗格可定義要在哪個疊置 (z-order) 窗格中進行繪製。例如,折線與地圖位於同個平面,因此可以繪製在最底層 G_MAP_MAP_PANE 上。標記則可在 G_MAP_MARKER_SHADOW_PANE 上放置陰影元素,並在 G_MAP_MARKER_PANE 上放置前景元素。將疊加層元素放置在正確的窗格中,可確保在標記陰影之下繪製折線,並在地圖的其他疊加層之上繪製資訊視窗。在本例中,我們的疊加層與地圖位於同個平面,因此我們將它新增到最底層的疊置 (z-order) 窗格 G_MAP_MAP_PANE 中,如同 GPolyline 一樣。如需地圖窗格的完整清單,請參閱類別參考文件。
// A Rectangle is a simple overlay that outlines a lat/lng bounds on the
// map. It has a border of the given weight and color and can optionally
// have a semi-transparent background color.
function Rectangle(bounds, opt_weight, opt_color) {
this.bounds_ = bounds;
this.weight_ = opt_weight || 2;
this.color_ = opt_color || "#888888";
}
Rectangle.prototype = new GOverlay();
// Creates the DIV representing this rectangle.
Rectangle.prototype.initialize = function(map) {
// Create the DIV representing our rectangle
var div = document.createElement("div");
div.style.border = this.weight_ + "px solid " + this.color_;
div.style.position = "absolute";
// Our rectangle is flat against the map, so we add our selves to the
// MAP_PANE pane, which is at the same z-index as the map itself (i.e.,
// below the marker shadows)
map.getPane(G_MAP_MAP_PANE).appendChild(div);
this.map_ = map;
this.div_ = div;
}
// Remove the main DIV from the map pane
Rectangle.prototype.remove = function() {
this.div_.parentNode.removeChild(this.div_);
}
// Copy our data to a new Rectangle
Rectangle.prototype.copy = function() {
return new Rectangle(this.bounds_, this.weight_, this.color_,
this.backgroundColor_, this.opacity_);
}
// Redraw the rectangle based on the current projection and zoom level
Rectangle.prototype.redraw = function(force) {
// We only need to redraw if the coordinate system has changed
if (!force) return;
// Calculate the DIV coordinates of two opposite corners of our bounds to
// get the size and position of our rectangle
var c1 = this.map_.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var c2 = this.map_.fromLatLngToDivPixel(this.bounds_.getNorthEast());
// Now position our DIV based on the DIV coordinates of our bounds
this.div_.style.width = Math.abs(c2.x - c1.x) + "px";
this.div_.style.height = Math.abs(c2.y - c1.y) + "px";
this.div_.style.left = (Math.min(c2.x, c1.x) - this.weight_) + "px";
this.div_.style.top = (Math.min(c2.y, c1.y) - this.weight_) + "px";
}
var map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
// Display a rectangle in the center of the map at about a quarter of
// the size of the main map
var bounds = map.getBounds();
var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();
var lngDelta = (northEast.lng() - southWest.lng()) / 4;
var latDelta = (northEast.lat() - southWest.lat()) / 4;
var rectBounds = new GLatLngBounds(
new GLatLng(southWest.lat() + latDelta, southWest.lng() + lngDelta),
new GLatLng(northEast.lat() - latDelta, northEast.lng() - lngDelta));
map.addOverlay(new Rectangle(rectBounds));