一切就绪!

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

激活 Google Maps JavaScript API

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

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

街景服务

概览

Google 街景提供其整个覆盖区域内以指定道路为中心的 360 度全景视图。街景的 API 覆盖范围与 Google 地图应用 (https://maps.google.com/) 的覆盖范围相同。街景当前支持的城市列表可通过 Google 地图网站获取。

以下显示了一个示例街景图像。


Google Maps JavaScript API 提供了用于对 Google 地图街景中使用的图像进行获取和操纵的街景服务。浏览器内对该街景服务提供原生支持。

街景地图使用

尽管街景可在独立 DOM 元素内使用,但其在表示地图上的位置时最有用。地图上默认启用街景,并且导航(缩放和平移)控件内集成有街景小人控件。您可以通过在地图的 MapOptions 内将 streetViewControl 设置为 false 来隐藏该控件。您还可以通过将 MapstreetViewControlOptions.position 设置为一个新的 ControlPosition 来更改街景控件的默认位置。

街景小人控件允许您直接在地图内查看街景全景图。当用户点击并按住街景小人时,地图会进行更新,在启用了街景的街道周围显示蓝色轮廓,从而带来与 Google 地图应用类似的用户体验。

当用户在街道上放置街景小人标记时,地图会通过更新显示所指示位置的街景全景图。

街景全景图

通过使用 StreetViewPanorama 对象来支持街景图像,该对象提供连接街景“查看器”的 API 接口。每张地图都包含一幅默认街景全景图,您可以通过调用地图的 getStreetView() 方法对其进行检索。当您通过将街景控件的 streetViewControl 选项设置为 true 来向地图添加控件时,会自动将街景小人控件与该默认街景全景图相连。

您还可以创建自己的 StreetViewPanorama 对象,并通过显式地将地图的 streetView 属性设置为该构造对象,将地图设置为使用该对象而非默认全景图。如果您想修改默认行为,如地图与全景图之间叠层的自动共享,可能希望重写默认全景图。(请参阅下文的街景内的叠层。)

街景容器

您可能会改变想法,想在单独 DOM 元素(通常是 <div> 元素)内显示 StreetViewPanorama。只需在 StreetViewPanorama 的构造函数内传递 DOM 元素便可实现。要想获得最佳图像显示效果,我们建议的最小图像尺寸为 200x200 像素。

:尽管街景功能设计为与地图联用,这一用法并非强制性要求。您可以使用不与地图联用的独立街景对象。

街景位置和视角 (POV)

StreetViewPanorama 构造函数还允许您利用 StreetViewOptions 参数设置街景位置和视角。您可以在构造后对该对象调用 setPosition()setPov() 来更改其位置和 POV。

街景位置定义的是摄像头的图像焦点位置,但它并不定义对应于该图像的摄像头朝向。针对该用途,StreetViewPov 对象定义了两个属性:

  • heading(默认值 0)以相对于正北方的度数定义以摄像头所在地为中心的旋转角度。方位按顺时针计量(90 度为正东方)。
  • pitch(默认值 0)定义与摄像头初始默认间距的“向上”或“向下”角度差异,该间距通常(但并不总是)水平间距。(例如,在小山上拍摄的图像所呈现的默认间距可能并非水平间距。)计量的俯仰角为正值时摄像头仰视(最大 +90 度垂直向上,与默认间距正交),为负值时摄像头俯视(最大 -90 度垂直向下,与默认间距正交)。

StreetViewPov 对象最常应用确定街景摄像头的视角。您还可通过 StreetViewPanorama.getPhotographerPov() 方法确定拍摄者的视角,该视角通常是汽车或三轮车所面向的方向。

以下代码显示了一幅包含芬威球场初始视图的波士顿地图。选择街景小人并将其拖放到地图上某个支持的位置可更改街景全景图:

function initialize() {
  var fenway = {lat: 42.345573, lng: -71.098326};
  var map = new google.maps.Map(document.getElementById('map'), {
    center: fenway,
    zoom: 14
  });
  var panorama = new google.maps.StreetViewPanorama(
      document.getElementById('pano'), {
        position: fenway,
        pov: {
          heading: 34,
          pitch: 10
        }
      });
  map.setStreetView(panorama);
}
<div id="map"></div>
<div id="pano"></div>
html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}
#map, #pano {
  float: left;
  height: 100%;
  width: 45%;
}
<!-- Replace the value of the key parameter with your own API key. -->
<script async defer
    src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initialize">
</script>
function initialize() {
  var fenway = {lat: 42.345573, lng: -71.098326};
  var map = new google.maps.Map(document.getElementById('map'), {
    center: fenway,
    zoom: 14
  });
  var panorama = new google.maps.StreetViewPanorama(
      document.getElementById('pano'), {
        position: fenway,
        pov: {
          heading: 34,
          pitch: 10
        }
      });
  map.setStreetView(panorama);
}

查看示例 (streetview-simple.html)

移动设备上的运动跟踪功能

