Google Maps API 2 文档

读者
简介
Google Maps上的Hello World
浏览器兼容性
XHTML和VML
API升级
地理译码/Geocoding
行程规划和本地搜索
地图范例
基础
地图移动和动画
在地图上添加控件
事件监听器
打开信息窗口
地图覆盖物
点击事件处理
在标记上显示信息窗口
分页信息窗口
创建图标
使用Icon类
可拖动的标记
编码折线 New!
在地图上使用XML和异步远程调用(AJAX)
定制地图控件
定制地图覆盖物 地理译码示例 New!
JavaScript下使用地理译码
展开结构化地址信息
缓存地理译码
HTTP请求方式
错误排除
其他资源
API纵览
GMap2
事件
信息窗口
覆盖对象
控件
XML和RPC
减少浏览器内存泄露
类参考 New!

读者

本文档适用于熟悉JavaScript和面向对象编程概念的人。另外您也应该很熟悉Google地图这个产品。网上有很多JavaScript指南可供参考。

简介

Google Maps上的Hello World

学习这个API最简单的方法就是看一个简单的例子。下面的网页显示一个500x300的地图,中心位于California,Palo Alto:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Google Maps JavaScript API Example</title>
    <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=abcdefg"
            type="text/javascript"></script>
    <script type="text/javascript">
    //<![CDATA[

    function load() {
      if (GBrowserIsCompatible()) {
        var map = new GMap2(document.getElementById("map"));
        map.setCenter(new GLatLng(37.4419, -122.1419), 13);
      }
    }

    //]]>
    </script>
  </head>
  <body onload="load()" onunload="GUnload()">
    <div id="map" style="width: 500px; height: 300px"></div>
  </body>
</html>

