一切就绪!

着手开发前,请先阅读我们的开发者文档

激活 Google Maps JavaScript API

为帮助您起步,我们将引导您在 Google Developers Console 中先完成几项任务:

  1. 创建或选择项目
  2. 激活 Google Maps JavaScript API 及相关服务
  3. 创建相应密钥
继续

Places 库

概览

Google Places JavaScript 库中的函数可以帮助您的应用搜索规定的区域(例如地图的边界范围或围绕某个固定点的圆形区域)内包含的地点(在此 API 中定义为场所、地理位置或著名景点)。

Google Places API 提供了自动完成功能,可用来让您的应用具有 Google 地图搜索字段的提前键入搜索行为。当用户开始键入地址时,自动完成功能将填补余下内容。如需了解详细信息,请参阅自动完成功能的文档

入门指南

在 Google Maps JavaScript API 中使用 Places 内容库之前,首先要确保在为 Google Maps JavaScript API 设置的同一项目的 Google API Console 中启用 Google Places API Web Service。

要查看已启用 API 的列表,请执行以下操作:

  1. 转至 Google API Console
  2. 点击 Select a project 按钮,然后选择为 Google Maps JavaScript API 设置的同一项目并点击 Open
  3. Dashboard 上的 API 列表中,寻找 Google Places API Web Service
  4. 如果在列表中看到该 API,则大功告成。如果列出该 API,请执行以下操作将其启用:
    1. 在页面顶部,选择 ENABLE API 以显示 Library 标签。也可从左侧菜单中选择 Library
    2. 搜索 Google Places API Web Service,然后从结果列表中选择它。
    3. 选择 ENABLE。流程完成时,Google Places API Web Service 即会出现在 Dashboard 上的 API 列表中。

加载内容库

Places 服务是一个独立于主 Maps JavaScript API 代码的自包含内容库。要使用此库中包含的功能,必须先在 Maps API bootstrap URL 中使用 libraries 参数加载该库。

<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places"></script>

如需了解详细信息,请参阅库概览

使用限额和政策

配额

根据 Google Places API Web Service 的使用限额文档所述,Google Places API Web Service 和地点自动填充共享使用配额。这些使用限额在使用 Places Library in the Google Maps JavaScript API 时同样适用。每日使用量按客户端与服务器端请求次数之和计算。

政策

必须按照所介绍的适用于 Google Places API Web Service 的政策使用 Places Library in the Google Maps JavaScript API。

地点搜索

借助“地点”服务,您可以执行四种类型的搜索:

  • 附近地点搜索根据用户位置返回附近地点列表。
  • 文本搜索根据搜索字符串返回附近地点列表,例如:“Pizza”。
  • 雷达搜索返回一个包含指定搜索半径范围内大量地点的列表,但其详细程度不及附近地点搜索和文本搜索。
  • 地点详情请求返回有关某个特定地点的更为详细的信息,包括用户评论。

返回的信息可以包括诸如餐馆、商店和办事处之类的场所,以及“地理编码”结果,它表示地址、城镇和城市等政治区域以及其他景点。

附近地点搜索请求

通过附近地点搜索,您可以根据关键词或类型来搜索指定区域内的地点。附近地点搜索必须始终包含一个位置,可以通过以下两种方式之一来指定该位置:

  • LatLngBounds
  • 一个圆形区域,通过 location 属性(使用 LatLng 对象指定圆形区域的中心)和半径(以米为单位)的组合来定义。

通过调用 PlacesServicenearbySearch() 方法可发起 Places 附近地点搜索,该方法将返回一个 PlaceResult 对象的数组。请注意,从 3.9 版开始,nearbySearch() 方法就代替了 search() 方法。

service = new google.maps.places.PlacesService(map);
service.nearbySearch(request, callback);

