2008年12月9日星期二

使用地图API实现自定义叠加层

与地图上的控件不同,地图上的叠加层(Overlay)指的是和某个经纬度坐标绑定,能够跟随地图的缩放拖拽而相应移动的DOM原始,地图API文档里定义的GMarker、GPolyline、GInfoWindow都属于叠加层。右边地图上显示的交通信息的图标就是一个叠加层。
先看一段Hello World的代码吧:
var MyOverlay = function(latlng_) {
  this.latlng = latlng_;
};

MyOverlay.prototype.initialize = function(map_) {
  this.map = map_;
  var label_ = document.createElement("div");
  var container_ = map_.getPane(G_MAP_FLOAT_PANE);
  container_.appendChild(label_);
  label_.innerHTML = "<span style='color:#FF0000;background-color:#FFFFFF;'>Hello World!</span>";
  label_.style.position = "absolute";
  this.label = label_;
  this.redraw();
}
MyOverlay.prototype.redraw = function() {
  var position = this.map.fromLatLngToDivPixel(this.latlng);
  this.label.style.left = position.x + "px";
  this.label.style.top = position.y + "px";
}
MyOverlay.prototype.remove = function() {
  this.label.parentNode.removeChild(this.label);
}
上面的代码中,MyOverlay就是一个自定义的叠加层,需要的时候可以创建一个MyOverlay的实例,然后使用map.addOverlay()就可以在地图上加上这个叠加层了。这里的叠加层是在给定的位置(地图加载时的中心点)加上一个Hello World的文本,以后,无论你怎么拖动缩放地图,这个文本在地图上的位置会跟着地图变化。
下面详细解释一下代码:
var MyOverlay = function(latlng_) {
  this.latlng = latlng_;
};
声明MyOverlay类的构造函数,创建该类的实例是需要给一个GLatLng类型的坐标对象作为参数。

MyOverlay.prototype = new GOverlay();
声明这个类继承自GOverlay

接下来的initialize、redraw、remove都是实现了在GOverlay接口中定义的抽象方法,这些方法在MyOverlay类的对象初始化、地图拖拽缩放、从地图上删除的时候都会被自动调用。

Overlay也是一个DOM元素,所以在initialize方法中需要做的就是定义这个DOM元素并且把它添加到合适的地方去。使用GMap2对象(作为参数传递进来)的getPane方法取得Overlay需要依附的图层(这个图层按照z-index的不同现在可以分为七种不同的图层,我就不列举了,需要的可以到文档里查查GMapPane这个类),也就是Overlay所要依附的DOM容器(不同于GMap2对象的DOM容器),定义好Overlay的样式和内容,然后作为子元素添加到刚才取到的图层里就可以了。
在initialize方法中需要注意的是,作为叠加层的DOM元素的position样式属性必须设置为absolute,并且需要显式的调用redraw方法,才能保证在叠加层第一次加载时的位置显示正确。

对于redraw方法,就是在地图的位置发生变动以后能够重新计算叠加层的坐标并重新设定叠加层的显示位置,关键点就是使用GMap2.fromLatLngToDivPixel()方法来取得叠加层的DOM绝对坐标,不是很理解这个坐标的话可以看看我以前总结果的地图坐标系统

对于remove方法,地图在调用removeOverlay的时候会自动调用这个方法,把你的叠加层从地图上删除。

这里展示的只是一个添加简单文本的Overlay的例子,如果你需要添加更丰富的文本、图片,或者需要这个Overlay能够监听一些事件,比如单击、双击等等,只需要在initialize()方法里对Overlaly的DOM元素做更多的声明和控制就可以了,和你在网页中其他地方定义一个DOM元素没什么两样。