简明现代魔法 -> 软件项目 -> Google Maps 服务

Google Maps 服务

2009-11-27

服务概述

Google 地图 API 会定期扩展,添加新的功能和特性,通常这些功能和特性会先在 ditu.google.cn 上发布。本部分讲述这些服务。注意:由于“服务”的定义在某种程度上较难懂,因此本部分会涉及的内容也较广。我们基本上将无法放到其他部分的内容都放到了本部分中。

XML 和数据解析

Google 地图 API 导出一种工厂方法,用于创建适用于各种浏览器的 XmlHttpRequest() 对象(在 Internet Explorer、Firefox 和 Safari 的最新版本中均可使用)。和所有的 XmlHttpRequest 一样,任何检索的文件都必须在本地域中。以下示例下载名为 myfile.txt 的文件,并使用 JavaScript alert() 显示其内容:

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() 方法,无需检查 XmlHttpRequest() readyState。上面的示例可以如下使用 GDownloadUrl() 重新编写:

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

可以使用静态方法 GXml.parse() 解析 XML 文档,该方法取 XML 的一个字符串作为其唯一的参数。此方法与多数流行的浏览器兼容,但如果浏览器本身不支持 XML 解析,它会抛出异常。

在此示例中,我们使用 "data.xml"GDownloadUrl 方法下载一个静态文件 (),它包含一个 XML 格式的经纬坐标列表。当下载完成后,我们使用 GXml 解析该 XML,并在 XML 文档中的每个点处创建一个标记符。

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);

// Download the data in data.xml and load it on the map. The format we
// expect is:
// <markers>
//   <marker lat="39.945" lng="116.375"/>
//   <marker lat="39.872" lng="116.423"/>
// </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));
  }
}); 

查看示例 (xhr-requests.php)

地址解析

地址解析是将地址(如“1600 Amphitheatre Parkway, Mountain View, CA”)转换为地理坐标(如经度 -122.083739 和纬度 37.423021)的过程,可以用于放置标记符或定位地图。Google 地图 API 包含地址解析服务,可以通过 HTTP 请求直接访问,也可以通过使用 GClientGeocoder 对象来访问。

请注意,地址解析是一种时间和资源密集型任务。尽量为您的地址预先进行地址解析(使用 HTTP 地址解析器或其它地址解析服务),并使用地址解析缓存存储您的结果。

地址解析对象

可以通过 GClientGeocoder 对象访问 Google 地图 API 地址解析服务。使用 GClientGeocoder.getLatLng() 将字符串地址转换为 GLatLng。此方法采用要转换的字符串地址以及在检索到地址后要执行的回调函数作为参数。该回调函数是必要的,因为地址解析涉及向 Google 的服务器发送请求,可能需要一些时间。

在此示例中,我们将对一个地址进行地址解析,在该点添加标记,并打开一个显示该地址的信息窗口。请注意,该回调函数作为函数显式声明传递。

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

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

查看示例 (geocoding-simple.php)

还可以通过 GLatLngBounds 方法修改地图 API 地址解析器以指定解析结果在指定的视口内(视口是一个 GClientGeocoder.setViewport() 类型的矩形区域)。您可以使用 GClientGeocoder.setBaseCountryCode() 方法返回为特定地区(国家)定制的结果。可以对 Google 地图主应用程序提供地址解析的每个主要地区发送地址解析请求。例如,搜索“Toledo”将返回西班牙地区内(http://maps.google.es)由国家或地区代码“es”指定的不同结果,而不是默认的美国 (http://maps.google.com) 地区内的结果。

抽取结构化地址

如果要访问有关某个地址的结构化信息,GClientGeocoder 还提供了 getLocations() 方法,该方法返回包括以下信息的 JSON 对象:

  1. Status
    • request - 请求类型。在本例中,始终是 geocode。
    • code - 响应代码,类似于 HTTP 状态代码,指示地址解析请求是否成功。
  2. Placemark - 如果地址解析器发现多个匹配项,则可能返回多个地标。
    • address - 格式化良好,大小写正确的地址版本。
    • AddressDetails - 格式化为 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);
  }
}  