在支持设备屏幕方向事件的设备上,用户可以通过该 API 随设备的移动改变街景视角。用户可通过移动设备进行环视。这叫做运动跟踪或设备旋转跟踪。

作为应用开发者,您可以如下所述更改默认行为:

  • 启用或停用运动跟踪功能。默认情况下,在任何支持运动跟踪的设备上,该功能都处于启用状态。以下示例停用了运动跟踪,但仍使运动跟踪控件保持可见状态。(请注意,用户可通过点按该控件启用运动跟踪。)
    var panorama = new google.maps.StreetViewPanorama(
        document.getElementById('pano'), {
          position: {lat: 37.869260, lng: -122.254811},
          pov: {heading: 165, pitch: 0},
          motionTracking: false
        });
    
  • 隐藏或显示运动跟踪控件。默认情况下,支持运动跟踪的设备上会显示该控件。用户可以点按该控件来启用或停用运动跟踪。请注意,如果设备不支持运动跟踪,无论 motionTrackingControl 为何值,该控件都不会出现。

    以下示例同时停用了运动跟踪和运动跟踪控件。在此情况下,用户无法启用运动跟踪:

    var panorama = new google.maps.StreetViewPanorama(
        document.getElementById('pano'), {
          position: {lat: 37.869260, lng: -122.254811},
          pov: {heading: 165, pitch: 0},
          motionTracking: false,
          motionTrackingControl: false
        });
    
  • 更改运动跟踪控件的默认位置。默认情况下,该控件出现在靠近全景图右下角的位置(RIGHT_BOTTOM 位置)。以下示例将控件位置设置为左下角:
    var panorama = new google.maps.StreetViewPanorama(
        document.getElementById('pano'), {
          position: {lat: 37.869260, lng: -122.254811},
          pov: {heading: 165, pitch: 0},
          motionTrackingControlOptions: {
            position: google.maps.ControlPosition.LEFT_BOTTOM
          }
        });
    

要了解运动跟踪的实用效果,请在移动设备(或任何支持设备屏幕方向事件的设备)上查看以下示例:


在新页面上查看示例 (streetview-embed.html)

街景内的叠层

默认 StreetViewPanorama 对象支持地图叠层的原生显示。叠层一般出现在固定于 LatLng 位置的“街道级”(例如,显示标记时,其尾部固定于街景全景图内位置的水平面上。)

目前,街景全景图上支持的叠层类型仅限 MarkerInfoWindow 和自定义 OverlayView。可通过将全景图视为 Map 对象的替代项,调用 setMap(),并以参数而非地图形式传递 StreetViewPanorama,在街景全景图上显示您显示在地图上的叠层。同理,可通过调用 open(),传递 StreetViewPanorama() 而非地图,在街景全景图内打开信息窗口。

此外,在创建使用默认 StreetViewPanorama 的地图时,只要与地图关联的街景全景图可见,则在地图上创建的任何标记都会自动与其共享。如需检索默认街景全景图,请对 Map 对象调用 getStreetView()。请注意,如果您显式地将地图的 streetView 属性设置为您自己构造的某个 StreetViewPanorama,将会重写默认全景图并禁用自动叠层共享。

下例显示的标记表示纽约市阿斯特广场周围的不同位置。将显示切换到街景可显示 StreetViewPanorama 内显示的共享标记。

var panorama;

function initMap() {
  var astorPlace = {lat: 40.729884, lng: -73.990988};

  // Set up the map
  var map = new google.maps.Map(document.getElementById('map'), {
    center: astorPlace,
    zoom: 18,
    streetViewControl: false
  });

  // Set up the markers on the map
  var cafeMarker = new google.maps.Marker({
      position: {lat: 40.730031, lng: -73.991428},
      map: map,
      icon: 'https://chart.apis.google.com/chart?chst=d_map_pin_icon&chld=cafe|FFFF00',
      title: 'Cafe'
  });

  var bankMarker = new google.maps.Marker({
      position: {lat: 40.729681, lng: -73.991138},
      map: map,
      icon: 'https://chart.apis.google.com/chart?chst=d_map_pin_icon&chld=dollar|FFFF00',
      title: 'Bank'
  });

  var busMarker = new google.maps.Marker({
      position: {lat: 40.729559, lng: -73.990741},
      map: map,
      icon: 'https://chart.apis.google.com/chart?chst=d_map_pin_icon&chld=bus|FFFF00',
      title: 'Bus Stop'
  });

  // We get the map's default panorama and set up some defaults.
  // Note that we don't yet set it visible.
  panorama = map.getStreetView();
  panorama.setPosition(astorPlace);
  panorama.setPov(/** @type {google.maps.StreetViewPov} */({
    heading: 265,
    pitch: 0
  }));
}

function toggleStreetView() {
  var toggle = panorama.getVisible();
  if (toggle == false) {
    panorama.setVisible(true);
  } else {
    panorama.setVisible(false);
  }
}
<div id="floating-panel">
  <input type="button" value="Toggle Street View" onclick="toggleStreetView();"></input>