您可以下载这个例子修改并测试,但是您必须用您自己的API key代替文件中Key。(如果您注册了某个目录的API Key,那么您可以直接在这个目录的任何子目录下使用。

下面例子里面的地址(http://maps.google.com/maps?file=api&v=2)是在您的页面放置Google地图需要的所有的代码的JavaScript文件。您的页面必须包含指向这个地址的script标记,并加上您的API Key。如果您的API Key是"abcdefg",那么您的script标记看起来应该是这样的:

<script src="http://maps.google.com/maps?file=api&v=2&key=abcdefg"
        type="text/javascript">
</script>

描绘地图的类是GMap2。这个类在页面上显示一个地图。您可以创建任意多个该类的实例(一个实例就是页面上的一个地图)。创建了地图实例之后,就可以指定一个页面元素(通常是div元素)来包含它。除非您明确的指定地图的尺寸,否则地图大小会取决于容器的尺寸。

浏览器兼容性

Google Maps API支持的浏览器种类与Google地图网站相同。因为不同的应用程序在遇到不兼容的浏览器的时候需要表现不同的行为,所以Maps API提供了一个全局方法(GBrowserIsCompatible())来检查兼容性,但是,发现一个不兼容的浏览器时,它不会自动采取任何措施。 http://maps.google.com/maps?file=api&v=2里面的脚本几乎可以在任何浏览器里面解析而不产生错误,所以您可以在检查浏览器兼容性之前就包含脚本文件。

文档中的例子都不会检查浏览器兼容性(除了上面的那第一个例子),他们在老的浏览器上面也不会显示错误信息。很明显真实的应用程序应该在遇到不兼容浏览器的时候最好做点什么以表现得更加友好,而为了让范例代码更好看(易懂),我们省略了这种检查。

非凡的应用总是会遇到浏览器和平台兼容性的问题。这种问题没有任何简单的解决方案,但是Google Maps API讨论组和quirksmode.org应该可以找到些好的信息。

XHTML和VML

我们推荐您使用标准兼容的XHTML页面包含地图。当浏览器看到页面顶端的DOCTYPE,他们会用"标准兼容模式"来渲染页面,这样页面布局和行为在浏览器里的效果更有预见性。

如果您想在地图里面显示折线,您需要在您的XHTML文档里面包含VML命名空间和一些CSS代码,这样可以令它们在IE下面可以正常工作。XHTM文档的开头看起来就像这样:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
    <title>My Google Maps Hack</title>
    <style type="text/css">
    v/:* {
      behavior:url(#default#VML);
    }
    </style>
    <script src="http://maps.google.com/maps?file=api&v=2&key=abcdefg"
             type="text/javascript"></script>
  </head>

API升级

地址http://maps.google.com/maps?file=api&v=2中的v=2部分表明API的版本是2。当我们对API进行重大升级的时候,我们会改变版本号并在Google Code和Maps API讨论组发布相关信息。

一个新版本正式发布以后,我们会让新旧版本并行运行一个月。一个月以后,老版本会被关闭,而使用旧版本的代码将不能继续工作。

Maps API开发团队透明的升级API进行的Bug修正和性能改进。 这些Bug修正应该仅仅提高性能和修正Bug,但是我们可能会不经意的影响一些API用户的使用。请利用Maps API讨论组来报告这些问题。

地理译码/Geocoding

地理译码是把地址(如"1600 Amphitheatre Parkway, Mountain View, CA")转换为地理坐标(如经度-122.083739,纬度37.423021)的流程,您可以用它把数据库里面的街道地址或用户提供的地址信息标记在地图上。Google Maps API包含了可以通过HTTP请求和JavaScript来访问的地理译码器。译注:到目前为止,这个地理译码器还没有足够的中国的本地化信息可以使用。

行程规划和本地搜索

现在Google Maps API不包含任何行程规划服务.然而现在Web上有很多免费的行程规划API。如果您希望为您的网站增加本地搜索能力,您可以使用Google AJAX搜索API来在您的网站上嵌入一个本地搜索模块。

地图范例

下面的例子仅会显示主体相关的JavaScript代码,而不是完整的HTML文件。您可以把JavaScript代码嵌入到前面的骨架HTML文件,或者您可以直接下载每个例子下面的链接所引用的HTML文件。

基础

下面的例子创建一个地图并定位到Palo Alto, California。

var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);

显示范例 (simple.html)

地图移动和动画

下面的例子显示一个地图,然后等待2秒,然后平移到一个新的中心点.

panTo方法把地图的中心移动到一个指定点。如果指定点在地图的可见区域内,地图中心会平滑地平移到指定点,否则地图中心会直接跳到那个点。

var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
window.setTimeout(function() {
  map.panTo(new GLatLng(37.4569, -122.1569));
}, 1000);

显示范例 (animate.html)

在地图上添加控件

您可以用addControl方法在地图上添加控件。在这个例子里,我们加入GSmallMapControlGMapTypeControl控件,这样我们分别可以移动/缩放地图以及在地图和卫星模式之间切换。

var map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13);

显示范例 (controls.html)

事件监听器

要注册一个事件监听器需要调用GEvent.addListener方法。把一个地图,一个需要监听的事件,一个事件发生时需要调用的函数传给GEvent.addListener方法。在下面的例子里,在我们托动地图后,显示地图中心的经纬度。

var map = new GMap2(document.getElementById("map"));
GEvent.addListener(map, "moveend", function() {
  var center = map.getCenter();
  document.getElementById("message").innerHTML = center.toString();
});
map.setCenter(new GLatLng(37.4419, -122.1419), 13);

显示范例 (event.html)

想得到更多事件的信息,参看Events纵览。想得到GMap2对象的完整事件列表,参看GMap2.Events.

打开信息窗口

要创建一个信息窗口,调用openInfoWindow方法,传递给它一个位置和一个用来显示的DOM元素。下面的例子在地图中心显示一个包含"Hello, world"信息的窗口。

var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
map.openInfoWindow(map.getCenter(),
                   document.createTextNode("Hello, world"));

显示范例 (infowindow.html)

地图覆盖物

这个例子在地图上显示10个位置随机的标记和一个5个点连成的折线。如果不指定其他的图标,GMarker类会使用缺省的Google地图图标。自定义图标的例子请参看创建图标。

记得您必须在HTML文档里面包含VML命名空间和CSS以使您的网页能在IE下显示折线。更多的信息参看XHTML和VML。

var map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13); 

// Add 10 markers in random locations on the map
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));
}

// Add a polyline with five random points. Sort the points by
// longitude so that the line does not intersect itself.
var points = [];
for (var i = 0; i < 5; i++) {
  points.push(new GLatLng(southWest.lat() + latSpan * Math.random(),
                          southWest.lng() + lngSpan * Math.random()));
}
points.sort(function(p1, p2) {
  return p1.lng() - p2.lng();
});
map.addOverlay(new GPolyline(points));

显示范例 (overlay.html)

点击事件处理

要在用户点击地图的时候触发一个动作,就需要在您的GMap2实例上注册一个"click"事件的监听器。当事件被触发的时候,事件处理句柄将收到两个参数:被点击的标记(如果有),被点击点的GLatLng(经纬度)。如果没有标记被点击,那么第一个参数为null

注意:标记是唯一支持 "click"事件的内建覆盖对象。其他类型的覆盖对象,如 GPolyline是不能被点击的。

在下面的例子里,当访客点击在地图上一个没有标记的点上时,我们在这个点上创建一个标记。当访客点击在一个标记上的时候,我们把它删除。

var map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13);

GEvent.addListener(map, "click", function(marker, point) {
  if (marker) {
    map.removeOverlay(marker);
  } else {
    map.addOverlay(new GMarker(point));
  }
});

显示范例 (click.html)

想得到更多事件的信息,参看Events纵览。想得到GMap2对象的完整事件列表,参看GMap2.Events.