此方法发出的请求中包含以下字段:

  • 下列两个字段中的任何一个:
    • bounds,它必须是一个用来定义矩形搜索区域的 google.maps.LatLngBounds 对象;或者
    • locationradius,前者需要传入一个 google.maps.LatLng 对象,而后者需要传入一个简单的整型数,代表圆形区域的半径(以米为单位)。所允许的最大半径为 50000 米。请注意,当 rankBy 设置为 DISTANCE 时,必须指定 location,但不能指定 radiusbounds
  • keyword可选)– 要与所有可用字段进行匹配的词语,包括但不限于 name(名称)、type(类型)和 address(地址),以及客户评论和其他第三方内容。
  • minPriceLevelmaxPriceLevel可选)– 使结果仅限于指定范围内的地点。有效值的范围在 0(最实惠)和 4(最昂贵)之间,包括 0 和 4 本身。
  • name可选)– 要与地点名称进行匹配的一个词语。结果将限制为包含所传递的 name 值的项。请注意,除了已列出的名称外,地点可能还有其他关联的名称。该 API 会尝试将传递的 name 值与所有这些名称进行匹配;因此,结果中可能会返回这样的地点:其列出的名称与搜索词语不匹配,但其关联的名称却与搜索词语匹配。
  • openNow可选)– 一个布尔值,指示“地点”服务应只返回发送查询时正在营业的地点。如果您在查询中包含此参数,就不会返回在 Google Places 数据库中未指定开放时间的地点。将 openNow 设置为 false 没有任何作用。
  • rankBy可选)– 指定结果的排列顺序。可能的值为:
    • google.maps.places.RankBy.PROMINENCE(默认值)。此选项根据重要性对结果排序。优先列出指定半径区域内的知名地点,而不是虽然匹配但不那么知名的附近地点。知名度受 Google 索引中地点排序、全球知名度和其他因素影响。当指定 google.maps.places.RankBy.PROMINENCE 时,radius 参数是必填的。
    • google.maps.places.RankBy.DISTANCE。此选项按其与指定的 location(必填)之间的距离以升序对结果进行排序。请注意,如果指定了 RankBy.DISTANCE,则不能指定自定义 bounds 和/或 radius。指定 RankBy.DISTANCE 时,keywordnametype 中的一项或多项为必填项。
  • types – 将结果限制为与指定类型匹配的地点。只能指定一个类型(如果提供了多个类型,系统会忽略第一项之后的所有类型)。请参阅支持的类型列表
  • types已弃用)– 一个包含一种或多种所支持类型的数组。服务将返回一组最适合给定类型集的结果。

您还必须传递一个回调方法给 nearbySearch() 以处理结果对象和 google.maps.places.PlacesServiceStatus 响应。

var map;
var service;
var infowindow;

function initialize() {
  var pyrmont = new google.maps.LatLng(-33.8665433,151.1956316);

  map = new google.maps.Map(document.getElementById('map'), {
      center: pyrmont,
      zoom: 15
    });

  var request = {
    location: pyrmont,
    radius: '500',
    types: ['store']
  };

  service = new google.maps.places.PlacesService(map);
  service.nearbySearch(request, callback);
}

function callback(results, status) {
  if (status == google.maps.places.PlacesServiceStatus.OK) {
    for (var i = 0; i < results.length; i++) {
      var place = results[i];
      createMarker(results[i]);
    }
  }
}

查看示例 (place-search.html)

文本搜索请求

Google 地点文本搜索服务是一项 Web 服务,可以根据一个字符串(例如,“pizza in New York”或“shoe stores near Ottawa”)返回一组地点的相关信息。该服务返回一个匹配此文本字符串和已设定的任何位置偏向的地点列表响应。搜索响应将包含一个地点列表。如需了解有关响应中任何地点的详细信息,您可以发送一个地点详情请求。

通过调用 PlacesServicetextSearch() 方法可发起文本搜索。

service = new google.maps.places.PlacesService(map);
service.textSearch(request, callback);

此方法发出的请求中包含以下字段:

  • query必填)要搜索的文本字符串,例如:“restaurant”。“地点”服务将根据此字符串返回候选匹配项,并按照其判断的相关程度对结果排序。如果搜索请求中还使用了 type 参数,此参数将变为可选参数。
  • 可选:
    • openNow – 一个布尔值,指示“地点”服务应只返回发送查询时正在营业的地点。如果您在查询中包含此参数,就不会返回在 Google Places 数据库中未指定开放时间的地点。将 openNow 设置为 false 没有任何作用。
    • minPriceLevelmaxPriceLevel – 使结果仅限于指定价位内的地点。有效值范围在 0(最实惠)和 4(最昂贵)之间,包括 0 和 4 本身。
    • 下列两个字段中的任何一个:
      • bounds – 一个用来定义要搜索的矩形范围的 google.maps.LatLngBounds 对象;或者
      • locationradius – 通过传递 locationradius 参数,可以使结果偏向指定的圆形区域内。这将指示“地点”服务优先显示该圆形区域内的结果。定义区域以外的结果也会显示。location 需要传入一个 google.maps.LatLng 对象,而 radius 需要传入一个简单的整型数,代表圆形区域的半径(以米为单位)。所允许的最大半径为 50000 米。
    • types – 将结果限制为与指定类型匹配的地点。只能指定一个类型(如果提供了多个类型,系统会忽略第一项之后的所有类型)。请参阅支持的类型列表
    • types已弃用)– 一个包含一种或多种所支持类型的数组。该服务将返回与任何指定类型相匹配的结果。