</div>
<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;
}
#floating-panel {
  position: absolute;
  top: 10px;
  left: 25%;
  z-index: 5;
  background-color: #fff;
  padding: 5px;
  border: 1px solid #999;
  text-align: center;
  font-family: 'Roboto','sans-serif';
  line-height: 30px;
  padding-left: 10px;
}
#floating-panel {
  margin-left: -100px;
}
 <!-- Replace the value of the key parameter with your own API key. -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>
var panorama;

function initMap() {
  var astorPlace = {lat: 40.729884, lng: -73.990988};

  // Set up the map
  var map = new google.maps.Map(document.getElementById('map'), {
    center: astorPlace,
    zoom: 18,
    streetViewControl: false
  });

  // Set up the markers on the map
  var cafeMarker = new google.maps.Marker({
      position: {lat: 40.730031, lng: -73.991428},
      map: map,
      icon: 'https://chart.apis.google.com/chart?chst=d_map_pin_icon&chld=cafe|FFFF00',
      title: 'Cafe'
  });

  var bankMarker = new google.maps.Marker({
      position: {lat: 40.729681, lng: -73.991138},
      map: map,
      icon: 'https://chart.apis.google.com/chart?chst=d_map_pin_icon&chld=dollar|FFFF00',
      title: 'Bank'
  });

  var busMarker = new google.maps.Marker({
      position: {lat: 40.729559, lng: -73.990741},
      map: map,
      icon: 'https://chart.apis.google.com/chart?chst=d_map_pin_icon&chld=bus|FFFF00',
      title: 'Bus Stop'
  });

  // We get the map's default panorama and set up some defaults.
  // Note that we don't yet set it visible.
  panorama = map.getStreetView();
  panorama.setPosition(astorPlace);
  panorama.setPov(/** @type {google.maps.StreetViewPov} */({
    heading: 265,
    pitch: 0
  }));
}

function toggleStreetView() {
  var toggle = panorama.getVisible();
  if (toggle == false) {
    panorama.setVisible(true);
  } else {
    panorama.setVisible(false);
  }
}

查看示例 (streetview-overlays.html)

街景事件

在街景之间导航或操纵其朝向时,您可能希望对指示 StreetViewPanorama 状态变化的若干事件进行监控:

  • 每当个别 pano ID 发生变化时,便会触发 pano_changed。此事件不能保证触发此时间时全景图内的任何关联数据(如链接)同样发生了变化;此事件只表示 pano ID 发生了变化。请注意,pano ID(可用于引用该全景图)只在当前浏览器会话内保持稳定。
  • 每当全景图的基础 (LatLng) 位置发生变化时,便会触发 position_changed。旋转全景图不会触发此事件。请注意,您更改全景图的基础位置时不会改变关联的 pano ID,因为 API 会自动将距离最近的 pano ID 与全景图的位置关联。
  • 每当街景的 StreetViewPov 发生变化时,便会触发 pov_changed。请注意,此事件可能会在位置和 pano ID 保持稳定时触发。
  • 每当街景的链接发生变化时,便会触发 links_changed。请注意,此事件可能会在通过 pano_changed 指示的 pano ID 变化发生后以异步方式触发。
  • 每当街景的可见性发生变化时,便会触发 visible_changed。请注意,此事件可能会在通过 pano_changed 指示的 pano ID 变化发生后以异步方式触发。

以下代码说明了如何处理这些事件来收集有关基础 StreetViewPanorama 的数据:

function initPano() {
  var panorama = new google.maps.StreetViewPanorama(
      document.getElementById('pano'), {
        position: {lat: 37.869, lng: -122.255},
        pov: {
          heading: 270,
          pitch: 0
        },
        visible: true
  });

  panorama.addListener('pano_changed', function() {
      var panoCell = document.getElementById('pano-cell');
      panoCell.innerHTML = panorama.getPano();
  });

  panorama.addListener('links_changed', function() {
      var linksTable = document.getElementById('links_table');
      while (linksTable.hasChildNodes()) {
        linksTable.removeChild(linksTable.lastChild);
      }
      var links = panorama.getLinks();
      for (var i in links) {
        var row = document.createElement('tr');
        linksTable.appendChild(row);
        var labelCell = document.createElement('td');
        labelCell.innerHTML = '<b>Link: ' + i + '</b>';
        var valueCell = document.createElement('td');
        valueCell.innerHTML = links[i].description;
        linksTable.appendChild(labelCell);
        linksTable.appendChild(valueCell);
      }
  });

  panorama.addListener('position_changed', function() {
      var positionCell = document.getElementById('position-cell');
      positionCell.firstChild.nodeValue = panorama.getPosition() + '';
  });

  panorama.addListener('pov_changed', function() {
      var headingCell = document.getElementById('heading-cell');
      var pitchCell = document.getElementById('pitch-cell');
      headingCell.firstChild.nodeValue = panorama.getPov().heading + '';
      pitchCell.firstChild.nodeValue = panorama.getPov().pitch + '';
  });
}
<div id="pano"></div>
<div id="floating-panel">
<table>
  <tr>
    <td><b>Position</b></td><td id="position-cell">&nbsp;</td>
  </tr>
  <tr>
    <td><b>POV Heading</b></td><td id="heading-cell">270</td>
  </tr>
  <tr>
    <td><b>POV Pitch</b></td><td id="pitch-cell">0.0</td>
  </tr>
  <tr>
    <td><b>Pano ID</b></td><td id="pano-cell">&nbsp;</td>
  </tr>
  <table id="links_table"></table>