查看示例 (geocoding-extraction.php)

反向地址解析

术语“地址解析”通常是指将用户可阅读的地址转换成地图上的点。将地图上的点反向转换成用户可阅读的地址的过程称为“反向地址解析”。

GClientGeocoder.getLocations() 方法支持标准地址解析和反向地址解析。如果为此方法传递了一个 GLatLng 对象而不是 String 地址,地址解析器将执行反向查询并返回最接近的可寻址位置的结构化 JSON 对象。请注意,如果提供的 GLatLng 与任何可寻址位置都不完全匹配,那么,最接近的可寻址位置与查询的原始经度值和纬度值之间可能存在一段距离。

注意:反向地址解析不属于精密科学。地址解析器会试图在一定的偏差范围内查找最接近的可寻址位置;如果找不到匹配项,地址解析器通常会返回 G_GEO_UNKNOWN_ADDRESS (602) 状态代码。

var map;
var geocoder;
var address;

function initialize() {
  map = new GMap2(document.getElementById("map_canvas"));
  map.setCenter(new GLatLng(39.90822, 116.4055), 13);
  map.addControl(new GLargeMapControl);
  GEvent.addListener(map, "click", getAddress);
  geocoder = new GClientGeocoder();
}

function getAddress(overlay, latlng) {
  if (latlng != null) {
    address = latlng;
    geocoder.getLocations(latlng, showAddress);
  }
}

function showAddress(response) {
  map.clearOverlays();
  if (!response || response.Status.code != 200) {
    alert("Status Code:" + response.Status.code);
  } 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(
        '<b>orig latlng:</b>' + response.name + '<br/>' + 
        '<b>latlng:</b>' + place.Point.coordinates[0] + "," + place.Point.coordinates[1] + '<br>' +
        '<b>Status Code:</b>' + response.Status.code + '<br>' +
        '<b>Status Request:</b>' + response.Status.request + '<br>' +
        '<b>Address:</b>' + place.address + '<br>' +
        '<b>Accuracy:</b>' + place.AddressDetails.Accuracy + '<br>' +
        '<b>Country code:</b> ' + place.AddressDetails.Country.CountryNameCode);
  }
}  

查看示例 (geocoding-reverse.php)

地址解析缓存

GClientGeocoder 默认配备有客户端缓存。该缓存存储地址解析器响应,当重新对地址进行地址解析时可以加快响应。可以通过执行 GClientGeocoder 对象的 setCache() 方法并传递一个 null 参数来关闭缓存。但我们建议保留缓存,因为它可以提高性能。要更改 GClientGeocoder 使用的缓存,请调用 setCache() 方法并传递一个新缓存作为参数。要清空当前缓存的内容,请对地址解析器或直接对缓存调用 reset() 方法。

我们鼓励开发人员构建自己的客户端缓存。在此示例中,我们构造了一个缓存,包含对地址解析 API 所涵盖的国家或地区中的六个首都或首府城市的预先计算的地址解析器响应。首先,我们构建了一个地址解析响应数组。然后,我们创建了扩展标准 GeocodeCache 的自定义缓存。定义该缓存后,我们调用 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_canvas"));
  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());  

查看示例 (geocoding-cache.php)

本地搜索

如果要向您的网站中添加本地搜索功能,可以使用 Google AJAX 搜索 API 在网站中嵌入本地搜索控件。此控件是 GControl 对象的一个子类,是一个很好的创建自定义控件的示例。

向您的地图 API 应用程序中添加此控件之前,需要添加 Google AJAX 搜索 API 的网址,并使用地图 API 密钥才能使用该服务。您还需要加载该控件对象的样式表,如下所示:

// Load the Code
<script src="http://www.google.cn/uds/api?file=uds.js&v=1.0&key=ABCDEF"
      type="text/javascript"></script>
<script src="http://www.google.cn/uds/solutions/localsearch/gmlocalsearch.js" 
      type="text/javascript"></script>