您还必须传递一个回调方法给 textSearch() 以处理结果对象和 google.maps.places.PlacesServiceStatus 响应。

var map;
var service;
var infowindow;

function initialize() {
  var pyrmont = new google.maps.LatLng(-33.8665433,151.1956316);

  map = new google.maps.Map(document.getElementById('map'), {
      center: pyrmont,
      zoom: 15
    });

  var request = {
    location: pyrmont,
    radius: '500',
    query: 'restaurant'
  };

  service = new google.maps.places.PlacesService(map);
  service.textSearch(request, callback);
}

function callback(results, status) {
  if (status == google.maps.places.PlacesServiceStatus.OK) {
    for (var i = 0; i < results.length; i++) {
      var place = results[i];
      createMarker(results[i]);
    }
  }
}

雷达搜索请求

通过雷达搜索,您可以根据关键词、类型或名称来搜索指定搜索半径范围内的地点。雷达搜索返回的结果比附近地点搜索或文本搜索要多,但结果中包含的字段要少一些。您可以调用 PlacesService.getDetails() 来获取有关响应中任何地点的详细信息。

radarSearch() 返回的 PlaceResult 对象仅包含以下属性:

  • geometry.location
  • place_id
  • reference注:如本页面上的弃用通告中所述,reference 已被弃用,取而代之的是 place_id。)

通过调用 PlacesServiceradarSearch() 方法可发起地点雷达搜索,该方法将返回一个最多包含 200 个 PlaceResult 对象的数组。

service = new google.maps.places.PlacesService(map);
service.radarSearch(request, callback);

此方法发出的请求中包含以下字段:

  • 下列两个字段中的任何一个:
    • bounds,它必须是一个用来定义矩形搜索区域的 google.maps.LatLngBounds 对象;或者
    • locationradius,前者需要传入一个 google.maps.LatLng 对象,而后者需要传入一个简单的整型数,代表圆形区域的半径(以米为单位)。所允许的最大半径为 50000 米。
  • 至少需要以下字段之一:
    • keyword可选)– 要与所有可用字段进行匹配的词语,包括但不限于 name(名称)、type(类型)和 address(地址),以及客户评论和其他第三方内容。
    • name可选)– 要与地点名称进行匹配的一个词语。结果将限制为包含所传递的 name 值的项。请注意,除了已列出的名称外,地点可能还有其他关联的名称。该 API 会尝试将传递的 name 值与所有这些名称进行匹配;因此,结果中可能会返回这样的地点:其列出的名称与搜索词语不匹配,但其关联的名称却与搜索词语匹配。
    • types – 将结果限制为与指定类型匹配的地点。只能指定一个类型(如果提供了多个类型,系统会忽略第一项之后的所有类型)。请参阅支持的类型列表
    • types已弃用)– 一个包含一种或多种所支持类型的数组。服务将返回一组最适合给定类型集的结果。
  • 可选:
    • minPriceLevelmaxPriceLevel可选)– 使结果仅限于指定价位内的地点。有效值范围在 0(最实惠)和 4(最昂贵)之间,包括 0 和 4 本身。
    • openNow – 一个布尔值,指示“地点”服务应只返回发送查询时正在营业的地点。如果您在查询中包含此参数,就不会返回在 Google Places 数据库中未指定开放时间的地点。将 openNow 设置为 false 没有任何作用。

您还必须将一个回调方法传递给 radarSearch() 以处理 PlaceResults 对象和 google.maps.places.PlacesServiceStatus

// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">

var map;
var infoWindow;
var service;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: -33.867, lng: 151.206},
    zoom: 15,
    styles: [{
      stylers: [{ visibility: 'simplified' }]
    }, {
      elementType: 'labels',
      stylers: [{ visibility: 'off' }]
    }]
  });

  infoWindow = new google.maps.InfoWindow();
  service = new google.maps.places.PlacesService(map);

  // The idle event is a debounced event, so we can query & listen without
  // throwing too many requests at the server.
  map.addListener('idle', performSearch);
}

function performSearch() {
  var request = {
    bounds: map.getBounds(),
    keyword: 'best view'
  };
  service.radarSearch(request, callback);
}

function callback(results, status) {
  if (status !== google.maps.places.PlacesServiceStatus.OK) {
    console.error(status);
    return;
  }
  for (var i = 0, result; result = results[i]; i++) {
    addMarker(result);
  }
}