</table>
</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;
}
#floating-panel {
  position: absolute;
  top: 10px;
  left: 25%;
  z-index: 5;
  background-color: #fff;
  padding: 5px;
  border: 1px solid #999;
  text-align: center;
  font-family: 'Roboto','sans-serif';
  line-height: 30px;
  padding-left: 10px;
}
#pano {
  width: 50%;
  height: 100%;
  float: left;
}
#floating-panel {
  width: 45%;
  height: 100%;
  float: right;
  text-align: left;
  overflow: auto;
  position: static;
  border: 0px solid #999;
}
<!-- Replace the value of the key parameter with your own API key. -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initPano">
</script>
function initPano() {
  var panorama = new google.maps.StreetViewPanorama(
      document.getElementById('pano'), {
        position: {lat: 37.869, lng: -122.255},
        pov: {
          heading: 270,
          pitch: 0
        },
        visible: true
  });

  panorama.addListener('pano_changed', function() {
      var panoCell = document.getElementById('pano-cell');
      panoCell.innerHTML = panorama.getPano();
  });

  panorama.addListener('links_changed', function() {
      var linksTable = document.getElementById('links_table');
      while (linksTable.hasChildNodes()) {
        linksTable.removeChild(linksTable.lastChild);
      }
      var links = panorama.getLinks();
      for (var i in links) {
        var row = document.createElement('tr');
        linksTable.appendChild(row);
        var labelCell = document.createElement('td');
        labelCell.innerHTML = '<b>Link: ' + i + '</b>';
        var valueCell = document.createElement('td');
        valueCell.innerHTML = links[i].description;
        linksTable.appendChild(labelCell);
        linksTable.appendChild(valueCell);
      }
  });

  panorama.addListener('position_changed', function() {
      var positionCell = document.getElementById('position-cell');
      positionCell.firstChild.nodeValue = panorama.getPosition() + '';
  });

  panorama.addListener('pov_changed', function() {
      var headingCell = document.getElementById('heading-cell');
      var pitchCell = document.getElementById('pitch-cell');
      headingCell.firstChild.nodeValue = panorama.getPov().heading + '';
      pitchCell.firstChild.nodeValue = panorama.getPov().pitch + '';
  });
}

查看示例 (streetview-events.html)

街景控件

显示 StreetViewPanorama 时,默认情况下全景图上会出现各类控件。可以通过在 StreetViewPanoramaOptions 内将相应字段设置为 truefalse 来启用或停用这些控件:

  • panControl 提供了一种旋转全景图的方法。默认情况下,此控件以标准集成罗盘和平移控件的形式出现。您可以通过在 panControlOptions 字段内提供 PanControlOptions,改变该控件的位置。
  • zoomControl 提供了一种在图像内进行缩放的方法。默认情况下,此控件出现在靠近全景图右下角的位置。您可以通过在 zoomControlOptions 字段内提供 ZoomControlOptions,改变该控件的外观。
  • addressControl 提供表示关联位置地址的文本叠层,并提供在 Google 地图中打开该位置的链接。您可以通过在 addressControlOptions 字段内提供 StreetViewAddressControlOptions,改变该控件的外观。
  • fullScreenControl 提供以全屏模式打开街景的选择。可以通过在 fullscreenControlOptions 字段内提供 FullscreenControlOptions,改变该控件的外观。
  • motionTrackingControl 提供在移动设备上启用或停用运动跟踪的选择。该控件只会出现在支持设备屏幕方向事件的设备上。默认情况下,该控件出现在靠近全景图右下角的位置。可以通过提供 MotionTrackingControlOptions 改变该控件的位置。如需了解详细信息,请参阅有关运动跟踪的部分。
  • linksControl 在图像上提供用于切换到相邻全景图图像的指示箭头。
  • Close 控件允许用户关闭街景查看器。您可以通过将 enableCloseButton 设置为 truefalse 来启用或禁用 Close 控件。

下例改变了关联街景内显示的控件并删除了视图的链接:

全屏查看此示例。

