您已全部設定完成!

若要開始開發,請參閱我們的開發人員文件

啟用 Google Maps JavaScript API

為協助您開始,我們將先引導您使用「Google 開發人員控制台」來執行一些動作:

  1. 建立或選擇專案
  2. 啟用 Google Maps JavaScript API 與相關服務
  3. 建立適當的金鑰
繼續

「街景服務」服務

總覽

「Google 街景服務」提供指定道路整個涵蓋區域的 360 度全景檢視。「街景服務」的 API 涵蓋範圍與「Google 地圖」應用程式 (https://maps.google.com/) 涵蓋範圍相同。目前支援「街景服務」的城市清單可在 Google 地圖網站找到。

「街景服務」影像範例顯示如下。


Google Maps JavaScript API 提供「街景服務」服務,用來取得和操縱「Google 地圖街景服務」中使用的影像。瀏覽器內原本就支援「街景服務」服務。

「街景服務」地圖用法

雖然「街景服務」可以在獨立的 DOM 元素內使用,但是它在地圖上指出位置時將可以發揮最大的用途。地圖上預設已啟用「街景服務」,而且「街景服務」小黃人控制項已整合到瀏覽(縮放和平移)控制項內。您可以透過將 streetViewControl 設定成 false,以在地圖的 MapOptions 內隱藏這個控制項。您也可以透過將 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,您將會覆寫預設全景並停用自動疊加層共用。

下列範例顯示指明紐約市 Astor Place 周圍各個位置的標記。切換顯示到「街景服務」,以顯示 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_changed 會在個別全景 ID 變更時引發。此事件不保證全景內任何關聯的資料(例如連結)也在這個事件觸發時變更;此事件只指出全景 ID 已變更。請注意,全景 ID(您用它來參照此全景)只在目前的瀏覽器工作階段內才能穩定運作。
  • position_changed 會在全景的底層 (LatLng) 位置變更時引發。旋轉全景將不會觸發此事件。請注意,您可以不變更關聯的全景 ID 而只變更全景的底層位置,因為 API 將會自動將最近的全景 ID 關聯到全景的位置。
  • pov_changed 會在「街景服務」的 StreetViewPov 變更時引發。請注意,這個事件引發時,位置和全景 ID 仍維持穩定。
  • links_changed 會在「街景服務」的連結變更時引發。請注意,透過 pano_changed 指出全景 ID 變更之後,會非同步地引發此事件。
  • visible_changed 會在「街景服務」的能見度變更時引發。請注意,透過 pano_changed 指出全景 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 控制項可讓使用者關閉「街景服務」檢視器。將 Close 控制項的 enableCloseButton 設定成 truefalse,即可啟用或停用它:

下列範例會修改於關聯「街景服務」內顯示的控制項並移除檢視的連結:

全螢幕檢視此範例。

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() 需要一個「回呼」函式,以於從「街景服務」服務擷取到結果時執行。此回呼函式會傳回 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 中的相片拼接應用程式比較。)此類影像應該共用單一的「相機」地點,也就是每個全景影像的拍攝地點。產生的 360 度全景即可透過將影像包圍在二維球體表面,以在球體上定義投影。

將全景視為在使用直線座標系統的球面上的投影,對於將影像分成直線型「地圖方塊」,並根據計算的地圖方塊座標提供影像而言,具有很大的優點。

建立自訂全景地圖方塊

「街景服務」也透過縮放控制項來支援不同層級的影像詳細資料,讓您放大和縮小預設檢視。一般而言,「街景服務」針對任何特定全景影像,提供五種解析度縮放層級。如果您要依賴單一全景影像來處理所有縮放層級,此類影像可能就會過大而大幅降低應用程式的速度,或者在較高的縮放層級因解析度太差而產生低落品質的像素化影像。然而,我們可以使用類似在不同縮放層級提供 Google 地圖之地圖方塊的設計模式,為每個縮放層級的全景提供適當解析度的影像。

StreetViewPanorama 一開始載入時,預設會顯示由 25%(90 度弧度)水平寬度之縮放層級 1 的全景所組成的影像。這個視圖約略對應一般的人類視野。縮小這個預設檢視基本上會提供更寬的弧度,放大則會將視野縮小至較小的弧度。StreetViewPanorama 會自動計算所選縮放層級的適當視野,然後選擇最適合該解析度的影像,方式是選取大約符合水平視野維度的地圖方塊集。下列視野對應到「街景服務」縮放層級:

「街景服務」縮放層級 視野(角度)
0 180
1(預設) 90
2 45
3 22.5
4 11.25

請注意,「街景服務」內顯示的影像大小完全取決於「街景服務」容器的畫面大小(寬度)。如果您提供更寬的容器,該服務仍會為任何指定的縮放層級提供相同的視野,不過它可能會選取更適合該解析度的地圖方塊。

因為每個全景是由等距圓柱投影組成,所以建立全景地圖方塊相對較為簡單。由於投影提供外觀比例為 2:1 的影像,所以 2:1 比例的地圖方塊將較易於使用,即使正方形地圖方塊在正方形地圖上可提供更好的效能(因為視野將會是正方形的)。

對於 2:1 的地圖方塊,圍繞整個全景的單一影像代表縮放層級 0 的整個全景「世界」(基本影像),而每增加一個縮放層級,將會提供 4 個 zoomLevel 地圖方塊。(例如,在縮放層級 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
需要協助嗎?請前往我們的支援網頁