function addMarker(place) {
  var marker = new google.maps.Marker({
    map: map,
    position: place.geometry.location,
    icon: {
      url: 'https://developers.google.com/maps/documentation/javascript/images/circle.png',
      anchor: new google.maps.Point(10, 10),
      scaledSize: new google.maps.Size(10, 17)
    }
  });

  google.maps.event.addListener(marker, 'click', function() {
    service.getDetails(place, function(result, status) {
      if (status !== google.maps.places.PlacesServiceStatus.OK) {
        console.error(status);
        return;
      }
      infoWindow.setContent(result.name);
      infoWindow.open(map, marker);
    });
  });
}
<div id="map"></div>
/* Always set the map height explicitly to define the size of the div
 * element that contains the map. */
#map {
  height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=places,visualization" async defer></script>
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">

var map;
var infoWindow;
var service;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: -33.867, lng: 151.206},
    zoom: 15,
    styles: [{
      stylers: [{ visibility: 'simplified' }]
    }, {
      elementType: 'labels',
      stylers: [{ visibility: 'off' }]
    }]
  });

  infoWindow = new google.maps.InfoWindow();
  service = new google.maps.places.PlacesService(map);

  // The idle event is a debounced event, so we can query & listen without
  // throwing too many requests at the server.
  map.addListener('idle', performSearch);
}

function performSearch() {
  var request = {
    bounds: map.getBounds(),
    keyword: 'best view'
  };
  service.radarSearch(request, callback);
}

function callback(results, status) {
  if (status !== google.maps.places.PlacesServiceStatus.OK) {
    console.error(status);
    return;
  }
  for (var i = 0, result; result = results[i]; i++) {
    addMarker(result);
  }
}

function addMarker(place) {
  var marker = new google.maps.Marker({
    map: map,
    position: place.geometry.location,
    icon: {
      url: 'https://developers.google.com/maps/documentation/javascript/images/circle.png',
      anchor: new google.maps.Point(10, 10),
      scaledSize: new google.maps.Size(10, 17)
    }
  });

  google.maps.event.addListener(marker, 'click', function() {
    service.getDetails(place, function(result, status) {
      if (status !== google.maps.places.PlacesServiceStatus.OK) {
        console.error(status);
        return;
      }
      infoWindow.setContent(result.name);
      infoWindow.open(map, marker);
    });
  });
}

查看示例 (place-radar-search.html)

搜索响应

状态代码

PlacesServiceStatus 响应对象包含了请求的状态,还可能包含调试信息,以帮助您跟踪地点请求失败的原因。可能的状态值为:

  • ERROR:连接 Google 服务器时遇到了问题。
  • INVALID_REQUEST:该请求无效。
  • OK:响应中包含有效结果。
  • OVER_QUERY_LIMIT:该网页已超过其请求限额。
  • REQUEST_DENIED:不允许该网页使用 PlacesService。
  • UNKNOWN_ERROR:由于服务器发生错误,因此无法处理该 PlacesService 请求。如果您重试一次,请求可能会成功
  • ZERO_RESULTS:该请求查询不到任何结果。

地点搜索结果

nearbySearch()textSearch() 函数均返回一个 PlaceResult 对象的数组。radarSearch() 函数返回 PlaceResult 中的一部分字段,如以上所述。

