简介
叠加层是地图上与纬度/经度坐标绑定的对象,会随您拖动或缩放地图而移动。有关预定义叠加层类型的信息,请参阅在地图上绘制。
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>