在标记上显示信息窗口

在这个例子里,我们通过监听每一个标记来在他们上面显示定制的信息窗口。借助Javascript函数闭包(closure)技术,我们可以定制每个标记的信息窗口的内容。

var map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13);

// Creates a marker at the given point with the given number label
function createMarker(point, number) {
  var marker = new GMarker(point);
  GEvent.addListener(marker, "click", function() {
    marker.openInfoWindowHtml("Marker #<b>" + number + "</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 + 1));
}

显示范例 (markerinfowindow.html)

想得到更多事件的信息,参看Events纵览。想得到GMap2对象的完整事件列表,参看GMap2.Events.

分页信息窗口

API版本2引入了openInfoWindowTabs()方法和GInfoWindowTab类用来支持信息窗口拥有多个命名的分页。下面的例子在一个标记上显示了一个简单的分页信息窗口。

var map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13);

// Our info window content
var infoTabs = [
  new GInfoWindowTab("Tab #1", "This is tab #1 content"),
  new GInfoWindowTab("Tab #2", "This is tab #2 content")
];

// Place a marker in the center of the map and open the info window
// automatically
var marker = new GMarker(map.getCenter());
GEvent.addListener(marker, "click", function() {
  marker.openInfoWindowTabsHtml(infoTabs);
});
map.addOverlay(marker);
marker.openInfoWindowTabsHtml(infoTabs);

显示范例 (tabbedinfowindow.html)

创建图标

这个例子创建一个新类型图标,采用Google Ride Finder里面的小标记图标做为例子。我们需要指定背景图片,影子图片和点本身的图片。

var map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13);

// Create our "tiny" marker icon
var icon = new GIcon();
icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
icon.iconSize = new GSize(12, 20);
icon.shadowSize = new GSize(22, 20);
icon.iconAnchor = new GPoint(6, 20);
icon.infoWindowAnchor = new GPoint(5, 1);

// 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, icon));
}

显示范例 (icon.html)

使用Icon类

在很多情况下,您的图标有很多不同的前景,但是有相同的形状和背景。实现这类行为的最简单的方式就是利用GIcon类的复制构造函数,它会把所有的属性复制给您想定制的新图标。

var map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13);

// Create a base icon for all of our markers that specifies the
// shadow, icon dimensions, etc.
var baseIcon = new GIcon();
baseIcon.shadow = "http://www.google.com/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);
baseIcon.infoShadowAnchor = new GPoint(18, 25);

// 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 icon = new GIcon(baseIcon);
  icon.image = "http://www.google.com/mapfiles/marker" + letter + ".png";
  var marker = new GMarker(point, icon);

  GEvent.addListener(marker, "click", function() {
    marker.openInfoWindowHtml("Marker <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));
}

显示范例 (iconclass.html)

可拖动的标记

标记是可以点击和拖动到一个新位置的交互对象。在这个例子里,我们把一个可以拖动的标记放置在地图上,并监听它的几种简单事件。可拖动的标记支持四种事件clickdragstartdragdragend。缺省情况下,标记是可以点击的,但不能被拖动,所以他们需要用设置附加标记选项draggable为真的方式来初始化。可拖动的标记缺省情况下,会在放下的时候跳动。如果您不喜欢这个行为,把bouncy选项设置为假,他们就会在放下的时候老实些。

var map = new GMap2(document.getElementById("map"));
var center = new GLatLng(37.4419, -122.1419);
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("Just bouncing along...");
  });

map.addOverlay(marker);

显示范例 (dragmarker.html)

编码折线

Google地图中的GPolyline对象表示的是一系列的点,简单易用但不够简洁。表示长且复杂的折线需要大量的内存,而且在描绘的时候会花费大量的时间。而且未经编码的折线会在Google地图的每个缩放级别中可见。

Google Maps API也允许你用编码折线来表现路径。编码折线用一个压缩格式的ASCII字符串来表现一系列的点。编码折线还允许你指定线段的可见缩放级别;这样你就可以指定折线在当前的缩放级别下细节如何表现。虽然用起来更加复杂,但是编码折线可以让你的地图描绘效率更高。

例如,有三个点的GPolyline对象通常表现为:

var polyline = new GPolyline([
    new GLatLng(37.4419, -122.1419),
    new GLatLng(37.4519, -122.1519),
    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",
    zoomLevel: 32,
    numLevels: 4
]);
map.addOverlay(encodedPolyline);