每个 PlaceResult 对象可能包括以下属性:

  • formatted_address 是一个包含此地点可人工读取的地址的字符串。此地址往往相当于“邮政编码”。formatted_address 属性只为文本搜索返回。
  • geometry:该地点的几何相关信息。这包括:
    • location 提供了该地点的纬度和经度。
    • viewport 定义了当查看该地点时地图上的首选视口。
  • html_attributions:当显示搜索结果时应该显示的提供方说明的数组。数组中的每一项都包含一条提供方说明的 HTML 文本。:这是整个搜索响应的所有提供方说明的集合。因此,响应中的所有 PlaceResult 对象均包含相同的提供方说明列表。
  • icon:指向可用于代表该地点类型的图像资源的 URL。
  • id:包含指示该地点的唯一标识符。此标识符可能无法用于检索有关此地点的信息,但是可用于合并有关此地点的数据,并在不同的搜索中验证地点的同一性。由于 ID 偶尔会变化,因此,建议您将存储的地点 ID 与后来针对同一地点的详情请求返回的 ID 进行比较,并在必要时进行更新。:如本页面上的弃用通告中所述,id 已被弃用,取而代之的是 place_id
  • name:该地点的名称。
  • opening_hours 可能包含以下信息:
    • open_now 是表示该地点当前是否正在营业的布尔值。
  • place_id 是用于唯一标识地点的文本标识符。要检索有关该地点的信息,请在地点详情请求placeId 字段中传递此标识符。详细了解如何通过地点 ID 引用地点
  • rating 包含基于用户总体评论的地点评分,范围从 0.0 到 5.0。
  • reference 包含可用于将来查询详情服务的令牌。此令牌可能与详情服务请求中使用的引用不同。建议您定期更新存储的地点引用。尽管此令牌唯一标识该地点,但是反之则不然:一个地点可以有多个有效的引用令牌。:如本页面上的弃用通告中所述,reference 已被弃用,取而代之的是 place_id
  • types 此地点类型的数组(例如 ["political", "locality"]["restaurant", "lodging"])。
  • vicinity:该地点的简化地址,包括街道名称、门牌号码和行政区划,但不包括省/州、邮政编码或国家/地区。例如,Google 澳大利亚悉尼分公司的 vicinity 值为 5/48 Pirrama Road, Pyrmont

访问其他结果

默认情况下,对于每个地点搜索,每次查询可返回最多 20 条结果。但是,每个搜索可以返回多达 60 条结果,分三页显示。可以通过 PlaceSearchPagination 对象获取其他页面。为了访问其他页面,您必须通过一个回调函数获取 PlaceSearchPagination 对象。PlaceSearchPagination 对象定义如下:

  • hasNextPage 是一个布尔属性,指示是否还有更多结果。当还有其他结果页面时,其值为 true
  • nextPage() 是用来返回下一组结果的函数。在执行搜索后,您必须等待两秒钟,下一页的结果才会出现。

要查看下一组结果,请调用 nextPage。对每一个结果页面而言,必须先显示当前页的结果,然后才能显示下一页的结果。请注意,每次搜索都算作使用限制中的一次请求。

以下示例演示了如何更改回调函数来获取 PlaceSearchPagination 对象,以便您能够发出多个搜索请求。

// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">

var map;

function initMap() {
  var pyrmont = {lat: -33.866, lng: 151.196};

  map = new google.maps.Map(document.getElementById('map'), {
    center: pyrmont,
    zoom: 17
  });

  var service = new google.maps.places.PlacesService(map);
  service.nearbySearch({
    location: pyrmont,
    radius: 500,
    type: ['store']
  }, processResults);
}

function processResults(results, status, pagination) {
  if (status !== google.maps.places.PlacesServiceStatus.OK) {
    return;
  } else {
    createMarkers(results);

    if (pagination.hasNextPage) {
      var moreButton = document.getElementById('more');

      moreButton.disabled = false;

      moreButton.addEventListener('click', function() {
        moreButton.disabled = true;
        pagination.nextPage();
      });
    }
  }
}

function createMarkers(places) {
  var bounds = new google.maps.LatLngBounds();
  var placesList = document.getElementById('places');

  for (var i = 0, place; place = places[i]; i++) {
    var image = {
      url: place.icon,
      size: new google.maps.Size(71, 71),
      origin: new google.maps.Point(0, 0),
      anchor: new google.maps.Point(17, 34),
      scaledSize: new google.maps.Size(25, 25)
    };

    var marker = new google.maps.Marker({
      map: map,
      icon: image,
      title: place.name,
      position: place.geometry.location
    });

    placesList.innerHTML += '<li>' + place.name + '</li>';

    bounds.extend(place.geometry.location);
  }
  map.fitBounds(bounds);
}
<div id="map"></div>
<div id="right-panel">
  <h2>Results</h2>
  <ul id="places"></ul>
  <button id="more">More results</button>
</div>
/* Always set the map height explicitly to define the size of the div
 * element that contains the map. */
#map {
  height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}
#right-panel {
  font-family: 'Roboto','sans-serif';
  line-height: 30px;
  padding-left: 10px;
}

#right-panel select, #right-panel input {
  font-size: 15px;
}

#right-panel select {
  width: 100%;
}

#right-panel i {
  font-size: 12px;
}
#right-panel {
  font-family: Arial, Helvetica, sans-serif;
  position: absolute;
  right: 5px;
  top: 60%;
  margin-top: -195px;
  height: 330px;
  width: 200px;
  padding: 5px;
  z-index: 5;
  border: 1px solid #999;
  background: #fff;
}
h2 {
  font-size: 22px;
  margin: 0 0 5px 0;
}
ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
  height: 271px;
  width: 200px;
  overflow-y: scroll;
}
li {
  background-color: #f1f1f1;
  padding: 10px;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}
