除了同样具有功能强大的地图外,还包含 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(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));
}
标记是可以点击和拖动到新位置的交互式对象。在此示例中,我们将一个可拖动的标记放置在地图上,并监听它的几个较简单事件。可拖动标记通过实现以下四类事件来表示其拖动状态: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);
标记可以用自定义的新图标来显示,以替代默认图标。因为地图 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));
}
多数图标包含前景图像和阴影图像。阴影图像应该和前景图像成 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));
}
请注意 GMarkerOptions 对象的定义演示了“对象常量”表示法的用法。该对象不是使用构造函数实例化的,而只是使用名-值对进行声明。
GIcon 对象也有若干其他属性,应对其进行适当设置,以便使您的图标获取最佳的浏览器兼容性和功能。例如,imageMap 属性指定图标图像不透明部分的形状。如果不在图标中设置此属性,则整个图标图像(包括透明部分)在 Firefox/Mozilla 中都将是可点击的。有关详细信息,请参阅 GIcon 类参考。
在许多情况下,图标可以有不同的前景,但具有相同的形状和阴影。最简单的实现方式是使用 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("标记 <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() 集中添加标记,因为这样更高效。只有显式地调用 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();
}
标记管理器也可以执行简单的标记集群。虽然不是自动执行此操作,但您可以通过设置显示指定标记的最大缩放级别和最小缩放级别来实现所需效果。在此示例中,我们创建 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(39.9493, 116.3975), new GLatLng(39.9593, 116.4071) ], "#ff0000", 10); map.addOverlay(polyline);
在地图上表示的折线是符合当前投影的直线。即它们在地图上显示为直的,但实际上可能没有正确考虑到地球的弧度。如果想绘制测地线(“大圆球”的一段,表示地球表面上两点之间的最短距离),则需要通过 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);
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);
关于此代码要注意两点。
GPolyline 中却使用常见的经度和纬度。将这些点创建为一系列编码 ASCII 值的算法位于此处。如果要通过服务器进程动态计算编码折线(举例而言),则需要此算法。但是,如果只想要转换现有点指定的经度和纬度,则可以使用我们的交互实用工具。
GPolyline 中不可用,它在以下情况下特别有用:允许在高缩放级别(某些线段的细节可能不相关)下快速绘制。例如,当地图缩小到州级别时,表示从纽约到芝加哥行车路线的编码折线应不关心表示曼哈顿特定街道的线段。
请参阅折线算法以了解有关底层编码折线算法的信息。
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);
});
多边形是非常有用的叠加层,可表示任意大小的区域,但不能显示图像。如果您有一个要放置在地图上的图像,可以使用 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.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 文件(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.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,地图上的每个 x 和 y 像素均可以使用 0 和·256 * 219 之间的值来引用。
引用整个地图上这样一个唯一的点通常是不实际的。在较高的缩放级别,Google 地图 API 不能使用一个图像文件显示整个地球。因此确定正在使用哪个图块,然后相对于该图块的原点计算像素坐标非常有用。您实现的任何自定义地图都需要进行相同的计算。
Google 地图中的图块从与像素相同的原点开始计算,以便使原点图块始终处于地图的西北角。图块使用从该原点算起的 x,y 坐标进行索引。例如,在缩放级别 2,当地球分为 16 个图块时,每个图块可以通过一个唯一的 x,y 对来引用:
因此索引特殊缩放级别的特殊点可以使用两个 GPoint 值:一个引用正在使用的图块,一个引用图块 256 x 256 像素图像中的坐标。
如果不是少许简单缩放级别,则实现图块叠加层是一个麻烦的任务,因为您需要添加逻辑来确定处理哪个特定的图块。Google 地图·API 可让您构建一个 GTileLayer,将 GTileLayerOptions 参数作为对象常量传递。GTileLayerOptions 参数包含 tileUrlTemplate 属性,可根据图块坐标将图块请求映射到网址。叠加层的构造函数可能如下所示:
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 属性定义此版权信息有效的限制条件,包含版权字符串的 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() 会返回附加到该对象的版权声明,查看指定的 bounds 和 zoom 是否适用于其每个子 GCopyright 对象。其中每个方法都包含 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。我们会维护此电子表格中的这个列表。
以下代码段会将英文的“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);
}
}
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));