需要注意的两点是:

  1. 首先,编码折线用一系列ASCII字符来表现一系列点,就像基本GPolyline对象用一系列经纬度那样。创建这些点序列的编码ASCII值的算法文档在此。如果你需要在运行期间在服务器上面计算这些编码的话,那么你需要了解这个算法。然而,如果你仅仅需要把现有点的经纬度转换成编码,那么你可以使用我们的交互工具。
  2. 其次,编码折线允许你指定每个线段的最高可见缩放级别。如果一个点在更高的缩放级别中不可见,那么折线会自动地连接上一个可见点和下一个可见点。注意,这个特性非编码折线并不支持,这一特性非常有利于加快在高缩放级别的折线绘制速度,因为折线的一些细节无需表现出来。例如,当地图放大到州级的时候,一条用于表现从纽约市到芝加哥驱车路线的编码折线,就不需要表现出麦哈顿的具体街道了。

显示范例(polylineencoding.html)

在地图上使用XML和异步远程调用(AJAX)

在这里例子里,我们下载一个静态文件("data.xml"),我们用GDownloadUrl方法下载这个包含一个经纬度列表的XML文件。当下载完成,我们用GXml类来解析,并为XML文档中的每一个点建立一个标记。

var map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(37.4419, -122.1419), 13);

// Download the data in data.xml and load it on the map. The format we
// expect is:
// <markers>
//   <marker lat="37.441" lng="-122.141"/>
//   <marker lat="37.322" lng="-121.213"/>
// </markers>
GDownloadUrl("data.xml", function(data, responseCode) {
  var xml = GXml.parse(data);
  var markers = xml.documentElement.getElementsByTagName("marker");
  for (var i = 0; i < markers.length; i++) {
    var point = new GLatLng(parseFloat(markers[i].getAttribute("lat")),
                            parseFloat(markers[i].getAttribute("lng")));
    map.addOverlay(new GMarker(point));
  }
});

显示范例 (async.html)。这个例子使用了一个外部的XML数据文件data.xml。

定制地图控件

Maps API的版本2引入了创建定制地图空间的能力,就像内建的平移和缩放控件,继承内建类GControl即可。在这个例子里,我们创建了一个简单的缩放控件,基于文字链接而不是像标准的Google地图缩放控件那样基于图片。

GTextualZoomControl类定义了GControl接口中两个必须的方法:initialize(),用来创建我们用来表现我们的控件的DOM元素;getDefaultPosition(),用来返回一个GControlPosition用于设定在没有指定控件位置的情况下控件的放置位置。想得到关于创建您的自定义控件可以重载函数的更多信息请参看GControl类参考。

所有的地图控件应该加入在地图的容器内,这个容器可以用GMap2类的getContainer()方法。

// A TextualZoomControl is a GControl that displays textual "Zoom In"
// and "Zoom Out" buttons (as opposed to the iconic buttons used in
// Google Maps).
function TextualZoomControl() {
}
TextualZoomControl.prototype = new GControl();

// Creates a one DIV for each of the buttons and places them in a container
// DIV which is returned as our control element. We add the control to
// to the map container and return the element for the map class to
// position properly.
TextualZoomControl.prototype.initialize = function(map) {
  var container = document.createElement("div");

  var zoomInDiv = document.createElement("div");
  this.setButtonStyle_(zoomInDiv);
  container.appendChild(zoomInDiv);
  zoomInDiv.appendChild(document.createTextNode("Zoom In"));
  GEvent.addDomListener(zoomInDiv, "click", function() {
    map.zoomIn();
  });

  var zoomOutDiv = document.createElement("div");
  this.setButtonStyle_(zoomOutDiv);
  container.appendChild(zoomOutDiv);
  zoomOutDiv.appendChild(document.createTextNode("Zoom Out"));
  GEvent.addDomListener(zoomOutDiv, "click", function() {
    map.zoomOut();
  });

  map.getContainer().appendChild(container);
  return container;
}

// By default, the control will appear in the top left corner of the
// map with 7 pixels of padding.
TextualZoomControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(7, 7));
}

// Sets the proper CSS for the given button element.
TextualZoomControl.prototype.setButtonStyle_ = function(button) {
  button.style.textDecoration = "underline";
  button.style.color = "#0000cc";
  button.style.backgroundColor = "white";
  button.style.font = "small Arial";
  button.style.border = "1px solid black";
  button.style.padding = "2px";
  button.style.marginBottom = "3px";
  button.style.textAlign = "center";
  button.style.width = "6em";
  button.style.cursor = "pointer";
}

var map = new GMap2(document.getElementById("map"));
map.addControl(new TextualZoomControl());
map.setCenter(new GLatLng(37.441944, -122.141944), 13);

显示范例 (customcontrol.html)

定制地图覆盖物

Maps API版本2引入了创建自定义的地图覆盖对象的能力,就像内建的GMarkerGPolyline对象,继承内建的GOverlay类即可。在这个例子里,我们创建一个矩形对象用来在地图上面标记一个矩形区域。

Rectangle类定义了GOverlay接口中四个必须的方法:initialize(),用来创建我们用来表现覆盖对象的DOM元素;remove(),用于移除覆盖对象;copy(),用于复制覆盖对象;redraw(),用于在当前投影范围缩放级别下定位和调节覆盖对象的大小。想得到关于创建您的自定义覆盖对象可以重载函数的更多信息请参看GOverlay类参考。

