概要
Google ストリートビューは、対象地域全体について、指定された道路からの 360 度のパノラマビューを提供します。ストリートビューの API の対象地域は、Google マップ アプリケーション(https://maps.google.com/
)の対象地域と同じです。ストリートビューを現在利用できる都市の一覧については、Google マップのウェブサイトをご覧ください。
ストリートビュー画像の例は次のとおりです。
Maps JavaScript API には、Google マップのストリートビューで使用される画像を取得および操作するためのストリートビュー サービスが用意されています。ストリートビュー サービスは、ブラウザ内でネイティブにサポートされています。
ストリートビュー地図の用途
ストリートビューは、スタンドアロンの DOM 要素内で使用できますが、用途として最も便利なのは地図上で場所を特定したいときです。地図でストリートビューはデフォルトで有効になっており、ズームや移動に使用するナビゲーション コントロールには、ストリートビューの「ペグマン コントロール」が統合されています。このコントロールを非表示にするには、地図の MapOptions
で streetViewControl
を false
に設定します。ストリートビュー コントロールのデフォルトの位置を変更することもできます。その場合は、Map
の streetViewControlOptions.position
プロパティを新しい ControlPosition
に設定します。
ストリートビューのペグマン コントロールを使用して、地図内で直接ストリートビューのパノラマ画像を表示できます。ユーザーがペグマンを長押しすると地図が更新され、ストリートビューが有効な道路の周りに青い輪郭線が表示されて、Google マップアプリと同様の機能が提供されます。
ユーザーがペグマン マーカーを道路にドロップすると、地図が更新されて、指定された場所のストリートビュー パノラマが表示されます。
ストリートビュー パノラマ
ストリートビュー画像は、StreetViewPanorama
オブジェクトを使用することでサポートされます。このオブジェクトがストリートビュー「ビューア」への API インターフェースとなります。各地図にはデフォルトのストリートビュー パノラマがあり、これは地図の getStreetView()
メソッドを呼び出して取得できます。streetViewControl
オプションを true
に設定してストリートビュー コントロールを地図に追加すると、ペグマン コントロールがこのデフォルトのストリートビュー パノラマに自動的に接続されます。
独自の StreetViewPanorama
オブジェクトを作成して、地図の streetView
プロパティを明示的にこの作成したオブジェクトに設定することで、地図でデフォルトのオブジェクトを使わずに、作成したオブジェクトを使用することもできます。地図とパノラマ画像間のオーバーレイの自動共有など、デフォルトの動作を変更する場合、デフォルトのパノラマ画像をオーバーライドすることをおすすめします(下記のストリートビュー内のオーバーレイを参照してください)。
ストリートビュー コンテナ
別の DOM 要素(一般には <div>
要素)内の StreetViewPanorama
を表示する場合は、StreetViewPanorama
のコンストラクタ内で DOM 要素を渡します。画像の表示を最適化するために、最小サイズの 200 x 200 ピクセルを推奨します。
注: ストリートビュー機能は地図との併用を念頭に設計されていますが、地図の使用が必須であるというわけではありません。地図を使用せずに、ストリートビュー オブジェクトを単独で使用することもできます。
ストリートビューの位置情報と視点(POV)
StreetViewPanorama
コンストラクタで StreetViewOptions
パラメータを使用して、ストリートビューの場所と視点を設定することもできます。場所と視点を変更するには、オブジェクト作成後にそのオブジェクトの
setPosition()
と setPov()
を呼び出します。
ストリートビューではカメラで何を写すかが「場所」として定義されますが、このときカメラ画像の向きは指定されません。向きを指定するには、StreetViewPov
オブジェクトで次の 2 つのプロパティを指定します。
heading
(デフォルトは0
)は、カメラ中心の回転角度を、真北からの相対角度で定義します。方角の相対角度は時計回りで定義します(90 度に設定すると東向きになります)。pitch
(デフォルトは0
)は、カメラの初期デフォルト ピッチからの「上」または「下」向きの角度を定義します。通常は水平です(常に水平とは限りません。たとえば、山で撮影された画像は、水平ではないデフォルトの初期ピッチで表示される場合があります)。ピッチ角度は、見上げる方向を正の値(デフォルトのピッチと直行する真上方向が +90 度)で、下を向く方向を負の値(デフォルトのピッチと直交する真下の方向が -90 度)として指定します。
StreetViewPov
オブジェクトは、ほとんどの場合、ストリートビュー カメラの視点の特定に使用されます。StreetViewPanorama.getPhotographerPov()
メソッドを使用して、撮影者の視点(通常は車やトライクが向いていた方向)を特定することもできます。
次のコードは、ボストンの地図とフェンウェイ パークの初期ビューです。ペグマンを選択して地図上のサポート対象の場所にドラッグすると、ストリートビュー パノラマが変化します。
TypeScript
function initialize() { const fenway = { lat: 42.345573, lng: -71.098326 }; const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { center: fenway, zoom: 14, } ); const panorama = new google.maps.StreetViewPanorama( document.getElementById("pano") as HTMLElement, { position: fenway, pov: { heading: 34, pitch: 10, }, } ); map.setStreetView(panorama); } declare global { interface Window { initialize: () => void; } } window.initialize = initialize;
JavaScript
function initialize() { const fenway = { lat: 42.345573, lng: -71.098326 }; const map = new google.maps.Map(document.getElementById("map"), { center: fenway, zoom: 14, }); const panorama = new google.maps.StreetViewPanorama( document.getElementById("pano"), { position: fenway, pov: { heading: 34, pitch: 10, }, }, ); map.setStreetView(panorama); } window.initialize = initialize;
CSS
html, body { height: 100%; margin: 0; padding: 0; } #map, #pano { float: left; height: 100%; width: 50%; }
HTML
<html> <head> <title>Street View split-map-panes</title> <link rel="stylesheet" type="text/css" href="./style.css" /> <script type="module" src="./index.js"></script> </head> <body> <div id="map"></div> <div id="pano"></div> <!-- The `defer` attribute causes the script to execute after the full HTML document has been parsed. For non-blocking uses, avoiding race conditions, and consistent behavior across browsers, consider loading using Promises. See https://developers.google.com/maps/documentation/javascript/load-maps-js-api for more information. --> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initialize&v=weekly" defer ></script> </body> </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 } });
実際のモーション トラッキングの動作を確認するには、モバイル デバイス(またはデバイスの画面の向きイベントをサポートする任意のデバイス)で次のサンプルを表示してください。
ストリートビュー内のオーバーレイ
デフォルトの StreetViewPanorama
オブジェクトは地図オーバーレイの表示をネイティブにサポートします。オーバーレイは一般に、LatLng
の位置に固定された「ストリート レベル」で表示されます(たとえば、マーカーは、その尾の部分がストリートビュー パノラマ内で場所の水平面に固定されて表示されます)。
現在、ストリートビュー パノラマでサポートされているオーバーレイのタイプは、Marker
、InfoWindow
、カスタムの OverlayView
に制限されています。地図上に表示するオーバーレイは、ストリートビュー パノラマ上でも表示できます。その場合は、パノラマ画像を Map
オブジェクトの代替として扱い、setMap()
を呼び出して引数に地図の代わりに StreetViewPanorama
を渡します。情報ウィンドウも同様に、open()
を呼び出して、地図の代わりに StreetViewPanorama()
を渡すことで、ストリートビュー パノラマ内で開くことができます。
また、デフォルトの StreetViewPanorama
で地図を作成する場合、地図上にマーカーが作成されると、地図の関連付けられたストリートビュー パノラマと自動的に共有されます(パノラマが表示されている場合)。デフォルトのストリートビュー パノラマを取得するには、Map
オブジェクトの getStreetView()
を呼び出します。地図の streetView
プロパティを明示的に独自構成の StreetViewPanorama
に設定する場合、デフォルトのパノラマ画像をオーバーライドすることになります。
次の例は、ニューヨーク市アスター プレイス周辺のさまざまな場所を表すマーカーを表示します。ストリートビューに表示を切り替えると、共有マーカーが StreetViewPanorama
内に表示されます。
TypeScript
let panorama: google.maps.StreetViewPanorama; function initMap(): void { const astorPlace = { lat: 40.729884, lng: -73.990988 }; // Set up the map const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { center: astorPlace, zoom: 18, streetViewControl: false, } ); document .getElementById("toggle")! .addEventListener("click", toggleStreetView); const cafeIcon = document.createElement("img"); cafeIcon.src = "https://developers.google.com/maps/documentation/javascript/examples/full/images/cafe_icon.svg"; const dollarIcon = document.createElement("img"); dollarIcon.src = "https://developers.google.com/maps/documentation/javascript/examples/full/images/bank_icon.svg"; const busIcon = document.createElement("img"); busIcon.src = "https://developers.google.com/maps/documentation/javascript/examples/full/images/bus_icon.svg"; // Set up the markers on the map const cafeMarker = new google.maps.Marker({ position: { lat: 40.730031, lng: -73.991428 }, map, title: "Cafe", icon: cafeIcon.src, }); const bankMarker = new google.maps.Marker({ position: { lat: 40.729681, lng: -73.991138 }, map, title: "Bank", icon: dollarIcon.src, }); const busMarker = new google.maps.Marker({ position: { lat: 40.729559, lng: -73.990741 }, map, title: "Bus Stop", icon: busIcon.src, }); // We get the map's default panorama and set up some defaults. // Note that we don't yet set it visible. panorama = map.getStreetView()!; // TODO fix type panorama.setPosition(astorPlace); panorama.setPov( /** @type {google.maps.StreetViewPov} */ { heading: 265, pitch: 0, } ); } function toggleStreetView(): void { const toggle = panorama.getVisible(); if (toggle == false) { panorama.setVisible(true); } else { panorama.setVisible(false); } } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
let panorama; function initMap() { const astorPlace = { lat: 40.729884, lng: -73.990988 }; // Set up the map const map = new google.maps.Map(document.getElementById("map"), { center: astorPlace, zoom: 18, streetViewControl: false, }); document.getElementById("toggle").addEventListener("click", toggleStreetView); const cafeIcon = document.createElement("img"); cafeIcon.src = "https://developers.google.com/maps/documentation/javascript/examples/full/images/cafe_icon.svg"; const dollarIcon = document.createElement("img"); dollarIcon.src = "https://developers.google.com/maps/documentation/javascript/examples/full/images/bank_icon.svg"; const busIcon = document.createElement("img"); busIcon.src = "https://developers.google.com/maps/documentation/javascript/examples/full/images/bus_icon.svg"; // Set up the markers on the map const cafeMarker = new google.maps.Marker({ position: { lat: 40.730031, lng: -73.991428 }, map, title: "Cafe", icon: cafeIcon.src, }); const bankMarker = new google.maps.Marker({ position: { lat: 40.729681, lng: -73.991138 }, map, title: "Bank", icon: dollarIcon.src, }); const busMarker = new google.maps.Marker({ position: { lat: 40.729559, lng: -73.990741 }, map, title: "Bus Stop", icon: busIcon.src, }); // We get the map's default panorama and set up some defaults. // Note that we don't yet set it visible. panorama = map.getStreetView(); // TODO fix type panorama.setPosition(astorPlace); panorama.setPov( /** @type {google.maps.StreetViewPov} */ { heading: 265, pitch: 0, }, ); } function toggleStreetView() { const toggle = panorama.getVisible(); if (toggle == false) { panorama.setVisible(true); } else { panorama.setVisible(false); } } window.initMap = initMap;
CSS
/* * 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; }
HTML
<html> <head> <title>Overlays Within Street View</title> <link rel="stylesheet" type="text/css" href="./style.css" /> <script type="module" src="./index.js"></script> </head> <body> <div id="floating-panel"> <input type="button" value="Toggle Street View" id="toggle" /> </div> <div id="map"></div> <!-- The `defer` attribute causes the script to execute after the full HTML document has been parsed. For non-blocking uses, avoiding race conditions, and consistent behavior across browsers, consider loading using Promises. See https://developers.google.com/maps/documentation/javascript/load-maps-js-api for more information. --> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&libraries=marker&v=weekly" defer ></script> </body> </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
のデータを収集します。
TypeScript
function initPano() { const panorama = new google.maps.StreetViewPanorama( document.getElementById("pano") as HTMLElement, { position: { lat: 37.869, lng: -122.255 }, pov: { heading: 270, pitch: 0, }, visible: true, } ); panorama.addListener("pano_changed", () => { const panoCell = document.getElementById("pano-cell") as HTMLElement; panoCell.innerHTML = panorama.getPano(); }); panorama.addListener("links_changed", () => { const linksTable = document.getElementById("links_table") as HTMLElement; while (linksTable.hasChildNodes()) { linksTable.removeChild(linksTable.lastChild as ChildNode); } const links = panorama.getLinks(); for (const i in links) { const row = document.createElement("tr"); linksTable.appendChild(row); const labelCell = document.createElement("td"); labelCell.innerHTML = "<b>Link: " + i + "</b>"; const valueCell = document.createElement("td"); valueCell.innerHTML = links[i].description as string; linksTable.appendChild(labelCell); linksTable.appendChild(valueCell); } }); panorama.addListener("position_changed", () => { const positionCell = document.getElementById( "position-cell" ) as HTMLElement; (positionCell.firstChild as HTMLElement).nodeValue = panorama.getPosition() + ""; }); panorama.addListener("pov_changed", () => { const headingCell = document.getElementById("heading-cell") as HTMLElement; const pitchCell = document.getElementById("pitch-cell") as HTMLElement; (headingCell.firstChild as HTMLElement).nodeValue = panorama.getPov().heading + ""; (pitchCell.firstChild as HTMLElement).nodeValue = panorama.getPov().pitch + ""; }); } declare global { interface Window { initPano: () => void; } } window.initPano = initPano;
JavaScript
function initPano() { const 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", () => { const panoCell = document.getElementById("pano-cell"); panoCell.innerHTML = panorama.getPano(); }); panorama.addListener("links_changed", () => { const linksTable = document.getElementById("links_table"); while (linksTable.hasChildNodes()) { linksTable.removeChild(linksTable.lastChild); } const links = panorama.getLinks(); for (const i in links) { const row = document.createElement("tr"); linksTable.appendChild(row); const labelCell = document.createElement("td"); labelCell.innerHTML = "<b>Link: " + i + "</b>"; const valueCell = document.createElement("td"); valueCell.innerHTML = links[i].description; linksTable.appendChild(labelCell); linksTable.appendChild(valueCell); } }); panorama.addListener("position_changed", () => { const positionCell = document.getElementById("position-cell"); positionCell.firstChild.nodeValue = panorama.getPosition() + ""; }); panorama.addListener("pov_changed", () => { const headingCell = document.getElementById("heading-cell"); const pitchCell = document.getElementById("pitch-cell"); headingCell.firstChild.nodeValue = panorama.getPov().heading + ""; pitchCell.firstChild.nodeValue = panorama.getPov().pitch + ""; }); } window.initPano = initPano;
CSS
/* * 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; }
HTML
<html> <head> <title>Street View Events</title> <link rel="stylesheet" type="text/css" href="./style.css" /> <script type="module" src="./index.js"></script> </head> <body> <div id="pano"></div> <div id="floating-panel"> <table> <tr> <td><b>Position</b></td> <td id="position-cell"> </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"> </td> </tr> <table id="links_table"></table> </table> </div> <!-- The `defer` attribute causes the script to execute after the full HTML document has been parsed. For non-blocking uses, avoiding race conditions, and consistent behavior across browsers, consider loading using Promises. See https://developers.google.com/maps/documentation/javascript/load-maps-js-api for more information. --> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initPano&v=weekly" defer ></script> </body> </html>
サンプルを試す
ストリートビューのコントロール
StreetViewPanorama
を表示するとき、デフォルトでさまざまなコントロールがパノラマに表示されます。これらのコントロールは、ストリートビューの StreetViewPanoramaOptions
内にある該当のフィールドを true
または false
に設定して、有効または無効にできます。
panControl
は、パノラマを回転させるために使用します。このコントロールは、デフォルトでコンパスとパンが統合された標準コントロールとして表示されます。panControlOptions
フィールドのPanControlOptions
を指定して、コントロールの位置を変更できます。zoomControl
は、画像内をズームするために使用します。このコントロールは、デフォルトでパノラマ画像の右下に表示されます。コントロールの外観を変更するには、zoomControlOptions
フィールド内でZoomControlOptions
を指定します。addressControl
は、関連する場所の住所を示すテキスト オーバーレイと、Google マップでその場所を開くためのリンクを提供します。コントロールの外観を変更するには、addressControlOptions
フィールド内でStreetViewAddressControlOptions
を指定します。fullscreenControl
は、ストリートビューを全画面モードで開くオプションを提供します。コントロールの外観を変更するには、fullscreenControlOptions
フィールド内でFullscreenControlOptions
を指定します。motionTrackingControl
は、モバイル デバイスでモーション トラッキングを有効または無効にするオプションを提供します。このコントールは、デバイスの画面の向きイベントをサポートするデバイスでのみ表示されます。このコントロールは、デフォルトでパノラマ画像の右下に表示されます。コントロールの位置を変更するには、MotionTrackingControlOptions
を指定します。詳しくは、モーション トラッキングのセクションをご覧ください。linksControl
は、隣接するパノラマ画像に移動するためのガイド矢印を画面上に表示します。- クローズ コントロールがあると、ユーザーがストリートビューのビューアを閉じることができます。クローズ コントロールは、
enableCloseButton
をtrue
またはfalse
に設定することで有効または無効にできます。
次の例は、関連するストリートビュー内に表示されるコントロールを変更して、ビューのリンクを削除しています。
TypeScript
function initPano() { // Note: constructed panorama objects have visible: true // set by default. const panorama = new google.maps.StreetViewPanorama( document.getElementById("map") as HTMLElement, { position: { lat: 42.345573, lng: -71.098326 }, addressControlOptions: { position: google.maps.ControlPosition.BOTTOM_CENTER, }, linksControl: false, panControl: false, enableCloseButton: false, } ); } declare global { interface Window { initPano: () => void; } } window.initPano = initPano;
JavaScript
function initPano() { // Note: constructed panorama objects have visible: true // set by default. const 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, }, ); } window.initPano = initPano;
CSS
/* * 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; }
HTML
<html> <head> <title>Street View Controls</title> <link rel="stylesheet" type="text/css" href="./style.css" /> <script type="module" src="./index.js"></script> </head> <body> <div id="map"></div> <!-- The `defer` attribute causes the script to execute after the full HTML document has been parsed. For non-blocking uses, avoiding race conditions, and consistent behavior across browsers, consider loading using Promises. See https://developers.google.com/maps/documentation/javascript/load-maps-js-api for more information. --> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initPano&v=weekly" defer ></script> </body> </html>
サンプルを試す
ストリートビューのデータへの直接アクセス
地図やパノラマ画像を直接操作する必要なく、プログラムを使用してストリートビュー データの利用可否を判断したり、特定のパノラマ画像に関する情報を返したりすることが必要な場合があります。StreetViewService
オブジェクトを使用して、これを実行できます。このオブジェクトには Google のストリートビュー サービスに保存されているデータへのインターフェースがあります。
ストリートビュー サービスのリクエスト
ストリートビュー サービスにアクセスすると、Google Maps API は外部サーバーに対して呼び出しを行うので、処理が非同期になります。このため、コールバック メソッドを渡してリクエストの完了時に実行し、このコールバック メソッドで結果を処理する必要があります。
StreetViewService
へのリクエストは、StreetViewPanoRequest
または StreetViewLocationRequest
を使用して実行できます。
StreetViewPanoRequest
を使用したリクエストは、パノラマ画像を一意に識別する参照 ID が指定されたパノラマデータを返します。これらの参照 ID は、該当のパノラマ画像の使用期間のみ不変です。
StreetViewLocationRequest
を使用するリクエストは、次のパラメータを使用して、指定された場所のパノラマデータを検索します。
location
は、パノラマを検索する場所(緯度と経度)を指定します。preference
は、指定された場所に最も近い位置にあるパノラマや、半径内で最適なパノラマなど、半径内でどのようなパノラマを優先して検索するかを設定します。radius
は、パノラマを検索する半径(メートル単位)を設定します。指定された緯度と経度の地点を中心とした半径になります。指定しない場合のデフォルトは 50 です。source
は、検索するパノラマのソースを指定します。有効な値は次のとおりです。default
は、ストリートビューのデフォルトのソースを使用します。検索対象が特定のソースに限定されません。outdoor
は、検索対象を屋外のパノラマのみに限定します。 なお、指定された場所の屋外のパノラマが存在しない場合があります。
ストリートビュー サービスのレスポンス
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
: ストリートビュー リクエストが処理できず、正確な理由が不明であることを示します。
次のコードは、マーカーを作成し、地図上でのユーザーのクリックに応答する StreetViewService
を作成します。このマーカーをクリックすると、その場所の StreetViewPanorama
を表示します。コードはサービスから返された StreetViewPanoramaData
のコンテンツを使用します。
TypeScript
/* * Click the map to set a new location for the Street View camera. */ let map: google.maps.Map; let panorama: google.maps.StreetViewPanorama; function initMap(): void { const berkeley = { lat: 37.869085, lng: -122.254775 }; const sv = new google.maps.StreetViewService(); panorama = new google.maps.StreetViewPanorama( document.getElementById("pano") as HTMLElement ); // Set up the map. map = new google.maps.Map(document.getElementById("map") as HTMLElement, { center: berkeley, zoom: 16, streetViewControl: false, }); // Set the initial Street View camera to the center of the map sv.getPanorama({ location: berkeley, radius: 50 }).then(processSVData); // Look for a nearby Street View panorama when the map is clicked. // getPanorama will return the nearest pano when the given // radius is 50 meters or less. map.addListener("click", (event) => { sv.getPanorama({ location: event.latLng, radius: 50 }) .then(processSVData) .catch((e) => console.error("Street View data not found for this location.") ); }); } function processSVData({ data }: google.maps.StreetViewResponse) { const location = data.location!; const marker = new google.maps.Marker({ position: location.latLng, map, title: location.description, }); panorama.setPano(location.pano as string); panorama.setPov({ heading: 270, pitch: 0, }); panorama.setVisible(true); marker.addListener("click", () => { const markerPanoID = location.pano; // Set the Pano to use the passed panoID. panorama.setPano(markerPanoID as string); panorama.setPov({ heading: 270, pitch: 0, }); panorama.setVisible(true); }); } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
/* * Click the map to set a new location for the Street View camera. */ let map; let panorama; function initMap() { const berkeley = { lat: 37.869085, lng: -122.254775 }; const 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 }).then(processSVData); // Look for a nearby Street View panorama when the map is clicked. // getPanorama will return the nearest pano when the given // radius is 50 meters or less. map.addListener("click", (event) => { sv.getPanorama({ location: event.latLng, radius: 50 }) .then(processSVData) .catch((e) => console.error("Street View data not found for this location."), ); }); } function processSVData({ data }) { const location = data.location; const marker = new google.maps.Marker({ position: location.latLng, map, title: location.description, }); panorama.setPano(location.pano); panorama.setPov({ heading: 270, pitch: 0, }); panorama.setVisible(true); marker.addListener("click", () => { const markerPanoID = location.pano; // Set the Pano to use the passed panoID. panorama.setPano(markerPanoID); panorama.setPov({ heading: 270, pitch: 0, }); panorama.setVisible(true); }); } window.initMap = initMap;
CSS
/* * 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; }
HTML
<html> <head> <title>Directly Accessing Street View Data</title> <link rel="stylesheet" type="text/css" href="./style.css" /> <script type="module" src="./index.js"></script> </head> <body> <div id="map" style="width: 45%; height: 100%; float: left"></div> <div id="pano" style="width: 45%; height: 100%; float: left"></div> <!-- The `defer` attribute causes the script to execute after the full HTML document has been parsed. For non-blocking uses, avoiding race conditions, and consistent behavior across browsers, consider loading using Promises. See https://developers.google.com/maps/documentation/javascript/load-maps-js-api for more information. --> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly" defer ></script> </body> </html>
サンプルを試す
カスタム ストリートビュー パノラマの指定
Maps JavaScript API は、StreetViewPanorama
オブジェクト内のカスタム パノラマの表示に対応しています。カスタムのパノラマ画像を使用すると、ビルの内部や風光明媚な場所の景色、その他にも考えられるあらゆる画像を表示できます。これらのカスタム パノラマ画像から Google の既存のストリートビュー パノラマ画像へのリンクも設定できます。
一連のカスタム パノラマ画像を設定するには、次の手順に従います。
- 各カスタム パノラマの基本パノラマ画像を作成します。この基本画像はズームイン画像を提供するため、最高解像度の画像である必要があります。
- (オプション、推奨)基本画像から、異なるズームレベルの一連のパノラマタイルを作成します。
- カスタム パノラマ画像間のリンクを作成します。
- (省略可能)Google の既存のストリートビュー画像の中から「エントリ」パノラマを指定し、カスタムセットと標準セット間のリンクをカスタマイズします。
StreetViewPanoramaData
オブジェクト内で、各パノラマ画像のメタデータを定義します。- カスタム パノラマのデータと画像を特定するためのメソッドを実装し、そのメソッドを
StreetViewPanorama
オブジェクト内でカスタム ハンドラとして指定します。
以降のセクションでこの処理について説明します。
カスタム パノラマを作成する
各ストリートビュー パノラマは、単一地点からの 360 度ビューを提供する 1 枚の画像または画像のセットです。StreetViewPanorama
オブジェクトは、正距円筒図法(Plate Carrée 図法)に準拠した画像を使用します。このような図法では、360 度の水平ビュー(周囲全体)と 180 度の垂直ビュー(真上から真下)が含まれています。これらの視野を合わせてアスペクト比 2:1 の画像にします。湾曲したパノラマの全体画像は次のようになります。
通常、パノラマ画像は、1 か所から複数の写真を撮影して、パノラマ ソフトウェアを使用してそれらをスティッチする(つなぎ合わせる)ことで取得します(詳しくは、写真のスティッチ用アプリケーションの比較に関する Wikipedia をご覧ください)。これらのパノラマ画像は、カメラを 1 地点に固定して撮影する必要があります。そうすることで、2 次元平面画像を 360 度パノラマの球体に投影することができます。
パノラマを直線座標系で球体に投影しておくと、画像を直線的な「タイル」に分割する場合や、計算上のタイル座標に基づいて画像を提供する場合に便利です。
カスタムのパノラマタイルを作成する
ストリートビューでは、ズームレベルが異なる画像を用意し、ズーム コントロールを使ってデフォルト ビューからズームインしたりズームアウトしたりできます。通常、ストリートビューでは所定のパノラマ画像に対して 5 レベルのズーム解像度が提供されます。単一のパノラマ画像を使用してすべてのズームレベルを提供しようとすると、このような画像は必然的に大きなものになりアプリケーションを著しく低速化するか、高ズームレベルで非常に粗い解像度となりピクセル化された見劣りする画像を提供することになります。ただし、ズームレベルごとに解像度を変えた画像は、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 ではパノラマの全範囲を含んだ 1 つの画像(基本画像)がパノラマ全体を表し、ズームレベルを上げると全体が 4 zoomLevel 個分のタイルで表示されます(たとえば、ズームレベル 2 ではパノラマ全体が 16 枚のタイルで構成されます)。注: ストリートビューのズームレベルのタイルは、ストリートビュー コントロールで指定したズームレベルと完全に一致するわけではありません。ストリートビュー コントロールのズームレベルの場合は、指定された視野(FoV)に基づいて適切なタイルが選択されます。
通常は、画像タイルに名前を付けて、プログラムによって選択できるようにします。このような場合の命名規則については、カスタム パノラマ リクエストの処理をご覧ください。
カスタム パノラマ リクエストの処理
カスタム パノラマを使用するには、StreetViewPanorama.registerPanoProvider()
を呼び出してカスタム パノラマ プロバイダのメソッドの名前を指定します。パノラマ プロバイダのメソッドは StreetViewPanoramaData
オブジェクトを返し、次のシグネチャを持つ必要があります。
Function(pano):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 ] }
カスタム パノラマを次のように表示します。
StreetViewPanoramaOptions.pano
プロパティにカスタム値を設定します。StreetViewPanorama.registerPanoProvider()
を呼び出して、カスタム パノラマのプロバイダ関数を指定します。- 指定された
pano
値を処理するカスタム パノラマのプロバイダ関数を実装します。 StreetViewPanoramaData
オブジェクトを作成します。StreetViewTileData.getTileUrl
プロパティを、指定するカスタムタイルのプロバイダ関数の名前に設定します(例:getCustomPanoramaTileUrl
)。- 次のサンプルのように、カスタムタイルのプロバイダ関数を実装します。
StreetViewPanoramaData
オブジェクトを返します。
注: カスタム パノラマを表示したい場合は、position
を直接 StreetViewPanorama
で設定しないようにしてください。位置を直接設定すると、その場所に一番近いデフォルトのストリートビュー画像がリクエストされてしまいます。その代わりに、この位置は、カスタム StreetViewPanoramaData
オブジェクトの location.latLng
フィールド内で設定します。
次の例は、Google シドニー オフィスのカスタム パノラマ画像を表示します。なお、この例では、地図やデフォルトのストリートビュー画像は使用しません。
TypeScript
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. const panorama = new google.maps.StreetViewPanorama( document.getElementById("map") as HTMLElement, { pano: "reception", visible: true } ); panorama.registerPanoProvider(getCustomPanorama); } // Return a pano image given the panoID. function getCustomPanoramaTileUrl( pano: string, zoom: number, tileX: number, tileY: number ): string { return ( "https://developers.google.com/maps/documentation/javascript/examples/full/images/" + "panoReception1024-" + zoom + "-" + tileX + "-" + tileY + ".jpg" ); } // Construct the appropriate StreetViewPanoramaData given // the passed pano IDs. function getCustomPanorama(pano: string): google.maps.StreetViewPanoramaData { 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(2048, 1024), // The heading in degrees at the origin of the panorama // tile set. centerHeading: 105, getTileUrl: getCustomPanoramaTileUrl, }, }; } // @ts-ignore TODO fix typings return null; } declare global { interface Window { initPano: () => void; } } window.initPano = initPano;
JavaScript
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. const panorama = new google.maps.StreetViewPanorama( document.getElementById("map"), { pano: "reception", visible: true }, ); panorama.registerPanoProvider(getCustomPanorama); } // Return a pano image given the panoID. function getCustomPanoramaTileUrl(pano, zoom, tileX, tileY) { return ( "https://developers.google.com/maps/documentation/javascript/examples/full/images/" + "panoReception1024-" + zoom + "-" + tileX + "-" + tileY + ".jpg" ); } // Construct the appropriate StreetViewPanoramaData given // the passed pano IDs. function getCustomPanorama(pano) { 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(2048, 1024), // The heading in degrees at the origin of the panorama // tile set. centerHeading: 105, getTileUrl: getCustomPanoramaTileUrl, }, }; } // @ts-ignore TODO fix typings return null; } window.initPano = initPano;
CSS
/* * 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; }
HTML
<html> <head> <title>Custom Street View Panoramas</title> <link rel="stylesheet" type="text/css" href="./style.css" /> <script type="module" src="./index.js"></script> </head> <body> <div id="map"></div> <!-- The `defer` attribute causes the script to execute after the full HTML document has been parsed. For non-blocking uses, avoiding race conditions, and consistent behavior across browsers, consider loading using Promises. See https://developers.google.com/maps/documentation/javascript/load-maps-js-api for more information. --> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initPano&v=weekly" defer ></script> </body> </html>
サンプルを試す
カスタム パノラマのプロバイダは、渡されたパノラマ ID、ズームレベル、パノラマタイル座標が付与された適切なタイルを返します。画像の選択はこれらの渡される値に依存するため、これらの渡される値を使って、pano_zoom_tileX_tileY.png
などの名前を画像に付けると、プログラムで選択するときに便利です。
次の例では、デフォルトのストリートビューのナビゲーション矢印以外に、Google シドニー オフィスを指す別の矢印とカスタム画像へのリンクを画像に追加しています。
TypeScript
let panorama: google.maps.StreetViewPanorama; // StreetViewPanoramaData of a panorama just outside the Google Sydney office. let outsideGoogle: google.maps.StreetViewPanoramaData; // StreetViewPanoramaData for a custom panorama: the Google Sydney reception. function getReceptionPanoramaData(): google.maps.StreetViewPanoramaData { 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 as google.maps.StreetViewLocation).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: string, zoom: number, tileX: number, tileY: number ): string { 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") as HTMLElement, { pano: (outsideGoogle.location as google.maps.StreetViewLocation).pano } ); // Register a provider for the custom panorama. panorama.registerPanoProvider( (pano: string): google.maps.StreetViewPanoramaData => { if (pano === "reception") { return getReceptionPanoramaData(); } // @ts-ignore TODO fix typings return null; } ); // Add a link to our custom panorama from outside the Google Sydney office. panorama.addListener("links_changed", () => { if ( panorama.getPano() === (outsideGoogle.location as google.maps.StreetViewLocation).pano ) { panorama.getLinks().push({ description: "Google Sydney", heading: 25, pano: "reception", }); } }); } function initMap(): void { // Use the Street View service to find a pano ID on Pirrama Rd, outside the // Google office. new google.maps.StreetViewService() .getPanorama({ location: { lat: -33.867386, lng: 151.195767 } }) .then(({ data }: google.maps.StreetViewResponse) => { outsideGoogle = data; initPanorama(); }); } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
let panorama; // StreetViewPanoramaData of a panorama just outside the Google Sydney office. let 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 the custom panorama. panorama.registerPanoProvider((pano) => { if (pano === "reception") { return getReceptionPanoramaData(); } // @ts-ignore TODO fix typings return null; }); // Add a link to our custom panorama from outside the Google Sydney office. panorama.addListener("links_changed", () => { if (panorama.getPano() === outsideGoogle.location.pano) { panorama.getLinks().push({ description: "Google Sydney", heading: 25, pano: "reception", }); } }); } function initMap() { // Use the Street View service to find a pano ID on Pirrama Rd, outside the // Google office. new google.maps.StreetViewService() .getPanorama({ location: { lat: -33.867386, lng: 151.195767 } }) .then(({ data }) => { outsideGoogle = data; initPanorama(); }); } window.initMap = initMap;
CSS
html, body { height: 100%; margin: 0; padding: 0; } #street-view { height: 100%; }
HTML
<html> <head> <title>Custom Street View Panorama Tiles</title> <link rel="stylesheet" type="text/css" href="./style.css" /> <script type="module" src="./index.js"></script> </head> <body> <div id="street-view"></div> <!-- The `defer` attribute causes the script to execute after the full HTML document has been parsed. For non-blocking uses, avoiding race conditions, and consistent behavior across browsers, consider loading using Promises. See https://developers.google.com/maps/documentation/javascript/load-maps-js-api for more information. --> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly" defer ></script> </body> </html>