li:nth-child(odd) {
  background-color: #fcfcfc;
}
#more {
  width: 100%;
  margin: 5px 0 0 0;
}
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=places&callback=initMap" async defer></script>
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">

var map;

function initMap() {
  var pyrmont = {lat: -33.866, lng: 151.196};

  map = new google.maps.Map(document.getElementById('map'), {
    center: pyrmont,
    zoom: 17
  });

  var service = new google.maps.places.PlacesService(map);
  service.nearbySearch({
    location: pyrmont,
    radius: 500,
    type: ['store']
  }, processResults);
}

function processResults(results, status, pagination) {
  if (status !== google.maps.places.PlacesServiceStatus.OK) {
    return;
  } else {
    createMarkers(results);

    if (pagination.hasNextPage) {
      var moreButton = document.getElementById('more');

      moreButton.disabled = false;

      moreButton.addEventListener('click', function() {
        moreButton.disabled = true;
        pagination.nextPage();
      });
    }
  }
}

function createMarkers(places) {
  var bounds = new google.maps.LatLngBounds();
  var placesList = document.getElementById('places');

  for (var i = 0, place; place = places[i]; i++) {
    var image = {
      url: place.icon,
      size: new google.maps.Size(71, 71),
      origin: new google.maps.Point(0, 0),
      anchor: new google.maps.Point(17, 34),
      scaledSize: new google.maps.Size(25, 25)
    };

    var marker = new google.maps.Marker({
      map: map,
      icon: image,
      title: place.name,
      position: place.geometry.location
    });

    placesList.innerHTML += '<li>' + place.name + '</li>';

    bounds.extend(place.geometry.location);
  }
  map.fitBounds(bounds);
}

查看示例 (place-search-pagination.html)

地点详情

除了提供某个区域内的地点列表,“地点”服务还可以返回有关某个特定地点的详细信息。当地点搜索响应中返回某个地点后,可以使用其地点 ID 来请求有关该地点的更多详情,例如其完整地址、电话号码、用户评分和评论等。(如本页面上的弃用通告中所述,地点的 reference 也可用于检索地点详情,但是此字段已被弃用,取而代之的是地点 ID。)

地点详情请求

通过调用该服务的 getDetails() 方法可请求地点详情。

service = new google.maps.places.PlacesService(map);
service.getDetails(request, callback);

此方法会发出一个请求,其中包含所需地点的 placeIdreference。如本页面上的弃用通告中所述,reference 已被弃用,取而代之的是 placeId。详细了解如何通过地点 ID 引用地点

它也有一个回调方法,该方法需要处理 google.maps.places.PlacesServiceStatus 响应中传递的状态代码以及 google.maps.places.PlaceResult 对象。

var request = {
  placeId: 'ChIJN1t_tDeuEmsRUsoyG83frY4'
};

service = new google.maps.places.PlacesService(map);
service.getDetails(request, callback);

function callback(place, status) {
  if (status == google.maps.places.PlacesServiceStatus.OK) {
    createMarker(place);
  }
}

查看示例 (place-details.html)

地点详情响应

状态代码

PlacesServiceStatus 响应对象包含了请求的状态,还可能包含调试信息,以帮助您跟踪地点详情请求失败的原因。可能的状态值为:

  • ERROR:连接 Google 服务器时遇到了问题。
  • INVALID_REQUEST:该请求无效。
  • OK:响应中包含有效结果。
  • OVER_QUERY_LIMIT:该网页已超过其请求限额。
  • NOT_FOUND:在 Places 数据库中找不到引用的位置。
  • REQUEST_DENIED:不允许该网页使用 PlacesService。
  • UNKNOWN_ERROR:由于服务器发生错误,因此无法处理该 PlacesService 请求。如果您重试一次,请求可能会成功
  • ZERO_RESULTS:该请求查询不到任何结果。

地点详情结果

