簡介
疊加層為在地圖上與緯度/經度座標連結的物件,因此它們會隨著您拖曳或縮放地圖而移動。如需預先定義的疊加層類型的資訊,請參閱在地圖上繪製。
Google Maps JavaScript API 提供 OverlayView 類別供您建立自己的自訂疊加層。OverlayView 是一個基本類別,提供許多您在建立疊加層時必須實作的方法。此類別也提供幾種轉譯螢幕座標和地圖位置的方法。
新增自訂疊加層
以下是建立自訂疊加層所需的步驟摘要:
- 將您自訂疊加層物件的
prototype設定為新的google.maps.OverlayView()實例。這個動作實際上會將疊加層類別再細分成子類別。 - 建立自訂疊加層的建構函式,以及設定所有初始化參數。
- 在您的原型中實作
onAdd()方法,然後將疊加層附加到地圖。當地圖準備好附加疊加層時,將會呼叫OverlayView.onAdd()。 - 在您的原型中實作
draw()方法,然後處理物件的視覺顯示。當物件第一次顯示時,將會呼叫OverlayView.draw()。 - 您也需實作
onRemove()方法以清除在疊加層內新增的所有元素。
以下是每個步驟的詳細資訊。您也可以查看完整的可用範例:檢視範例 (overlay-simple.html)。
將疊加層分成子類別
下面的範例使用 OverlayView 建立簡單的影像疊加層。
// This example creates a custom overlay called USGSOverlay, containing
// a U.S. Geological Survey (USGS) image of the relevant area on the map.
// Set the custom overlay object's prototype to a new instance
// of OverlayView. In effect, this will subclass the overlay class therefore
// it's simpler to load the API synchronously, using
// google.maps.event.addDomListener().
// Note that we set the prototype to an instance, rather than the
// parent class itself, because we do not wish to modify the parent class.
var overlay;
USGSOverlay.prototype = new google.maps.OverlayView();
// Initialize the map and the custom overlay.
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 11,
center: {lat: 62.323907, lng: -150.109291},
mapTypeId: 'satellite'
});
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(62.281819, -150.287132),
new google.maps.LatLng(62.400471, -150.005608));
// The photograph is courtesy of the U.S. Geological Survey.
var srcImage = 'https://developers.google.com/maps/documentation/' +
'javascript/examples/full/images/talkeetna.png';
// The custom USGSOverlay object contains the USGS image,
// the bounds of the image, and a reference to the map.
overlay = new USGSOverlay(bounds, srcImage, map);
}
我們現在建立一個 USGSOverlay 類別的建構函式,然後將傳遞的參數初始化為新物件的屬性。
/** @constructor */
function USGSOverlay(bounds, image, map) {
// Initialize all properties.
this.bounds_ = bounds;
this.image_ = image;
this.map_ = map;
// Define a property to hold the image's div. We'll
// actually create this div upon receipt of the onAdd()
// method so we'll leave it null for now.
this.div_ = null;
// Explicitly call setMap on this overlay.
this.setMap(map);
}
我們還不能在疊加層的建構函式中將此疊加層附加到地圖。首先,我們必須確認所有的地圖窗格都能使用,因為這些窗格指定物件在地圖上顯示的順序。API 提供一個協助程式方法可以確認。我們將在下一節處理這個方法。
初始化疊加層
當疊加層一開始啟動而準備好顯示時,我們必須透過瀏覽器的 DOM 將它附加到地圖。API 會呼叫疊加層的 onAdd() 方法,指出疊加層已新增到地圖。若要處理此方法,我們要建立 <div> 保留我們的影像、新增 <img> 元素、將元素附加到 <div>,然後將疊加層附加到地圖的其中一個「窗格」。窗格是 DOM 樹狀結構內的節點。
MapPanes 類型的窗格指定不同圖層在地圖上的堆疊順序。以下是可以使用的窗格,由下到上堆疊:
mapPane是最低的窗格,在地圖方塊上方。不會接收 DOM 事件。(窗格 0)。overlayLayer包含折線、多邊形、地面疊加層和地圖方塊圖層疊加層。不會接收 DOM 事件。(窗格 1)。overlayShadow包含標記陰影。不會接收 DOM 事件。(窗格 2)。overlayImage包含標記前景影像。(窗格 3)。floatShadow包含資訊視窗陰影。在overlayImage上方,以便讓標記能落在資訊視窗的陰影中。(窗格 4)。overlayMouseTarget包含接收 DOM 滑鼠事件的元素,例如標記的透明目標。在floatShadow上方,以便讓資訊視窗陰影中的標記可以點選。(窗格 5)。floatPane包含資訊視窗。在所有地圖疊加層的上方。(窗格 6)。
因為我們的影像是「地面疊加層」,所以我們要使用 overlayLayer 窗格。當我們有這個窗格時,就要將物件附加到上面成為子項。
/**
* onAdd is called when the map's panes are ready and the overlay has been
* added to the map.
*/
USGSOverlay.prototype.onAdd = function() {
var div = document.createElement('div');
div.style.borderStyle = 'none';
div.style.borderWidth = '0px';
div.style.position = 'absolute';
// Create the img element and attach it to the div.
var img = document.createElement('img');
img.src = this.image_;
img.style.width = '100%';
img.style.height = '100%';
img.style.position = 'absolute';
div.appendChild(img);
this.div_ = div;
// Add the element to the "overlayLayer" pane.
var panes = this.getPanes();
panes.overlayLayer.appendChild(div);
};
繪製疊加層
請注意,我們在上面的程式碼中還沒呼叫任何特殊的視覺顯示。每當 API 必須在地圖上繪製疊加層(包括一開始新增)時,就會在疊加層上另外呼叫一個 draw() 方法。
所以我們將實作這個 draw() 方法,使用 getProjection() 擷取疊加層的 MapCanvasProjection,以及計算要錨定物件的右上角點和左下角點的確切座標。然後我們就可以調整 <div> 的大小。這會依序調整影像的大小,以符合我們在疊加層的建構函式中所指定的邊界。
USGSOverlay.prototype.draw = function() {
// We use the south-west and north-east
// coordinates of the overlay to peg it to the correct position and size.
// To do this, we need to retrieve the projection from the overlay.
var overlayProjection = this.getProjection();
// Retrieve the south-west and north-east coordinates of this overlay
// in LatLngs and convert them to pixel coordinates.
// We'll use these coordinates to resize the div.
var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
// Resize the image's div to fit the indicated dimensions.
var div = this.div_;
div.style.left = sw.x + 'px';
div.style.top = ne.y + 'px';
div.style.width = (ne.x - sw.x) + 'px';
div.style.height = (sw.y - ne.y) + 'px';
};
移除自訂疊加層
我們也要新增 onRemove() 方法以便能從地圖乾淨移除疊加層。
// The onRemove() method will be called automatically from the API if
// we ever set the overlay's map property to 'null'.
USGSOverlay.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
};
隱藏和顯示自訂疊加層
如果想要隱藏或顯示某個疊加層而不是只是建立或移除,可以實作自己的 hide() 和 show() 方法來調整疊加層的能見度。或者,您可以從地圖的 DOM 卸離疊加層,不過這個操作會比較耗費資源。請注意,如果您之後又再次將疊加層附加到地圖的 DOM,則會再次呼叫疊加層的 onAdd() 方法。
下列範例將 hide() 和 show() 方法新增到疊加層的原型,切換容器 <div> 的能見度。此外,我們還新增 toggleDOM() 方法,將疊加層附加到地圖,或從地圖卸離疊加層。
// Set the visibility to 'hidden' or 'visible'.
USGSOverlay.prototype.hide = function() {
if (this.div_) {
// The visibility property must be a string enclosed in quotes.
this.div_.style.visibility = 'hidden';
}
};
USGSOverlay.prototype.show = function() {
if (this.div_) {
this.div_.style.visibility = 'visible';
}
};
USGSOverlay.prototype.toggle = function() {
if (this.div_) {
if (this.div_.style.visibility === 'hidden') {
this.show();
} else {
this.hide();
}
}
};
// Detach the map from the DOM via toggleDOM().
// Note that if we later reattach the map, it will be visible again,
// because the containing <div> is recreated in the overlay's onAdd() method.
USGSOverlay.prototype.toggleDOM = function() {
if (this.getMap()) {
// Note: setMap(null) calls OverlayView.onRemove()
this.setMap(null);
} else {
this.setMap(this.map_);
}
};
處理使用者介面:
<!-- Add an input button to initiate the toggle method on the overlay. -->
<div id="floating-panel">
<input type="button" value="Toggle visibility" onclick="overlay.toggle();"></input>
<input type="button" value="Toggle DOM attachment" onclick="overlay.toggleDOM();"></input>
</div>