每个在地图上构成覆盖对象的DOM元素需要定义它绘制时的Z序。例如,折线浮在地图上,所以他们绘制在Z序最小的G_MAP_MAP_PANE层。标记的影子元素放置在G_MAP_MARKER_SHADOW_PANE层,他们的前景元素放置在G_MAP_MARKER_PANE层。放置您的覆盖元素在正确的层上,确保直线画在标记影子的下面,信息窗口在其他的覆盖对象之上。这个例子里,我们的覆盖对象负载地图上,所以,我们把它放置在Z序最小的G_MAP_MAP_PANE层,就像GPolyline。在类参考里面可以得到完整的地图层的列表。

// 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(37.4419, -122.1419), 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));

显示范例 (customoverlay.html)

地理译码示例

您可以直接发HTTP请求的方式来访问Maps API的地理译码器,或者可以用GClientGeocoder对象在JavaScript下发送请求。这样您可以从您的服务器进行地理译码调用或者让用户的浏览器进行这个操作。如果您有一个相对稳定的地址数据库(待售房产的列表),我们建议您通过HTTP请求一次性获得地理译码信息,然后把这些地址缓存在您自己的数据库呢。这让对用户来说您的网站会更快,而且可以减少您对每日地理译码请求限额的消耗。如果您不能访问服务器段脚本,那么您可以用JavaScript来发送地理译码请求。

JavaScript下使用地理译码

在JavaScript下您可以用GClientGeocoder对象来访问地理译码器。getLatLng方法可以用来把地址转换为GLatLng(经纬度)。因为地理译码需要发送请求到Google的服务器,所以这可能会花点时间。为了避免您的脚本一直等待,您需要指定一个函数在回应后触发。在这个例子里,我们把一个地址地理译码,然后在这个点上加一个标记,然后打开一个信息窗口显示地址。

var map = new GMap2(document.getElementById("map"));
var geocoder = new GClientGeocoder();

function showAddress(address) {
  geocoder.getLatLng(
    address,
    function(point) {
      if (!point) {
        alert(address + " not found");
      } else {
        map.setCenter(point, 13);
        var marker = new GMarker(point);
        map.addOverlay(marker);
        marker.openInfoWindowHtml(address);
      }
    }
  );
}

显示范例 (geocoder.html)

展开结构化地址信息

如果您想访问地址的结构化信息,GClientGeocoder提供getLocations方法返回一个JSON对象包含下列的信息。译注:JSON(JavaScript Object Notation),是一种轻量级的数据交换格式,详情请见http://json.org/

  • Status
    • request -- 请求类型,在这里永远是geocode
    • code -- 一个回应代码(近似于HTTP状态代码)指示地理译码是否成功。参看状态代码全列表。
  • Placemark -- 如果地理译码器找到多个结果,那么会返回多个地点。
    • address -- 一个格式良好的地址。
    • AddressDetails -- 格式化为xAL(可扩充地址语言)格式的地址。xAL是地址信息格式化方面的国际标准。
      • Accuracy -- 这个属性用来说明对给定地址地理译码的结果的精确度。参看精确度的取值范围。
    • Point -- 在三维空间的点。
      • coordinates -- 地址的经纬度以及海拔高度。目前,海拔总是为0。

这是用地理译码器查询Google总部地址返回的JSON对象。

{
  "name": "1600 Amphitheatre Parkway, Mountain View, CA, USA",
  "Status": {
    "code": 200,
    "request": "geocode"
  },
  "Placemark": [
    {
      "address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
      "AddressDetails": {
        "Country": {
          "CountryNameCode": "US",
          "AdministrativeArea": {
            "AdministrativeAreaName": "CA",
            "SubAdministrativeArea": {
              "SubAdministrativeAreaName": "Santa Clara",
              "Locality": {
                "LocalityName": "Mountain View",
                "Thoroughfare": {
                  "ThoroughfareName": "1600 Amphitheatre Pkwy"
                },
                "PostalCode": {
                  "PostalCodeNumber": "94043"
                }
              }
            }
          }
        },
        "Accuracy": 8
      },
      Point: {
        coordinates: [-122.083739, 37.423021, 0]
      }
    }
  ]
}

在这个例子里,我们用getLocations方法对地址进行地理译码,从JSON对象中展开良好格式的地址版本,和两个字母的国家代码显示在信息窗口上。

var map;
var geocoder;

function addAddressToMap(response) {
  map.clearOverlays();
  if (!response || response.Status.code != 200) {
    alert("/"" + address + "/" not found");
  } else {
    place = response.Placemark[0];
    point = new GLatLng(place.Point.coordinates[1],
                        place.Point.coordinates[0]);
    marker = new GMarker(point);
    map.addOverlay(marker);
    marker.openInfoWindowHtml(place.address + '<br>' +
    '<b>Country code:</b> ' + place.AddressDetails.Country.CountryNameCode);
  }
}