// Load the Style Sheets
<style type="text/css">
  @import url("http://www.google.cn/uds/css/gsearch.css");
  @import url("http://www.google.cn/uds/solutions/localsearch/gmlocalsearch.css");
</style>  

或者可以使用 AJAX 加载器,通过公共加载器加载所有这些模块。

执行完这些准备任务之后,加载控件本身相对比较简单:

// create your map
var map = new GMap2(document.getElementById("map_canvas"));

// create a local search control and add it to your map
var lsc = new google.maps.LocalSearch(); 
map.addControl(new google.maps.LocalSearch());  

查看示例 (control-localsearch.php)

KML/GeoRSS 叠加层

Google 地图 API 支持用于显示地理信息的 KML 和 GeoRSS 数据格式。使用 GGeoXml 对象将这些数据格式添加到地图,该对象的构造函数采用可公开访问的 XML 文件的网址。GGeoXml 地标显示为 GMarker,而 GGeoXml 折线和多边形显示为 Google 地图 API 折线和多边形。KML 文件中的 <GroundOverlay> 元素显示为地图上的 GGroundOverlay 元素。

使用 addOverlay() 方法将 GGeoXml 对象添加到地图。(您可以使用 removeOverlay() 从地图中删除它们。)KML 和 GeoRSS XML 文件均受支持。请注意,GGeoXml 是 Google 地图 API 中的一个模块化对象,并且在首次使用后才会完全加载。因此,请仅当页面完全加载后再调用其构造函数。此操作通常通过在 <body> 的 onload 处理程序中调用 GGeoXml 构造函数来完成。

// The GGeoXml constructor takes a URL pointing to a KML or GeoRSS file.
// You add the GGeoXml object to the map as an overlay, and remove it as an overlay as well.
// The Maps API determines implicitly whether the file is a KML or GeoRSS file.

var map;
var geoXml;

function initialize() {
  if (GBrowserIsCompatible()) {
    map = new GMap2(document.getElementById("map_canvas")); 
    geoXml = new GGeoXml("http://mapgadgets.googlepages.com/cta.kml");
    map.addControl(new GLargeMapControl());
    map.setCenter(new GLatLng(39.917, 116.397), 11); 
    map.addControl(new GLargeMapControl());
    map.addOverlay(geoXml);
  }
}   

查看 GeoRSS 示例 (geoxml-rss.php)

查看 KML 示例 (geoxml-kml.php)

交通叠加层

Google 地图 API 可让您使用 GTrafficOverlay 对象(其应用 GOverlay 接口)向地图中添加交通信息。可以使用 GMap2.addOverlay() 方法向地图中添加交通信息。GTrafficOverlay 有两种方法(hide() 和 show())用于切换是否显示交通叠加层。只有支持的城市才能显示交通信息。

也可以使用 GTrafficOverlayOptions 对象常量向 GTrafficOverlay 构造函数传递选项。

// The GTrafficOverlay is unique in that only one object of that type 
// should be added to a map. Adding multiple traffic overlays produces
// no added benefit.

var map;
var trafficInfo;

function initialize() {
  map = new GMap2(document.getElementById("map_canvas")); 
  map.setCenter(new GLatLng(49.496675,-102.65625), 3); 
  var trafficOptions = {incidents:true};
  trafficInfo = new GTrafficOverlay(trafficOptions);
  map.addOverlay(trafficInfo);
}  

查看交通示例 (trafficOverlay.php)

行车路线

您可以使用 GDirections 对象添加该功能来计算行车路线(使用各种交通方式)。GDirections 对象使用查询字符串(例如“New York, NY to Chicago, IL”)或提供的文字经度/纬度(例如“-73.967257, 40.712882 to -87.770677, 41.943181”)请求和接收行车路线结果。GDirections 对象还支持使用一系列路标的多段行车路线。行车路线可以在地图上显示为绘制路线的折线和/或 <div> 元素中的一系列文本描述(例如“向右转到 Williamsburg Bridge 斜道”)。