function initPano() {
  // Note: constructed panorama objects have visible: true
  // set by default.
  var panorama = new google.maps.StreetViewPanorama(
      document.getElementById('map'), {
        position: {lat: 42.345573, lng: -71.098326},
        addressControlOptions: {
          position: google.maps.ControlPosition.BOTTOM_CENTER
        },
        linksControl: false,
        panControl: false,
        enableCloseButton: false
  });
}
<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 async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initPano">
</script>
function initPano() {
  // Note: constructed panorama objects have visible: true
  // set by default.
  var panorama = new google.maps.StreetViewPanorama(
      document.getElementById('map'), {
        position: {lat: 42.345573, lng: -71.098326},
        addressControlOptions: {
          position: google.maps.ControlPosition.BOTTOM_CENTER
        },
        linksControl: false,
        panControl: false,
        enableCloseButton: false
  });
}

查看示例 (streetview-controls.html)

直接访问街景数据

您可能希望在无需直接操纵地图/全景图的情况下以编程方式确定街景数据的可用性,或者返回有关特定全景图的信息。您可以利用 StreetViewService 对象实现此目的,该对象提供了连接 Google 街景服务内所存储数据的接口。

街景服务请求

由于 Google Maps API 需要调用外部服务器,因此访问街景服务是异步进行的。为此,您需要传递一个在完成请求后执行的回调方法。此回调方法会对结果进行处理。

您可以向 StreetViewService 发起两类请求:

  • StreetViewPanoRequest 请求,它会在已知作为全景图唯一标识符的参考 ID 的情况下返回全景图数据。请注意,这些参考 ID 只在该全景图图像的生命周期内保持稳定。
  • StreetViewLocationRequest 请求,它根据传递的 LatLng 搜索给定区域的全景图数据。

街景服务响应

getPanorama() 需要用于在从街景服务检索结果时执行的“callback”函数。该回调函数返回 StreetViewPanoramaData 对象内的一组全景图数据,以及表示请求状态(按同一顺序)的 StreetViewStatus 代码。

StreetViewPanoramaData 对象规范包含以下形式的街景全景图元数据:

{
  "location": {
    "latLng": LatLng,
    "description": string,
    "pano": string
  },
  "copyright": string,
  "links": [{
      "heading": number,
      "description": string,
      "pano": string,
      "roadColor": string,
      "roadOpacity": number
    }],
  "tiles": {
    "worldSize": Size,
    "tileSize": Size,
    "centerHeading": number
  }
}

请注意,此数据对象本身并非 StreetViewPanorama 对象。如需使用该数据创建街景对象,您需要创建 StreetViewPanorama 并调用 setPano(),向其传递返回的 location.pano 字段中所记录的 ID。

status 代码可能返回下列值之一:

  • OK,表示服务找到了匹配的全景图
  • ZERO_RESULTS,表示服务找不到与传递的条件匹配的全景图
  • UNKNOWN_ERROR,表示无法处理街景请求,但确切原因未知

以下代码通过创建在点击时显示该位置 StreetViewPanorama 的标记来创建响应地图上用户点击的 StreetViewService。该代码使用从服务返回的 StreetViewPanoramaData 的内容。

/*
 * Click the map to set a new location for the Street View camera.
 */

var map;
var panorama;

function initMap() {
  var berkeley = {lat: 37.869085, lng: -122.254775};
  var sv = new google.maps.StreetViewService();

  panorama = new google.maps.StreetViewPanorama(document.getElementById('pano'));

  // Set up the map.
  map = new google.maps.Map(document.getElementById('map'), {
    center: berkeley,
    zoom: 16,
    streetViewControl: false
  });

  // Set the initial Street View camera to the center of the map
  sv.getPanorama({location: berkeley, radius: 50}, processSVData);

  // Look for a nearby Street View panorama when the map is clicked.
  // getPanoramaByLocation will return the nearest pano when the
  // given radius is 50 meters or less.
  map.addListener('click', function(event) {
    sv.getPanorama({location: event.latLng, radius: 50}, processSVData);
  });
}

function processSVData(data, status) {
  if (status === 'OK') {
    var marker = new google.maps.Marker({
      position: data.location.latLng,
      map: map,
      title: data.location.description
    });

    panorama.setPano(data.location.pano);
    panorama.setPov({
      heading: 270,
      pitch: 0
    });
    panorama.setVisible(true);

    marker.addListener('click', function() {
      var markerPanoID = data.location.pano;
      // Set the Pano to use the passed panoID.
      panorama.setPano(markerPanoID);
      panorama.setPov({
        heading: 270,
        pitch: 0
      });
      panorama.setVisible(true);
    });
  } else {
    console.error('Street View data not found for this location.');
  }
}
<div id="map" style="width: 45%; height: 100%;float:left"></div>
<div id="pano" style="width: 45%; height: 100%;float:left"></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 async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>
/*
 * Click the map to set a new location for the Street View camera.
 */

var map;
var panorama;

function initMap() {
  var berkeley = {lat: 37.869085, lng: -122.254775};
  var sv = new google.maps.StreetViewService();

  panorama = new google.maps.StreetViewPanorama(document.getElementById('pano'));

  // Set up the map.
  map = new google.maps.Map(document.getElementById('map'), {
    center: berkeley,
    zoom: 16,
    streetViewControl: false
  });

  // Set the initial Street View camera to the center of the map
  sv.getPanorama({location: berkeley, radius: 50}, processSVData);

  // Look for a nearby Street View panorama when the map is clicked.
  // getPanoramaByLocation will return the nearest pano when the
  // given radius is 50 meters or less.
  map.addListener('click', function(event) {
    sv.getPanorama({location: event.latLng, radius: 50}, processSVData);
  });
}