显示范例 (geocoder2.html)

缓存地理译码

GClientGeocoder类默认情况下装备了一个客户端的缓存。这个缓存会保存地理译码回应,这样当相同的地址被查询的时候,回应会直接从客户端的缓存中返回而不用连接到Google的地理译码器。想关闭缓存机制,可以用参数null调用GClientGeocoder类的setCache方法。然而,我们推荐您保留缓存机制,因为这可以提高性能。要改变使用的缓存,可以用新缓存作为参数调用setCache方法。要清空当前的缓存,可以调用reset方法。

我们鼓励开发者创建它们自己的客户端缓存。在这个例子里,我们用计算好的六个国家的首都的信息构建了一个缓存。首先,我们创建地理译码回应的数组。然后我们创建一个定制的缓存。缓存定义好后,我们用setCache方法设置它。对保存在缓存中的对象没有严格的检查,所以你可以你可以保存其他的信息(比如人口数目)等等。

// Builds an array of geocode responses for the 6 capitals
var city = [
  {
    name: "Washington, DC",
    Status: {
      code: 200,
      request: "geocode"
    },
    Placemark: [
      {
        address: "Washington, DC, USA",
        population: "0.563M",
        AddressDetails: {
          Country: {
            CountryNameCode: "US",
            AdministrativeArea: {
              AdministrativeAreaName: "DC",
              Locality: {
                LocalityName: "Washington"
              }
            }
          },
          Accuracy: 4
        },
        Point: {
          coordinates: [-77.036667, 38.895000, 0]
        }
      }
    ]
  },
  ... // etc., and so on for other cities
];

  var map;
  var geocoder;

  // CapitalCitiesCache is a custom cache that extends the standard GeocodeCache.
  // We call apply(this) to invoke the parent's class constructor.
  function CapitalCitiesCache() {
    GGeocodeCache.apply(this);
  }

  // Assigns an instance of the parent class as a prototype of the
  // child class, to make sure that all methods defined on the parent
  // class can be directly invoked on the child class.
  CapitalCitiesCache.prototype = new GGeocodeCache();

  // Override the reset method to populate the empty cache with
  // information from our array of geocode responses for capitals.
  CapitalCitiesCache.prototype.reset = function() {
    GGeocodeCache.prototype.reset.call(this);
    for (var i in city) {
      this.put(city[i].name, city[i]);
    }
  }

  map = new GMap2(document.getElementById("map"));
  map.setCenter(new GLatLng(37.441944, -122.141944), 6);

  // Here we set the cache to use the UsCitiesCache custom cache.
  geocoder = new GClientGeocoder();
  geocoder.setCache(new CapitalCitiesCache());

显示范例 (geocodercache.html)

HTTP请求方式

想直接让服务器端脚本访问地理译码器,可以发请求到http://maps.google.com/maps/geo?,把如下参数加在地址里面:

  • q -- 你想地理译码的地址。
  • key -- 你的API key。
  • output -- 输出格式。选项是xmlkmlcsv或者json

在这个例子里,我们请求google总部的地理坐标。

http://maps.google.com/maps/geo?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA&output=xml&key=abcdefg

如果你指定输出格式为json,那么回应就是格式化好的JSON对象,如上面的例子所示。如果你指定输出格式为xml或者kml,回应返回格式为XML或者VML。XML和VML这两种输出格式内容完全一致,唯一的不同只是MIME类型。

例如,这是地理译码器对"1600 amphitheatre mtn view ca"的回应。

<kml>
  <Response>
    <name>1600 amphitheatre mtn view ca</name>
    <Status>
      <code>200</code>
      <request>geocode</request>
    </Status>
    <Placemark>
      <address>
        1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA
      </address>
      <AddressDetails Accuracy="8">
        <Country>
          <CountryNameCode>US</CountryNameCode>
          <AdministrativeArea>
            <AdministrativeAreaName>CA</AdministrativeAreaName>
           <SubAdministrativeArea>
             <SubAdministrativeAreaName>Santa Clara</SubAdministrativeAreaName>
             <Locality>
               <LocalityName>Mountain View</LocalityName>
               <Thoroughfare>
                 <ThoroughfareName>1600 Amphitheatre Pkwy</ThoroughfareName>
               </Thoroughfare>
               <PostalCode>
                 <PostalCodeNumber>94043</PostalCodeNumber>
               </PostalCode>
             </Locality>
           </SubAdministrativeArea>
         </AdministrativeArea>
       </Country>
     </AddressDetails>
     <Point>
       <coordinates>-122.083739,37.423021,0</coordinates>
     </Point>
   </Placemark>
  </Response>
