简明现代魔法 -> 软件项目 -> Google Maps 地图叠加层
Google Maps 地图叠加层
2009-11-26
地图叠加层概述
叠加层是地图上绑定到经度/纬度坐标的对象,会随您拖动或缩放地图而移动。叠加层用于反映您“添加”到地图上以指明点、线或区域的对象。
地图 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(39.9493, 116.3975), 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)); }
查看示例 (marker-simple.php)
可拖动的标记
标记是可以点击和拖动到新位置的交互式对象。在此示例中,我们将一个可拖动的标记放置在地图上,并监听它的几个较简单事件。可拖动标记通过实现以下四类事件来表示其拖动状态:click、dragstart、drag 和 dragend。默认情况下,标记可点击但不可拖动,所以它们需要通过将额外的标记选项 draggable 设置为 true 来初始化。可拖动标记拖动结束后默认有弹跳效果。如果不喜欢这种效果,请将 bouncy 选项设置为 false,标记会平缓放下。
var map = new GMap2(document.getElementById("map_canvas")); var center = new GLatLng(39.9493, 116.3975); 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("弹起来了..."); }); map.addOverlay(marker);
查看示例 (marker-drag.php)
图标
标记可以用自定义的新图标来显示,以替代默认图标。因为地图 API 中一个图标(GIcon 对象)需要由多个不同的图像组成,所以定义图标较为复杂。一个图标最少应定义前景图像、类型为 GSize 的尺寸和用于定位图标的图标偏移值。
最简单的自定义图标是基于 G_DEFAULT_ICON 类型来创建。基于此类型创建图标让您仅通过修改若干属性即可快速更改默认图标。
在下面的示例中,我们先用 G_DEFAULT_ICON 类型创建一个图标,然后使用其他图像来改变默认图像。(使用不同图像时要谨慎,因为它们需要设置为与默认图像相同的正确尺寸才能正常显示。)
var map = new GMap2(document.getElementById("map_canvas")); map.addControl(new GSmallMapControl()); map.setCenter(new GLatLng(39.9493, 116.3975), 13); // Create our "tiny" marker icon var blueIcon = new GIcon(G_DEFAULT_ICON); blueIcon.image = "http://www.google.cn/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)); }
查看示例 (icon-simple.php)
多数图标包含前景图像和阴影图像。阴影图像应该和前景图像成 45 度夹角(向右上方倾斜),阴影图像的左下角应与图标前景图像的左下角对齐。阴影图像应是经过 Alpha 透明处理的 24 位 PNG 图像,以便图像边界可以在地图上正确显示。
以下示例使用 Google Ride Finder“迷你”标记为例,创建一种新类型的图标。我们必须指定前景图像、阴影图像以及一些将图标锚定到地图、将信息窗口锚定到图标的点。请注意该图标的参数都是通过 GMarkerOptions 中的选项来指定的。
var map = new GMap2(document.getElementById("map")); map.addControl(new GSmallMapControl()); map.addControl(new GMapTypeControl()); map.setCenter(new GLatLng(39.9493, 116.3975), 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)); }
查看示例 (icon-complex.php)
请注意 GMarkerOptions 对象的定义演示了“对象常量”表示法的用法。该对象不是使用构造函数实例化的,而只是使用名-值对进行声明。
自定义图标
GIcon 对象也有若干其他属性,应对其进行适当设置,以便使您的图标获取最佳的浏览器兼容性和功能。例如,imageMap 属性指定图标图像不透明部分的形状。如果不在图标中设置此属性,则整个图标图像(包括透明部分)在 Firefox/Mozilla 中都将是可点击的。
在许多情况下,图标可以有不同的前景,但具有相同的形状和阴影。最简单的实现方式是使用 GIcon 类的构造函数“复制”已有的图标(比如 G_DEFAULT_ICON,将其作为 GIcon 的 copy 参数),它将复制该图标所有的默认属性,然后您可以对其进行自定义。
var map = new GMap2(document.getElementById("map_canvas")); map.addControl(new GSmallMapControl()); map.addControl(new GMapTypeControl()); map.setCenter(new GLatLng(39.9493, 116.3975), 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.cn/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.cn/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("标记 " + letter + ""); }); 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)); }
查看示例 (icon-custom.php)
使用标记管理器
向 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() 集中添加标记,因为这样更高效。只有显式地调用 MarkerManager 的 refresh() 方法,使用 addMarkers() 方法添加的标记才会显示在地图上,这会将当前视口和边界填充区域内的所有标记添加到地图中。首次显示后,MarkerManager 可以通过监控地图的“moveend”事件来监控所有可见的更新。
缩放级别示例:天气地图
以下示例创建欧洲的模拟天气地图。在缩放级别 3 时,显示 20 个随机分布的天气图标。在级别 6 时,可以轻松地辨别出所有 200 个人口超过 30 万的城市,并显示额外 200 个标记。最后,在级别 8 时,会显示 1000 个标记。(注意:为了简化示例,标记将添加在随机位置。)
function setupMap() { if (GBrowserIsCompatible()) { map = new GMap2(document.getElementById("map_canvas")); map.addControl(new GLargeMapControl()); map.setCenter(new GLatLng(39.90, 116.40), 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(); }
查看示例 (weather_map.php)
集群示例:Google 办事处
标记管理器也可以执行简单的标记集群。虽然不是自动执行此操作,但您可以通过设置显示指定标记的最大缩放级别和最小缩放级别来实现所需效果。在此示例中,我们创建 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.php)
折线
GPolyline 对象可在地图上创建线性叠加层。GPolyline 包括一系列点,并创建一系列有序连接这些点的线段。
绘制折线
折线在地图上绘制为一系列直线段。可以自定义这些线段的颜色、粗细和透明度。颜色应是十六进制数字 HTML 样式,例如使用 #ff0000 而非 red。GPolyline 无法识别命名颜色。
GPolyline 对象使用浏览器的矢量绘制功能(如果可用)。在 Internet Explorer 中,Google 地图使用 VML(请参阅 XHTML 和 VML)绘制折线;在其他浏览器中使用 SVG(如果可用)。在所有其他环境中,我们从 Google 服务器请求一个线段图像并将该图像叠加到地图上,当地图缩放和拖动时按需要刷新图像。
以下代码段会在两点之间创建 10 像素宽的红色折线:
var polyline = new GPolyline([ new GLatLng(39.9493, 116.3975), new GLatLng(39.9593, 116.4071) ], "#ff0000", 10); map.addOverlay(polyline);
查看示例 (polyline-simple.php)
测地折线
在地图上表示的折线是符合当前投影的直线。即它们在地图上显示为直的,但实际上可能没有正确考虑到地球的弧度。如果想绘制测地线(“大圆球”的一段,表示地球表面上两点之间的最短距离),则需要通过 GPolyline 的 GPolylineOptions 参数传递 geodesic:true。
GPolylineOptions 对象是一个对象常量的示例。如果使用对象常量,则无需构造对象。而是可以将参数作为一系列名/值对在花括号中传递。对象常量经常用于不需要实例化对象的情况。
var map = new GMap2(document.getElementById("map_canvas")); map.setCenter(new GLatLng(37, 107), 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(50, 120), new GLatLng(30, 100) ], "#ff0000", 10, 1, polyOptions); map.addOverlay(polyline);
查看示例 (polyline-geodesic.php)
编码折线
Google 地图中的 GPolyline 对象将直线表示为一系列点,使其易于使用但不一定紧凑。长线和复杂的线需要大量内存,绘制起来也需要更长时间。同时,在地图上绘制非编码折线中的线段时,不会考虑较大缩放级别时的分辨率。
Google 地图 API 可让您使用编码折线表示路径,编码折线使用 ASCII 字符的压缩格式在 GPolyline 中指定一系列点。编码折线还可让您指定绘制线段时应忽略的缩放级别组,这样您就可以指定一条折线在指定缩放级别的详细程度。尽管编码折线设置起来更困难,但它们可使您更高效地绘制叠加层。
例如,3 个点的 GPolyline(两条线段)通常表示为:
var polyline = new GPolyline([ new GLatLng(39.9493, 116.3975), new GLatLng(39.9593, 116.4071), 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);
关于此代码要注意两点。
第一,各系列点在编码折线中表示为一系列 ASCII 字符,而在基本 GPolyline 中却使用常见的经度和纬度。将这些点创建为一系列编码 ASCII 值的算法位于此处。如果要通过服务器进程动态计算编码折线(举例而言),则需要此算法。但是,如果只想要转换现有点指定的经度和纬度,则可以使用我们的交互实用工具。
第二,编码折线还允许您指定每个线段在 Google 地图上绘制自身的最大缩放级别。如果在较高的缩放级别上未显示某个点,则只绘制先前可显示的点到下一个可显示的点之间的路径。请注意,此特性在非编码 GPolyline 中不可用,它在以下情况下特别有用:允许在高缩放级别(某些线段的细节可能不相关)下快速绘制。例如,当地图缩小到州级别时,表示从纽约到芝加哥行车路线的编码折线应不关心表示曼哈顿特定街道的线段。
查看示例 (polyline-encoding.php)
多边形
GPolygon 对象类似于 GPolyline 对象,因为它们都包括一系列有序的点。但是,多边形不像折线一样有两个端点,而是设计为定义形成闭环的区域。和折线一样,您可以自定义多边形边(线)的颜色、粗细和透明度,以及封闭的填充区域的颜色和透明度。颜色应是十六进制数字 HTML 样式。
GPolygon 对象类似于 GPolyline对象,使用浏览器的矢量绘制功能(如果可用)。
下面的代码段用四个点创建一个 10 像素宽的方框。请注意,此多边形是“封闭的”,即线段路径的终点与始点重合;始终应闭合多边形以避免发生未定义的行为。
var map = new GMap2(document.getElementById("map_canvas")); map.setCenter(new GLatLng(39.9493, 116.3975), 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); });
查看示例 (polygon-simple.php)
底面叠加层
多边形是非常有用的叠加层,可表示任意大小的区域,但不能显示图像。如果您有一个要放置在地图上的图像,可以使用 GGroundOverlay 对象。 GGroundOverlay 的构造函数将图像的网址和图像的 GLatLngBounds 作为参数。
下面的示例将美国新泽西州纽华克的旧地图作为叠加层放在地图上:
var map = new GMap2(document.getElementById("map_canvas")); map.setCenter(new GLatLng(36.0, 113), 12); // ground overlay var boundaries = new GLatLngBounds(new GLatLng(35.5, 112), new GLatLng(36.5, 114)); 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.php)
图块叠加层
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 文件(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(39.9493, 116.3975), 13); map.addOverlay(myTileLayer);
查看示例 (tileoverlay-simple.php)
自定义地图类型
如果觉得 GTileLayerOverlay 太受限制,则您可以定义自己的自定义地图类型,并开发全新的显示样式。要执行此操作,请构造一个 GMapType 对象,并使用 GMap2.addMapType() 方法将其添加到地图。
从头构造地图类型是一个复杂的过程。您需要构建一种方式,在提供当前图标的情况下,定义和检索在地图上显示的动态数据,并需要确定怎样引用和显示图块。您怎么做由您自己决定,但我们可以通过说明 Google 地图怎样实现其图块引用来向您提供一些帮助。
层
GLayer 对象是叠加层对象,存储第三方地理信息集合。“层”是地理相关功能的集合,可共享某些常用函数,在地图上显示为一个组。Google 通过从其他源获取的数据提供这些集合,并将它们包含在一个层内。
层通常包含多种项目,通常有标记、折线和多边形,但是这些项目不被视为单独对象。层自身(及其所有组件)被视为地图 API 的一个叠加层,通过标准 addOverlay() 方法添加到地图。层还可以进行交互,例如,可对组件执行操作以调出信息窗口。
每个层均包含唯一的命名空间 ID,以便可以轻松地引用、唯一地定位它们。命名空间 ID 当前基于源层的域。例如,英文的“Geotagged Wikipedia © Articles”层的命名空间 ID 为“org.wikipedia.en”。
Google 地图 API 当前可以访问这些公共层。会定期将新的层添加到地图 API。我们会维护此电子表格中的这个列表。
以下代码段会将英文的“Wikipedia”层添加到纽约城格林威治村:
function initialize() { if (GBrowserIsCompatible()) { var map = new GMap2(document.getElementById("map_canvas")); map.setCenter(new GLatLng(39.90822, 116.4055), 13); var myLayer = new GLayer("org.wikipedia.en"); map.addOverlay(myLayer); } }
查看示例 (layer-simple.php)
自定义叠加层
Google 地图 API 还可让您通过实现 GOverlay 接口而创建自定义叠加层。通过实现 GOverlay 接口,Google 地图 API 提供了若干服务,例如 GTrafficOverlay、GGeoXml 和 GStreetviewPanorama 对象。
GOverlay 接口需要您实现四种抽象方法:
- initialize(),用于响应 GMap2.addOverlay()
- remove(),用于响应 GMap2.removeOverlay()
- copy(),允许复制新建的叠加层
- redraw(),用于响应地图中的显示更改
Google 地图 API 接口的实现方式是在 JavaScript 中将 prototype 属性赋值为继承对象的一个实例。例如,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() 方法(创建表示叠加层的 DOM 元素)和 redraw() 方法(基于当前投影和缩放级别在地图上定位叠加层并调整叠加层大小)。
组成叠加层的每个 DOM 元素都位于一个“地图窗格”上,地图窗格定义绘制的 Z 轴次序。例如,折线对于地图来说是平面,所以在最低的 G_MAP_MAP_PANE 中绘制。标记将其阴影元素放置在 G_MAP_MARKER_SHADOW_PANE 中,将前景元素放置在 G_MAP_MARKER_PANE 中。将叠加层元素放置在正确的窗格中可以确保地图上的折线在标记阴影下方绘制,信息窗口在其他叠加层上方绘制。在此示例中,我们的叠加层相对于地图是平面,所以我们将其和 GPolyline 一样添加到最低绘制顺序窗格 G_MAP_MAP_PANE。
// 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(39.9493, 116.3975), 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));
查看示例 (overlay-custom.php)