function processSVData(data, status) {
  if (status === 'OK') {
    var marker = new google.maps.Marker({
      position: data.location.latLng,
      map: map,
      title: data.location.description
    });

    panorama.setPano(data.location.pano);
    panorama.setPov({
      heading: 270,
      pitch: 0
    });
    panorama.setVisible(true);

    marker.addListener('click', function() {
      var markerPanoID = data.location.pano;
      // Set the Pano to use the passed panoID.
      panorama.setPano(markerPanoID);
      panorama.setPov({
        heading: 270,
        pitch: 0
      });
      panorama.setVisible(true);
    });
  } else {
    console.error('Street View data not found for this location.');
  }
}

查看示例 (streetview-service.html)

提供自定义街景全景图

Google Maps JavaScript API 支持在 StreetViewPanorama 对象内显示自定义全景图。您可以利用自定义全景图显示建筑内部、景点视图或任何您想像的内容。您甚至可以将这些自定义全景图与 Google 的现有街景全景图链接起来。

设置一组自定义全景图图像涉及下列步骤:

  • 为每幅自定义全景图创建一幅基础全景图图像。此基础图像使用的分辨率应为您想提供的放大图像的最高分辨率。
  • (可选但并非建议步骤)根据基础图像创建一组不同缩放比例的全景图图块。
  • 创建自定义全景图之间的链接。
  • (可选步骤)在 Google 的现有街景图像内指定“入口”全景图,并定制自定义集与标准集之间的双向链接。
  • StreetViewPanoramaData 对象内定义每一幅全景图图像的元数据。
  • 实现确定自定义全景图数据和图像的方法,并将该方法指定为 StreetViewPanorama 对象内的自定义处理程序。

下文对此过程做了说明。

创建自定义全景图

每张街景全景图都是一幅图像或一组图像,提供以单个位置为中心的 360 度全视图。StreetViewPanorama 对象使用遵照等距柱状 (Plate Carrée) 投影的图像。此类投影包含 360 度水平视图(全包围)和 180 度垂直视图(从直上至直下)。这些视野生成的图片具有 2:1 的纵横比。全包围全景图如下所示。

全景图图像一般通过从一个位置拍摄多张照片,然后利用全景图软件进行拼接来获得。(如需了解详细信息,请参阅 Wikipedia 的 Comparison of photo stitching applications [照片拼接应用比较]。)此类图像的“摄像头”所在地(即拍摄每一幅全景图图像的位置)应是同一个。生成的 360 度全景图随后便可定义一个球面投影,其图像包绕在球面的二维表面上。

将全景图视为采用直线坐标系的球面上投影有助于将图像分解成直线图块,以及根据计算的图块坐标提供图像。

创建自定义全景图图块

街景还支持利用缩放控件实现不同的图像详细程度,该控件允许您基于默认视图进行缩放。街景一般可为任何给定全景图图像提供五级缩放分辨率。如果您想靠一幅全景图图像服务所有缩放比例,此类图像要么必定体积偏大,会显著拖慢应用速度,要么在较高缩放比例下分辨率不佳,只能提供低像素图像。但幸运的是,我们可以在不同缩放比例下使用与提供 Google 地图图块时所用相似的设计模式,为各缩放比例下的全景图提供分辨率适当的图像。

StreetViewPanorama 首次加载时,默认情况下其显示的图像包括缩放比例为 1 的全景图水平宽度的 25%(圆弧的 90 度)。此视野大致与人的正常视野一致。在此默认视野基础上“缩小”实质上是将圆弧变大,而放大则会将视野缩窄到更小的圆弧上。StreetViewPanorama 会自动计算与所选缩放比例相适的视野,然后通过选择与水平视野尺寸大致相同的图块集,选择最适合该分辨率的图像。以下是视野与街景缩放比例的对应关系:

街景缩放比例 视野(度)
0 180
1(默认值) 90
2 45
3 22.5
4 11.25

请注意,街景内显示的图像尺寸完全取决于街景容器的屏幕尺寸(宽度)。如果您提供的容器较宽,服务仍会为任何给定缩放比例提供相同的视野,但可能会改为选择更适合该分辨率的图块。

由于每一幅全景图都包括一个等距柱状投影,因此创建全景图图块相对容易。由于投影提供的图像纵横比为 2:1,因此具有 2:1 纵横比的图块更便于使用,但方形图块可能会在方形地图上带来更好的性能(因为视野将是方形的)。