</kml>

如果你更喜欢更短的回应以利于解析,而且不需要特定特性比如多个结果或者良好的格式,我们提供csv输出格式。csv格式的回应包含4个用逗号分隔的数字。第一个数字是状态代码,第二个是精确度,第三个是纬度,第四个是经度。下面是三个地址,按照精确度增量排序:"State St, Troy, NY", "2nd st & State St, Troy, NY" and "7 State St, Troy, NY"

200,6,42.730070,-73.690570
200,7,42.730210,-73.691800
200,8,42.730287,-73.692511

错误排除

如果你的代码不能正常工作,这里有些步骤可能帮您解决您的问题:

  • 确保你的API Key是正确的。
  • 检查你的拼写。记住JavaScript是大小写敏感的语言。
  • 使用JavaScript调试器。在Firefox下,你可以使用JavaScript控制台或者Venkman Debugger。在IE下,你可以使用微软脚本调试器。
  • 搜索Maps API讨论组。如果你不能找到你问题的答案,发帖提问。
  • 查看其他资源获取第三方开发者资源。

其他资源

这里有一些额外的资源。注意这些站点不属于Google。

  • Mapki一个关于Maps API的流行wiki,包括FAQ页面。

API纵览

API纵览描述了Maps API的核心概念。为了查看全部类和方法的列表,参看Maps API类参考。

GMap2类

GMap2类的实例用来在页面展现地图。你可以创建多个类的实例(一个地图一个)。当您创建了一个地图实例,您指定一个页面元素(通常是div元素)来包含这个地图。除非您明确的指定地图的尺寸,否则地图大小会取决于容器的尺寸。

GMap2类的方法可以控制地图的中心和缩放级别,添加删除覆盖对象(例如,GMarkerGPolyline)。还有方法可以用来打开一个信息窗口,就像你在Google Maps里面看到的。更多信息参看信息窗口。

更多GMap2类的信息,参看GMap2类参考。

事件

您可以利用事件监听器在您的程序里面加入动态元素。一个对象导出命名事件,您的程序可以用静态方法GEvent.addListenerGEvent.bind来"监听"这些事件。例如,这个代码片断在每次用户点击的时候显示一个警告框:

var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
GEvent.addListener(map, "click", function() {
  alert("You clicked the map.");
});

GEvent.addListener把一个函数当作第三个参数,用来指定时间句柄的相应函数。想把事件绑定到类实例的方法上,可以用GEvent.bind方法。在下面的例子里,应用程序类实例把地图事件绑定在他的方法上,在触发的时候修改类的状态:

function MyApplication() {
  this.counter = 0;
  this.map = new GMap2(document.getElementById("map"));
  this.map.setCenter(new GLatLng(37.4419, -122.1419), 13);
  GEvent.bind(this.map, "click", this, this.onMapClick);
}

MyApplication.prototype.onMapClick = function() {
  this.counter++;
  alert("You have clicked the map " + this.counter + " " +
        (this.counter == 1 ?"time" : "times"));
}

var application = new MyApplication();

显示范例 (bind.html)

信息窗口

每个地图有一个"信息窗口"用来浮在地图之上显示HTML内容。信息窗口看起来像一个漫画书的文字气泡;它包含一个内容区域和一个锥形箭头,锥形的箭头指向地图上的指定点。你可以在Google地图上点击一个标记,就可以看到信息窗口。

一个地图同时只能显示一个信息窗口,但你可以移动信息窗口,或者修改它的内容。

信息窗口的基本方法是openInfoWindow,需要提供一个点和一个HTML DOM元素作为参数。HTML DOM元素会被追加到信息窗口的容器内,而信息窗口的锥形箭头会指向给定的点。

openInfoWindowHtml方法很类似,只是它用HTML字符串作为参数而不是HTML DOM元素。

要在如标记之类的一个覆盖对象之上显示信息窗口的话,您可以设置第三个可选参数,信息窗口尖端和给定点之间的偏移量。所以,如果你的标记有10个像素那么高,你可以把点偏移量GSize(0, -10)传给方法。

GMarker类导出了openInfoWindow方法,可以处理你的图标形状和尺寸相应的偏移量,所以你不用担心如何自己去计算这个值。

更多信息请查看GMap2GMarker的类参考。

覆盖对象

覆盖对象是覆盖在地图上有固定经纬度坐标位置的对象,所以当你拖动地图或者改变地图类型的时候,他们也会跟着移动。

Maps API支持两种类型的覆盖对象:标记,地图上的图标;折线,用一系列点形成的折线。

标记和图标

GMarker类的构造器有两个参数,一个是图标,一个是点,还支持一些事件,比如"点击"事件。参看overlay.html在地图上创建标记的一个简单例子。

创建标记最难的部分是指定一个图标,这很复杂是因为Maps API里的一个图标需要很多图片构成。