要在 Google 地图 API 中使用行车路线,请创建类型为 GDirections 的对象,并指定用于接收和显示结果的 GMap2 对象和/或 <div>。默认情况下,地图居中并且通过返回的路线限制边界(尽管可以在 GDirectionOptions 对象中使用参数进行更改)。

加载行车路线

行车路线使用 GDirections.load() 方法请求。此方法取查询字符串和一组可选的 GDirectionsOptions 参数。有以下选项可用:

出行模式

默认情况下,行车路线会假定您是驾车行驶,但您可以通过在调用 Directions.load() 方法时传递 GTravelMode 来请求其他出行模式。支持以下出行方式:

注意:步行路线有时可能不包括畅通的步行街,因此步行路线仅当您在 GDirections 构造函数中提供了 <div> 时才受支持;此 <div> 用于在返回的分路段显示文字路线中向用户显示警告。如果没有此类 <div>,则在请求步行路线时就会返回错误。

处理返回的行车路线

如果 GDirections 对象使用提供的 GMap2 对象构建,则返回的行车路线将包含折线叠加层。如果使用提供的 <div> 元素构造 GDirections 对象,则返回的行车路线将包含一个 GRoute 对象,该对象包含一组 GStep 对象。(如果行车路线包括多点行车路线,则返回的行车路线将包含多个 GRoute 对象,其中每个都包含一系列的 GStep 对象。)

请注意行车路线对象不会立即填充此返回信息。因此,GDirections 对象定义了一个“load”事件,以截获该事件来确定此状态。

默认情况下,返回行车路线后,地图会显示一条显示路线的折线,而文字行车路线则会显示在为达到此目的而提供的 <div> 中。GDirections 对象还会内部存储您可以使用 GDirections.getPolyline() 和/或 GDirections.getRoute(i:Number) 方法检索的结果。可以使用 GRoute.getStep(i:Number) 方法检索路线中的路段,使用 GStep.getDescriptionHtml() 方法检索该路段的 HTML 摘要。(请参见下面的路线和路段。)

GDirections 对象还会触发您可以截获的三个事件:

// Create a directions object and register a map and DIV to hold the 
// resulting computed directions

var map;
var directionsPanel;
var directions;

function initialize() {
  map = new GMap2(document.getElementById("map_canvas"));
  directionsPanel = document.getElementById("my_textual_div");
  map.setCenter(new GLatLng(49.496675,-102.65625), 3);
  directions = new GDirections(map, directionsPanel);
  directions.load("from: 500 Memorial Drive, Cambridge, MA to: 4 Yawkey Way, Boston, MA 02215 (Fenway Park)");
}  

查看示例 (directions-simple.php)

以下示例与第一个示例相同,只是行车路线通过传递 G_TRAVEL_MODE_WALKING 调用:

查看示例 (directions-walking.php)

路线和路段

GDirections 对象还支持多点的行车路线,可以使用 GDirections.loadFromWaypoints() 方法构建。此方法取文本输入地址或文本经纬度点的数组。每个单独的沿途路标均计算为单独的路线并在单独的 GRoute 对象中返回,其中每个都包含一系列的 GStep 对象。

GRoute 对象存储路线的路段(类型为 GStep)数目、路线的起点和终点地址解析以及计算出的其他信息,如距离、历时和终点的精确经纬度(如果地址解析不依赖于路段,则可能与终点地址解析不同)。每个 GStep 对象还包含文本描述(例如“通过到 San Jose 的斜道驶上 US-101 S”)以及计算出的信息,包括距离、历时和精确经纬度。

查看示例 (directions-advanced.php)

随机文章推荐
网站分类


注:如需转载本文,请注明出处(原文链接),谢谢。更多精彩内容,请进入简明现代魔法首页。

进入新博客
喜欢本文,就分享它吧
给我留言
您的名字:
您的邮件:
您的网站:


 

copyright © 2009 简明现代魔法    学习、分享、进步

power by Gonn 感谢所有关心和支持本站的朋友们