对于 2:1 图块,一幅囊括整个全景图的图像表示缩放比例为 0 的整个全景图“世界”(基础图像),缩放比例每增加 1,缩放比例图块增加 4.(例如,当缩放比例为 2 时,整个全景图包括 16 个图块。):街景图块覆盖中的缩放比例并不直接对应于使用街景控件时提供的缩放比例;街景控件缩放比例改为选择视野 (FoV),然后从视野中选择合适的图块。

您通常希望对图像图块命名,以便以编程方式选择它们。下面的处理自定义全景图请求中介绍了这一命名架构。

处理自定义全景图请求

通过在 StreetViewPanoramaOptions panoProvider 字段内注册自定义全景图方法,或者显式地调用 StreetViewPanorama.registerPanoProvider() 来表示使用自定义全景图。该全景图提供程序方法是一个返回 StreetViewPanoramaData 对象的函数,具有以下签名:

Function(pano,zoom,tileX,tileY):StreetViewPanoramaData

StreetViewPanoramaData 是以下形式的对象:

{
  copyright: string,
  location: {
    description: string,
    latLng: google.maps.LatLng,
    pano: string
  },
  tiles: {
    tileSize: google.maps.Size,
    worldSize: google.maps.Size,
    heading: number,
    getTileUrl: Function
  },
  links: [
    description: string,
    heading: number,
    pano: string,
    roadColor: string,
    roadOpacity: number
  ]
}

您只需将 StreetViewPanoramapano 属性设置为某个自定义值,设置 panoProvider,然后在自定义全景图提供程序方法内处理该自定义 pano 值,构造一个 StreetViewPanoramaData 对象并将其返回,便可显示自定义全景图。

注:请勿在想要显示自定义全景图时在 StreetViewPanorama 上设置 position,因为此类位置将指示街景服务请求靠近该位置的默认街景图像。请改为在自定义 StreetViewPanoramaDatalocation.latLng 字段内设置该位置。

下例显示了 Google 悉尼分公司的自定义全景图。请注意,我们在示例中根本没有使用任何地图(或默认街景图像):

function initPano() {
  // Set up Street View and initially set it visible. Register the
  // custom panorama provider function. Set the StreetView to display
  // the custom panorama 'reception' which we check for below.
  var panorama = new google.maps.StreetViewPanorama(
    document.getElementById('map'), {
      pano: 'reception',
      visible: true,
      panoProvider: getCustomPanorama
  });
}

// Return a pano image given the panoID.
function getCustomPanoramaTileUrl(pano, zoom, tileX, tileY) {
  // Note: robust custom panorama methods would require tiled pano data.
  // Here we're just using a single tile, set to the tile size and equal
  // to the pano "world" size.
  return 'https://developers.google.com/maps/documentation/javascript/examples/full/images/panoReception1024-0.jpg';
}

// Construct the appropriate StreetViewPanoramaData given
// the passed pano IDs.
function getCustomPanorama(pano, zoom, tileX, tileY) {
  if (pano === 'reception') {
    return {
      location: {
        pano: 'reception',
        description: 'Google Sydney - Reception'
      },
      links: [],
      // The text for the copyright control.
      copyright: 'Imagery (c) 2010 Google',
      // The definition of the tiles for this panorama.
      tiles: {
        tileSize: new google.maps.Size(1024, 512),
        worldSize: new google.maps.Size(1024, 512),
        // The heading in degrees at the origin of the panorama
        // tile set.
        centerHeading: 105,
        getTileUrl: getCustomPanoramaTileUrl
      }
    };
  }
}
<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 async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initPano">
</script>
function initPano() {
  // Set up Street View and initially set it visible. Register the
  // custom panorama provider function. Set the StreetView to display
  // the custom panorama 'reception' which we check for below.
  var panorama = new google.maps.StreetViewPanorama(
    document.getElementById('map'), {
      pano: 'reception',
      visible: true,
      panoProvider: getCustomPanorama
  });
}

// Return a pano image given the panoID.
function getCustomPanoramaTileUrl(pano, zoom, tileX, tileY) {
  // Note: robust custom panorama methods would require tiled pano data.
  // Here we're just using a single tile, set to the tile size and equal
  // to the pano "world" size.
  return 'https://developers.google.com/maps/documentation/javascript/examples/full/images/panoReception1024-0.jpg';
}

// Construct the appropriate StreetViewPanoramaData given
// the passed pano IDs.
function getCustomPanorama(pano, zoom, tileX, tileY) {
  if (pano === 'reception') {
    return {
      location: {
        pano: 'reception',
        description: 'Google Sydney - Reception'
      },
      links: [],
      // The text for the copyright control.
      copyright: 'Imagery (c) 2010 Google',
      // The definition of the tiles for this panorama.
      tiles: {
        tileSize: new google.maps.Size(1024, 512),
        worldSize: new google.maps.Size(1024, 512),
        // The heading in degrees at the origin of the panorama
        // tile set.
        centerHeading: 105,
        getTileUrl: getCustomPanoramaTileUrl
      }
    };
  }
}

查看示例 (streetview-custom-simple.html)