如果调用 getDetails() 成功,即可返回一个带有以下属性的 PlaceResult 对象:

  • address_components:该地点位置的地址组成部分的集合。如需了解更多详情,请参阅地理编码服务的地址组成部分类型部分。
  • formatted_address:该地点的详细地址。
  • formatted_phone_number:该地点的电话号码,其格式遵循号码区域公约
  • geometry:该地点的几何相关信息。这包括:
    • location 提供了该地点的纬度和经度。
    • viewport 定义了当查看该地点时地图上的首选视口。
  • html_attributions:要显示的此地点结果的提供方说明文本。
  • icon:指向可用于代表该地点类型的图像资源的 URL。
  • id:包含指示该地点的唯一标识符。此标识符可能无法用于检索有关此地点的信息,但是可用于合并有关此地点的数据,并在不同的搜索中验证地点的同一性。由于 ID 偶尔会变化,因此,建议您将存储的地点 ID 与后来针对同一地点的详情请求返回的 ID 进行比较,并在必要时进行更新。:如本页面上的弃用通告中所述,id 已被弃用,取而代之的是 place_id
  • international_phone_number 包含此地点以国际格式表示的电话号码。国际格式包含国家/地区代码,并且带有一个加号 (+) 前缀。例如,Google 澳大利亚悉尼分公司的 international_phone_number+61 2 9374 4000
  • name:该地点的名称。
  • utc_offset 包含此地点当前时区偏离 UTC 时间的分钟数。例如,对于澳大利亚悉尼的地点,在使用夏令时期间,此参数为 660(偏离 UTC 时间 +11 小时),对于加利福尼亚州的地点,在未使用夏令时期间,此参数为 -480(偏离 UTC 时间 -8 小时)。
  • opening_hours 包含以下信息:
    • open_now 是表示该地点当前是否正在营业的布尔值。
    • periods[] 是一个持续七天的营业时段数组,这些营业时段从星期日开始,按时间顺序排列。每个时段均包含:
      • open 包含一对用于说明该地点营业时段的日期和时间对象:
        • day 是一个介于 0 到 6 之间的数字,对应于从星期日开始一周内的某天。例如,2 表示星期二。
        • time 可以包含一天中的某个时间,采用 24 小时制 hhmm 格式(值的范围为 0000–2359)。系统将按该地点的时区报告 time
      • close 可包含一对用于说明该地点何时关闭的日期和时间对象。:如果该地点全天开放,响应中将缺少 close 部分。应用可以通过下述方法来表示全天开放:将 open 中的 day 值设置为 0,time 值设置为 0000,并且不包含 close
    • weekday_text 是包含 7 个字符串的数组,这些字符串表示以特定格式表示的一周内每一天的开放时间。如果地点详情请求中指定了 language 参数,则“地点”服务会格式化并本地化该语言的相应开放时间。此数组中的元素排序取决于 language 参数。有些语言的一周从星期一开始,有些语言则从星期日开始。
  • permanently_closed:一个布尔标志,指示该地点是否已永久关闭(如果是,则值为 true)。如果地点未永久关闭,响应中将不会显示该标志。
  • photos[]PlacePhoto 对象的数组。可以使用 PlacePhotogetUrl() 方法来获取照片,或者您也可以检查对象的以下值:
    • height:图像的最大高度(以像素为单位)。
    • width:图像的最大宽度(以像素为单位)。
    • html_attributions:要随此地点照片一起显示的提供方说明文本。
  • place_id:一个文本标识符,它唯一标识某个地点,并可用于通过地点详情请求检索该地点的相关信息。详细了解如何通过地点 ID 引用地点
  • rating:基于用户总体评论的地点评分,范围从 0.0 到 5.0。
  • reference 包含可用于将来查询详情服务的令牌。此令牌可能与详情服务请求中使用的引用不同。建议您定期更新存储的地点引用。尽管此令牌唯一标识该地点,但是反之则不然:一个地点可以有多个有效的引用令牌。:如本页面上的弃用通告中所述,reference 已被弃用,取而代之的是 place_id
  • reviews 是一个最多包含五条评论的数组。每条评论均由若干部分组成:
    • aspects[] 包含一个 PlaceAspectRating 对象数组,其中每个对象都提供了对该场所单个属性的评分。该数组中的第一个对象被认为是主要评分指标。每个 PlaceAspectRating 分别定义如下:
      • type 表示评分指标名称。支持以下类型:appealatmospheredecorfacilitiesfoodoverallqualityservice
      • rating 表示用户针对该特定评分指标的评分,范围为 0 至 3。
    • author_name 表示提交评论的用户的姓名。匿名评论的作者统称为“A Google user”。如果设置了语言参数,那么短语“A Google user”将返回一个本地化的字符串。
    • author_url 是指向用户 Google+ 个人资料(若有的话)的 URL。
    • language 表示用户评论所用语言的 IETF 语言代码。此字段仅包含主要语言标记,而不包含表示国家或地区的辅助标记。例如,所有英语评论都标记为“en”,而不是“en-AU”或“en-UK”等。
    • rating 表示用户对此地点的总体评分。此参数是一个整数,范围为 1 至 5。
    • text 表示用户的评论。通过 Google Places 评论某个位置时,文本评论被视为可选项;因此,此字段有可能为空。
  • types 此地点类型的数组(例如 ["political", "locality"]["restaurant", "lodging"])。
  • url:此地点的官方 Google 页面的 URL。这是由 Google 拥有的页面,其中包含有关该地点的最佳可用信息。在任何向用户显示该地点详细结果的屏幕上,应用必须与该页面相关联或者嵌入此页面。
  • vicinity:该地点的简化地址,包括街道名称、门牌号码和行政区划,但不包括省/州、邮政编码或国家/地区。例如,Google 澳大利亚悉尼分公司的 vicinity 值为 5/48 Pirrama Road, Pyrmont。对于附近地点搜索,仅返回 vicinity 属性。
  • website 列出此地点的官方网站,例如商家主页。