每个图标包含一个前景图片和一个影子。影子应该由前景图片倾斜45度(向右上方)构成,而影子图片左下角应该跟前景图片的左下角对齐。影子图片应该是24位的PNG图形格式背景应该透明,这样影子的边缘在地图上面才能正确显示。

GIcon类需要您在初始化图标的时候指定这些图片的尺寸,这样Maps API就能用恰当的尺寸来创建这些图片。这是创建一个图标所需的最小代码(图标来自Google地图):

var icon = new GIcon();
icon.image = "http://www.google.com/mapfiles/marker.png";
icon.shadow = "http://www.google.com/mapfiles/shadow50.png";
icon.iconSize = new GSize(20, 34);
icon.shadowSize = new GSize(37, 34);

GIcon还有几个属性,如果设置就可以得到最大化的浏览器兼容性以及图标的功能性。例如,imageMap属性可以用来设定图标的不透明区域的形状。如果你不设定这个属性,在Firefox/Mozilla下整个图片范围(包括透明区域)都可以点击。更多的信息参看GIcon类参考。

折线

GPolyline类的构造器把一个点的数组作为参数,根据给定点的顺序创建连接这些点的一系列线段。您还可以指定这些线的颜色,宽度和透明度。颜色应该使用16进制数字表现,如#ff0000而不要用redGPolyline类不能理解颜色名。

下面的代码片断创建两点之间10个像素宽的红色折线:

var polyline = new GPolyline([
  new GLatLng(37.4419, -122.1419),
  new GLatLng(37.4519, -122.1519)
], "#ff0000", 10);
map.addOverlay(polyline);

在Internet Explorer下,Google地图使用VML来画折线(更多信息请看XHTML和VML)。在所有其它的浏览器,我们从Google服务器请求线的图片覆盖在地图上,在地图缩放和拖动的时候刷新图片。

控件

想为您的地图加入缩放工具条之类的空间,请使用addControl方法。Maps API包括很多可以用在您的地图上的控件:

  • GLargeMapControl - 大号平移和缩放控件,位置是左上角。
  • GSmallMapControl - 小号平移和缩放控件,位置是左上角。
  • GSmallZoomControl - 大号缩放控件,位置是左上角。
  • GScaleControl - 地图比例尺。
  • GMapTypeControl - 选择地图类型的控件。
  • GOverviewMapControl New! - 位于屏幕一角可以收起来的概览图。

例如,如果想在您的地图上添加一个平移和缩放控件,您可以包含下面的这行代码:

map.addControl(new GLargeMapControl());

addControl方法有一个可选参数GControlPosition用于让您自己指定控件的位置。如果这个参数被省略,Maps API将采用控件的默认位置。这个例子加入一个地图类型空间到右下角留空10个像素的位置:

map.addControl(new GMapTypeControl(),
               new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(10, 10)));

更多信息请看GControlPosition类参考。

XML和RPC

Google Maps API用工厂方法(译注:设计模式)创建XmlHttpRequest对象,可以支持新版本IE,Firefox和Safari。下面的例子下载一个叫做myfile.txt的文件然后用JavaScriptalert函数显示这个文件的内容:

var request = GXmlHttp.create();
request.open("GET", "myfile.txt", true);
request.onreadystatechange = function() {
  if (request.readyState == 4) {
    alert(request.responseText);
  }
}
request.send(null);

API还引入了针对典型的HTTP GET请求的类似方法叫GDownloadUrl,不需要XmlHttpRequestreadyState检查。上面的例子用GDownloadUrl函数改写如下:

GDownloadUrl("myfile.txt", function(data, responseCode) {
  alert(data);
});

您可以用静态方法GXml.parse来解析XML文档,它仅用一个XML字符串当作唯一的参数。这个方法兼容大多数现代浏览器,而当他遇到不支持本地XML解析的浏览器它会抛出一个异常。

更多信息请看GXmlHttpGXml类参考。

减少浏览器内存泄露

Google Maps API鼓励使用闭包/Closures(译注:闭包可以理解为把一段代码作为参数传递给一个函数,类似匿名函数之类的概念。)以及在事件处理系统GEvent中把事件绑定到DOM节点上,这些做法都不可避免的会造成浏览器的内存泄露,尤其是Internet Explorer。Maps API的第二版引入一个GUnload()函数,用于最大限度地消除可能引发内存泄露的循环引用。您应该在页面的unload事件中调用GUnload()函数来降低您的应用程序内存泄露的风险:

<body onunload="GUnload()">

这个函数确实可以消除Google地图在Internet Explorer下的内存泄露,但是如果您比较关心内存消耗问题,您仍旧应该用Drip之类的工具测试您自己网站的内存泄露情况。

你可能感兴趣的:(JavaScript,function,api,浏览器,XHTML,Google)