请注意,我们在上例中只返回了一幅图像,并且使用该图像放大导致分辨率不佳。为此,我们可以改为通过创建图块图像并修改 panoProvider 来提供一个图块集,从而根据传递的全景图 ID、缩放比例和全景图图块坐标返回合适的图块。

由于图像选择取决于这些传递的值,因此根据这些传递的值对可以编程方式选择的图像命名(例如 pano_zoom_tileX_tileY.png)很有帮助。

下例对上例略作扩展,提供了两个缩放比例。此外,它在默认街景导航箭头基础上为图像额外添加了一个箭头,该箭头指向 Google 悉尼分公司并链接到自定义图像:

var panorama;

// StreetViewPanoramaData of a panorama just outside the Google Sydney office.
var outsideGoogle;

// StreetViewPanoramaData for a custom panorama: the Google Sydney reception.
function getReceptionPanoramaData() {
  return {
    location: {
      pano: 'reception',  // The ID for this custom panorama.
      description: 'Google Sydney - Reception',
      latLng: new google.maps.LatLng(-33.86684, 151.19583)
    },
    links: [{
      heading: 195,
      description: 'Exit',
      pano: outsideGoogle.location.pano
    }],
    copyright: 'Imagery (c) 2010 Google',
    tiles: {
      tileSize: new google.maps.Size(1024, 512),
      worldSize: new google.maps.Size(2048, 1024),
      centerHeading: 105,
      getTileUrl: function(pano, zoom, tileX, tileY) {
        return 'https://developers.google.com/maps/documentation/javascript/examples/full/images/' +
            'panoReception1024-' + zoom + '-' + tileX + '-' + tileY + '.jpg';
      }
    }
  };
}

function initPanorama() {
  panorama = new google.maps.StreetViewPanorama(
      document.getElementById('street-view'),
      {
        pano: outsideGoogle.location.pano,
        // Register a provider for our custom panorama.
        panoProvider: function(pano) {
          if (pano === 'reception') {
            return getReceptionPanoramaData();
          }
        }
      });

  // Add a link to our custom panorama from outside the Google Sydney office.
  panorama.addListener('links_changed', function() {
    if (panorama.getPano() === outsideGoogle.location.pano) {
      panorama.getLinks().push({
        description: 'Google Sydney',
        heading: 25,
        pano: 'reception'
      });
    }
  });
}

function initialize() {
  // Use the Street View service to find a pano ID on Pirrama Rd, outside the
  // Google office.
  var streetviewService = new google.maps.StreetViewService;
  streetviewService.getPanorama(
      {location: {lat: -33.867386, lng: 151.195767}},
      function(result, status) {
        if (status === 'OK') {
          outsideGoogle = result;
          initPanorama();
        }
      });
}
<div id="street-view"></div>
html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}
#street-view {
  height: 100%;
}
<!-- Replace the value of the key parameter with your own API key. -->
<script async defer
    src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initialize">
</script>
var panorama;

// StreetViewPanoramaData of a panorama just outside the Google Sydney office.
var outsideGoogle;

// StreetViewPanoramaData for a custom panorama: the Google Sydney reception.
function getReceptionPanoramaData() {
  return {
    location: {
      pano: 'reception',  // The ID for this custom panorama.
      description: 'Google Sydney - Reception',
      latLng: new google.maps.LatLng(-33.86684, 151.19583)
    },
    links: [{
      heading: 195,
      description: 'Exit',
      pano: outsideGoogle.location.pano
    }],
    copyright: 'Imagery (c) 2010 Google',
    tiles: {
      tileSize: new google.maps.Size(1024, 512),
      worldSize: new google.maps.Size(2048, 1024),
      centerHeading: 105,
      getTileUrl: function(pano, zoom, tileX, tileY) {
        return 'https://developers.google.com/maps/documentation/javascript/examples/full/images/' +
            'panoReception1024-' + zoom + '-' + tileX + '-' + tileY + '.jpg';
      }
    }
  };
}

function initPanorama() {
  panorama = new google.maps.StreetViewPanorama(
      document.getElementById('street-view'),
      {
        pano: outsideGoogle.location.pano,
        // Register a provider for our custom panorama.
        panoProvider: function(pano) {
          if (pano === 'reception') {
            return getReceptionPanoramaData();
          }
        }
      });

  // Add a link to our custom panorama from outside the Google Sydney office.
  panorama.addListener('links_changed', function() {
    if (panorama.getPano() === outsideGoogle.location.pano) {
      panorama.getLinks().push({
        description: 'Google Sydney',
        heading: 25,
        pano: 'reception'
      });
    }
  });
}

function initialize() {
  // Use the Street View service to find a pano ID on Pirrama Rd, outside the
  // Google office.
  var streetviewService = new google.maps.StreetViewService;
  streetviewService.getPanorama(
      {location: {lat: -33.867386, lng: 151.195767}},
      function(result, status) {
        if (status === 'OK') {
          outsideGoogle = result;
          initPanorama();
        }
      });
}

查看示例 (streetview-custom-tiles.html)

发送以下问题的反馈:

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