并非所有地点都可使用多维评分。如果评论太少,那么详情响应要么包含一个 0.0 至 5.0 之间的旧版评分(如果可用),要么根本就不包含任何评分。

通过地点 ID 引用地点

Google 地图上的地点可以通过其地点 ID 唯一地引用。地点 ID 可用于大多数位置,包括商家、地标、公园和十字路口。这些 ID 是稳定的,这意味着一旦您确定了某个位置的地点 ID,就可以在下次查找该位置时重复使用该值。

要在您的应用中使用地点 ID,您必须先查找该 ID,它可以从地点搜索请求或详情请求的 PlaceResult 中获取。以后您就可以使用此地点 ID 查找地点详情,或在已登录的地图上启用 Save Attribution

地点 ID 可豁免于 Google Maps API 服务条款第 10.5.d 条中声明的缓存限制。因此,您可以无限制地存储地点 ID 值。

var map;

function initialize() {
  // Create a map centered in Pyrmont, Sydney (Australia).
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: -33.8666, lng: 151.1958},
    zoom: 15
  });

  // Search for Google's office in Australia.
  var request = {
    location: map.getCenter(),
    radius: '500',
    query: 'Google Sydney'
  };

  var service = new google.maps.places.PlacesService(map);
  service.textSearch(request, callback);
}

// Checks that the PlacesServiceStatus is OK, and adds a marker
// using the place ID and location from the PlacesService.
function callback(results, status) {
  if (status == google.maps.places.PlacesServiceStatus.OK) {
    var marker = new google.maps.Marker({
      map: map,
      place: {
        placeId: results[0].place_id,
        location: results[0].geometry.location
      }
    });
  }
}

google.maps.event.addDomListener(window, 'load', initialize);

地点照片

地点照片功能允许您将高品质照片内容添加到您的站点。照片服务可以让您访问 Places 和 Google+ Local 数据库中存储的数以百万计的照片。当您使用地点详情请求获取地点信息时,系统将返回相关照片内容的照片引用。附近地点搜索和文本搜索请求也会为每个地点返回一个照片引用(如果相关)。使用照片服务,您就可以访问所引用的照片,并将图像调整为最适合您的应用的大小。

对于向 PlacesService 发出的任何 getDetails()textSearch()nearbySearch() 请求,系统将返回一个 PlacePhoto 对象的数组作为 PlaceResult 对象的一部分。

:返回的照片数量因请求的不同而异。

  • 附近地点搜索或文本搜索将最多返回一个 PlacePhoto 对象。
  • 雷达搜索不会返回任何照片信息。
  • 详情请求将最多返回十个 PlacePhoto 对象。

您可以通过调用 PlacePhoto.getUrl() 方法并传入一个有效的 PhotoOptions 对象来请求相关图像的 URL。该 PhotoOptions 对象允许您指定图像所需的最大高度和宽度。如果您为 max_heightmax_width 都指定了值,该照片服务会将图像大小调整为两个尺寸中较小的那一个,同时保持原始纵横比不变。

下面这段代码接受一个地点对象,如果有照片的话,还会向地图添加一个标记。默认的标记图像将替换为缩略版的照片。

function createPhotoMarker(place) {
  var photos = place.photos;
  if (!photos) {
    return;
  }

  var marker = new google.maps.Marker({
    map: map,
    position: place.geometry.location,
    title: place.name,
    icon: photos[0].getUrl({'maxWidth': 35, 'maxHeight': 35})
  });
}

发送以下问题的反馈:

此网页
Google Maps JavaScript API
Google Maps JavaScript API
需要帮助?请访问我们的支持页面