Dịch vụ Chế độ xem đường phố

Tổng quan

Chọn nền tảng: Android iOS JavaScript

Chế độ xem đường phố của Google cung cấp chế độ xem toàn cảnh 360 độ từ các con đường được chỉ định trong toàn bộ khu vực bao phủ. Phạm vi áp dụng API của Chế độ xem đường phố giống như phạm vi của ứng dụng Google Maps (https://maps.google.com/). Danh sách các thành phố hiện được hỗ trợ cho Chế độ xem đường phố có trên trang web của Google Maps.

Dưới đây là một hình ảnh minh hoạ trong Chế độ xem đường phố.


API JavaScript của Maps cung cấp dịch vụ Chế độ xem đường phố để thu thập và chỉnh sửa hình ảnh dùng trong Chế độ xem đường phố của Google Maps. Dịch vụ Chế độ xem đường phố này được hỗ trợ sẵn trong trình duyệt.

Sử dụng bản đồ trong Chế độ xem phố

Mặc dù bạn có thể sử dụng Chế độ xem đường phố trong một phần tử DOM độc lập, nhưng chế độ này hữu ích nhất khi chỉ báo vị trí trên bản đồ. Theo mặc định, Chế độ xem đường phố sẽ được bật trên bản đồ và điều khiển Người hình mắc áo trong Chế độ xem đường phố xuất hiện được tích hợp trong các nút điều khiển điều hướng (thu phóng và xoay). Bạn có thể ẩn chế độ điều khiển này trong MapOptions của bản đồ bằng cách đặt streetViewControl thành false. Bạn cũng có thể thay đổi vị trí mặc định của thành phần điều khiển Chế độ xem đường phố bằng cách đặt thuộc tính streetViewControlOptions.position của Map thành một ControlPosition mới.

Kiểm soát Người hình mắc áo trong Chế độ xem đường phố cho phép bạn xem ảnh toàn cảnh của Chế độ xem đường phố ngay trong bản đồ. Khi người dùng nhấp và giữ Người hình mắc áo, bản đồ sẽ cập nhật để hiển thị các đường viền màu xanh dương xung quanh các con phố đã bật Chế độ xem đường phố, mang lại trải nghiệm người dùng tương tự như ứng dụng Google Maps.

Khi người dùng thả điểm đánh dấu Người hình mắc áo xuống một con phố, bản đồ sẽ cập nhật để hiển thị ảnh toàn cảnh về vị trí được chỉ định trong Chế độ xem đường phố.

Ảnh toàn cảnh trong Chế độ xem phố

Hình ảnh trong Chế độ xem đường phố được hỗ trợ thông qua việc sử dụng đối tượng StreetViewPanorama. Đối tượng này cung cấp giao diện API cho một "người xem" của Chế độ xem đường phố. Mỗi bản đồ chứa một ảnh toàn cảnh mặc định trong Chế độ xem đường phố mà bạn có thể truy xuất bằng cách gọi phương thức getStreetView() của bản đồ. Khi bạn thêm một chế độ điều khiển của Chế độ xem đường phố vào bản đồ bằng cách đặt tuỳ chọn streetViewControl thành true, bạn sẽ tự động kết nối chế độ điều khiển Người hình mắc áo với ảnh toàn cảnh mặc định này trong Chế độ xem đường phố.

Bạn cũng có thể tạo đối tượng StreetViewPanorama của riêng mình và thiết lập bản đồ để sử dụng đối tượng đó thay vì đối tượng mặc định, bằng cách đặt thuộc tính streetView của bản đồ một cách rõ ràng cho đối tượng đã tạo đó. Bạn có thể muốn ghi đè ảnh toàn cảnh mặc định nếu bạn muốn sửa đổi hoạt động mặc định, chẳng hạn như tự động chia sẻ lớp phủ giữa bản đồ và ảnh toàn cảnh. (Xem phần Lớp phủ trong Chế độ xem đường phố bên dưới.)

Vùng chứa Chế độ xem phố

Thay vào đó, bạn nên hiển thị StreetViewPanorama trong một phần tử DOM riêng biệt, thường là phần tử <div>. Chỉ cần truyền phần tử DOM vào trong hàm khởi tạo của StreetViewPanorama. Để hình ảnh hiển thị tối ưu, bạn nên sử dụng kích thước tối thiểu là 200 pixel x 200 pixel.

Lưu ý: Mặc dù chức năng Chế độ xem đường phố được thiết kế để sử dụng cùng với bản đồ, nhưng bạn không bắt buộc phải sử dụng chức năng này. Bạn có thể sử dụng một đối tượng độc lập của Chế độ xem đường phố mà không cần có bản đồ.

Vị trí và góc xem (POV) trong Chế độ xem đường phố

Hàm khởi tạo StreetViewPanorama cũng cho phép bạn đặt vị trí và góc nhìn của Chế độ xem đường phố bằng cách sử dụng tham số StreetViewOptions. Bạn có thể gọi setPosition()setPov() trên đối tượng sau khi tạo để thay đổi vị trí và góc nhìn của đối tượng.

Vị trí trong Chế độ xem đường phố xác định vị trí của tiêu điểm máy ảnh cho một hình ảnh, nhưng không xác định hướng của máy ảnh cho hình ảnh đó. Để làm được điều đó, đối tượng StreetViewPov sẽ xác định 2 thuộc tính:

  • heading (0 mặc định) xác định góc xoay xung quanh quỹ tích camera theo độ tương đối so với hướng bắc thực. Các tiêu đề được đo theo chiều kim đồng hồ (90 độ là đúng hướng Đông).
  • pitch (0 mặc định) xác định phương sai của góc "lên" hoặc "xuống" từ độ cao mặc định ban đầu của máy ảnh, thường (nhưng không phải lúc nào cũng) là ngang bằng phẳng. (Ví dụ: hình ảnh được chụp trên một ngọn đồi có thể sẽ có cao độ mặc định không phải là chiều ngang.) Góc cao độ được đo bằng các giá trị dương nhìn lên (tối đa +90 độ theo hướng thẳng và trực giao với cao độ mặc định) và giá trị âm nhìn xuống (đến -90 độ khi nhìn thẳng xuống và trực giao với cao độ mặc định).

Đối tượng StreetViewPov thường được dùng để xác định điểm xem của máy ảnh Chế độ xem đường phố. Bạn cũng có thể xác định góc nhìn của nhiếp ảnh gia (thường là hướng mà ô tô hoặc xe ba bánh đang nhìn) bằng phương thức StreetViewPanorama.getPhotographerPov().

Mã sau đây hiển thị bản đồ Boston với chế độ xem ban đầu của Công viên Fenway. Việc chọn Người hình mắc áo và kéo người đó đến một vị trí được hỗ trợ trên bản đồ sẽ thay đổi ảnh toàn cảnh của Chế độ xem đường phố:

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>
Xem ví dụ

Thử dùng mẫu

Theo dõi chuyển động trên thiết bị di động

Trên các thiết bị hỗ trợ các sự kiện về hướng thiết bị, API này cho phép người dùng thay đổi điểm xem của Chế độ xem đường phố dựa trên chuyển động của thiết bị. Người dùng có thể xem xung quanh bằng cách di chuyển thiết bị. Tính năng này được gọi là theo dõi chuyển động hoặc theo dõi xoay thiết bị.

Là nhà phát triển ứng dụng, bạn có thể thay đổi hành vi mặc định như sau:

  • Bật hoặc tắt chức năng theo dõi chuyển động. Theo mặc định, tính năng theo dõi chuyển động sẽ được bật trên mọi thiết bị hỗ trợ tính năng này. Mẫu sau đây vô hiệu hoá tính năng theo dõi chuyển động, nhưng vẫn hiển thị chế độ kiểm soát theo dõi chuyển động. (Lưu ý rằng người dùng có thể bật tính năng theo dõi chuyển động bằng cách nhấn vào nút điều khiển.)
    var panorama = new google.maps.StreetViewPanorama(
        document.getElementById('pano'), {
          position: {lat: 37.869260, lng: -122.254811},
          pov: {heading: 165, pitch: 0},
          motionTracking: false
        });
    
  • Ẩn hoặc hiện nút điều khiển theo dõi chuyển động. Theo mặc định, chế độ điều khiển này sẽ xuất hiện trên các thiết bị hỗ trợ tính năng theo dõi chuyển động. Người dùng có thể nhấn vào tuỳ chọn điều khiển để bật hoặc tắt tính năng theo dõi chuyển động. Lưu ý rằng tuỳ chọn điều khiển sẽ không bao giờ xuất hiện nếu thiết bị không hỗ trợ tính năng theo dõi chuyển động, bất kể giá trị của motionTrackingControl là gì.

    Mẫu sau đây vô hiệu hoá cả tính năng theo dõi chuyển động và kiểm soát theo dõi chuyển động. Trong trường hợp này, người dùng không thể bật tính năng theo dõi chuyển động:

    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
        });
    
  • Thay đổi vị trí mặc định của nút điều khiển theo dõi chuyển động. Theo mặc định, thành phần điều khiển xuất hiện gần phía dưới cùng bên phải của ảnh toàn cảnh (vị trí RIGHT_BOTTOM). Mẫu sau đây sẽ đặt vị trí của thành phần điều khiển thành dưới cùng bên trái:
    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
          }
        });
    

Để xem tính năng theo dõi chuyển động trong thực tế, hãy xem mẫu sau trên thiết bị di động (hoặc bất kỳ thiết bị nào hỗ trợ các sự kiện liên quan đến hướng thiết bị):


Xem ví dụ

Lớp phủ trong Chế độ xem phố

Đối tượng StreetViewPanorama mặc định hỗ trợ màn hình gốc của lớp phủ bản đồ. Lớp phủ thường xuất hiện ở "cấp đường phố" cố định tại các vị trí LatLng. (Ví dụ: Điểm đánh dấu sẽ xuất hiện với đuôi được neo vào mặt phẳng ngang của vị trí trong ảnh toàn cảnh của Chế độ xem đường phố.)

Hiện tại, các loại lớp phủ được hỗ trợ trên ảnh toàn cảnh của Chế độ xem đường phố chỉ có thể có Marker, InfoWindowOverlayView tuỳ chỉnh. Lớp phủ mà bạn hiển thị trên bản đồ có thể được hiển thị trên ảnh toàn cảnh của Chế độ xem đường phố bằng cách coi ảnh toàn cảnh đó là đối tượng thay thế cho đối tượng Map, gọi setMap() và truyền StreetViewPanorama làm đối số thay vì bản đồ. Tương tự, bạn có thể mở cửa sổ thông tin trong ảnh toàn cảnh của Chế độ xem đường phố bằng cách gọi open(), truyền StreetViewPanorama() thay vì bản đồ.

Ngoài ra, khi tạo bản đồ có StreetViewPanorama mặc định, mọi điểm đánh dấu được tạo trên bản đồ sẽ tự động được chia sẻ với ảnh toàn cảnh được liên kết với Chế độ xem đường phố trên bản đồ, miễn là ảnh toàn cảnh đó hiển thị được. Để truy xuất ảnh toàn cảnh mặc định của Chế độ xem đường phố, hãy gọi getStreetView() trên đối tượng Map. Lưu ý rằng nếu bạn đặt rõ ràng thuộc tính streetView của bản đồ thành StreetViewPanorama của công trình của riêng bạn, bạn sẽ ghi đè ảnh toàn cảnh mặc định.

Ví dụ sau đây cho thấy các điểm đánh dấu biểu thị nhiều vị trí xung quanh Astor Place, Thành phố New York. Chuyển màn hình sang Chế độ xem đường phố để hiển thị các điểm đánh dấu dùng chung đang hiển thị trong 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>
Xem ví dụ

Thử dùng mẫu

Sự kiện Chế độ xem phố

Khi di chuyển giữa Chế độ xem đường phố hoặc thao tác với hướng của Chế độ xem đường phố, bạn nên theo dõi một số sự kiện cho biết trạng thái của StreetViewPanorama có sự thay đổi:

  • pano_changed sẽ kích hoạt bất cứ khi nào mã ảnh toàn cảnh riêng lẻ thay đổi. Sự kiện này không đảm bảo rằng mọi dữ liệu được liên kết trong ảnh toàn cảnh (chẳng hạn như các đường liên kết) cũng đã thay đổi vào thời điểm sự kiện này được kích hoạt; sự kiện này chỉ cho biết rằng mã ảnh toàn cảnh đã thay đổi. Xin lưu ý rằng mã ảnh toàn cảnh (bạn có thể sử dụng để tham chiếu ảnh toàn cảnh này) chỉ ổn định trong phiên trình duyệt hiện tại.
  • position_changed sẽ kích hoạt bất cứ khi nào vị trí cơ bản (LatLng) của ảnh toàn cảnh thay đổi. Việc xoay ảnh toàn cảnh sẽ không kích hoạt sự kiện này. Lưu ý rằng bạn có thể thay đổi vị trí cơ bản của ảnh toàn cảnh mà không cần thay đổi mã ảnh toàn cảnh được liên kết, vì API sẽ tự động liên kết giá trị nhận dạng ảnh toàn cảnh gần nhất với vị trí của ảnh toàn cảnh.
  • pov_changed sẽ kích hoạt bất cứ khi nào StreetViewPov của Chế độ xem đường phố thay đổi. Xin lưu ý rằng sự kiện này có thể kích hoạt trong khi vị trí và mã ảnh toàn cảnh vẫn ổn định.
  • links_changed sẽ kích hoạt bất cứ khi nào các đường liên kết của Chế độ xem đường phố thay đổi. Lưu ý rằng sự kiện này có thể kích hoạt không đồng bộ sau khi có một thay đổi trong mã nhận dạng ảnh toàn cảnh được chỉ định thông qua pano_changed.
  • visible_changed sẽ kích hoạt bất cứ khi nào chế độ hiển thị của Chế độ xem đường phố thay đổi. Lưu ý rằng sự kiện này có thể kích hoạt không đồng bộ sau khi có một thay đổi trong mã nhận dạng ảnh toàn cảnh được chỉ định thông qua pano_changed.

Đoạn mã sau minh hoạ cách xử lý các sự kiện này để thu thập dữ liệu về StreetViewPanorama cơ bản:

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">&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>

    <!-- 
      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>
Xem ví dụ

Thử dùng mẫu

Các nút điều khiển trong Chế độ xem đường phố

Khi hiển thị StreetViewPanorama, theo mặc định, nhiều chế độ điều khiển sẽ xuất hiện trên ảnh toàn cảnh. Bạn có thể bật hoặc tắt các chế độ kiểm soát này bằng cách đặt các trường thích hợp trong StreetViewPanoramaOptions thành true hoặc false:

  • panControl cung cấp cách xoay ảnh toàn cảnh. Theo mặc định, chế độ điều khiển này xuất hiện dưới dạng một chế độ điều khiển la bàn và xoay tích hợp tiêu chuẩn. Bạn có thể thay đổi vị trí của thành phần điều khiển bằng cách cung cấp PanControlOptions trong trường panControlOptions.
  • zoomControl cung cấp cách thu phóng trong hình ảnh. Theo mặc định, chế độ điều khiển này sẽ xuất hiện ở gần phía dưới cùng bên phải của ảnh toàn cảnh. Bạn có thể thay đổi giao diện của chế độ điều khiển bằng cách cung cấp ZoomControlOptions trong trường zoomControlOptions.
  • addressControl cung cấp lớp phủ văn bản cho biết địa chỉ của vị trí được liên kết, đồng thời cung cấp một đường liên kết để mở vị trí đó trong Google Maps. Bạn có thể thay đổi giao diện của chế độ điều khiển bằng cách cung cấp StreetViewAddressControlOptions trong trường addressControlOptions.
  • fullscreenControl cung cấp tuỳ chọn để mở Chế độ xem đường phố ở chế độ toàn màn hình. Bạn có thể thay đổi giao diện của chế độ điều khiển bằng cách cung cấp FullscreenControlOptions trong trường fullscreenControlOptions.
  • motionTrackingControl cung cấp tuỳ chọn bật hoặc tắt tính năng theo dõi chuyển động trên thiết bị di động. Thành phần điều khiển này chỉ xuất hiện trên các thiết bị hỗ trợ các sự kiện liên quan đến hướng thiết bị. Theo mặc định, chế độ điều khiển này sẽ xuất hiện gần phía dưới cùng bên phải của ảnh toàn cảnh. Bạn có thể thay đổi vị trí của thành phần điều khiển bằng cách cung cấp MotionTrackingControlOptions. Để biết thêm thông tin, hãy xem phần theo dõi chuyển động.
  • linksControl cung cấp các mũi tên hướng dẫn trên hình ảnh để di chuyển đến hình ảnh toàn cảnh liền kề.
  • Nút Đóng cho phép người dùng đóng trình xem Chế độ xem đường phố. Bạn có thể bật hoặc tắt tuỳ chọn Đóng bằng cách đặt enableCloseButton thành true hoặc false.

Ví dụ sau đây làm thay đổi các chế độ điều khiển hiển thị trong Chế độ xem đường phố đã liên kết và xoá các đường liên kết của chế độ xem:

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>
Xem ví dụ

Thử dùng mẫu

Truy cập trực tiếp vào dữ liệu của Chế độ xem đường phố

Có thể bạn cần lập trình để xác định tính sẵn có của dữ liệu Chế độ xem phố hoặc trả về thông tin về ảnh toàn cảnh cụ thể mà không yêu cầu thao tác trực tiếp đối với bản đồ/ảnh toàn cảnh. Bạn có thể làm như vậy bằng cách sử dụng đối tượng StreetViewService. Đối tượng này cung cấp giao diện cho dữ liệu lưu trữ trong dịch vụ Chế độ xem đường phố của Google.

Yêu cầu dịch vụ Chế độ xem đường phố

Tính năng truy cập dịch vụ Chế độ xem đường phố không đồng bộ, vì API Google Maps cần thực hiện lệnh gọi đến máy chủ bên ngoài. Do đó, bạn cần truyền một phương thức callback để thực thi sau khi hoàn tất yêu cầu. Phương thức gọi lại này sẽ xử lý kết quả.

Bạn có thể bắt đầu yêu cầu đến StreetViewService bằng cách sử dụng StreetViewPanoRequest hoặc StreetViewLocationRequest.

Yêu cầu sử dụng StreetViewPanoRequest sẽ trả về dữ liệu ảnh toàn cảnh dựa trên mã tham chiếu, giúp nhận dạng duy nhất ảnh toàn cảnh đó. Lưu ý rằng các mã tham chiếu này chỉ ổn định trong toàn bộ thời gian của hình ảnh của ảnh toàn cảnh đó.

Một yêu cầu sử dụng StreetViewLocationRequest sẽ tìm kiếm dữ liệu toàn cảnh ở một vị trí cụ thể, sử dụng các tham số sau:

  • location chỉ định vị trí (vĩ độ và kinh độ) để tìm kiếm ảnh toàn cảnh.
  • preference đặt lựa chọn ưu tiên mà ảnh toàn cảnh sẽ được tìm thấy trong phạm vi bán kính: ảnh gần nhất với vị trí được cung cấp hoặc ảnh tốt nhất trong bán kính.
  • radius đặt bán kính (được chỉ định theo mét) để tìm kiếm ảnh toàn cảnh, nằm ở giữa vĩ độ và kinh độ cho trước. Giá trị mặc định là 50 khi không được cung cấp.
  • source chỉ định nguồn của ảnh toàn cảnh để tìm kiếm. Có các giá trị hợp lệ như sau:
    • default sử dụng các nguồn mặc định cho Chế độ xem đường phố; lượt tìm kiếm không chỉ giới hạn ở các nguồn cụ thể.
    • outdoor giới hạn việc tìm kiếm ở các bộ sưu tập ngoài trời. Lưu ý rằng ảnh toàn cảnh ngoài trời có thể không tồn tại cho vị trí được chỉ định.

Phản hồi của dịch vụ Chế độ xem đường phố

Hàm getPanorama() cần một hàm callback để thực thi sau khi truy xuất kết quả từ dịch vụ Chế độ xem đường phố. Hàm callback này trả về một tập hợp dữ liệu ảnh toàn cảnh trong đối tượng StreetViewPanoramaData và một mã StreetViewStatus biểu thị trạng thái của yêu cầu theo thứ tự đó.

Thông số kỹ thuật của đối tượng StreetViewPanoramaData chứa siêu dữ liệu về ảnh toàn cảnh trong Chế độ xem đường phố thuộc biểu mẫu sau:

{
  "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
  }
}

Lưu ý rằng đối tượng dữ liệu này không phải là đối tượng StreetViewPanorama. Để tạo đối tượng Chế độ xem đường phố bằng dữ liệu này, bạn cần tạo StreetViewPanorama và gọi setPano(), truyền mã nhận dạng như đã ghi chú trong trường location.pano được trả về.

status có thể trả về một trong các giá trị sau:

  • OK cho biết dịch vụ đã tìm thấy một ảnh toàn cảnh phù hợp.
  • ZERO_RESULTS cho biết dịch vụ không tìm thấy ảnh toàn cảnh phù hợp với các tiêu chí đã vượt qua.
  • UNKNOWN_ERROR cho biết không thể xử lý yêu cầu Chế độ xem đường phố, mặc dù lý do chính xác chưa được xác định.

Đoạn mã sau đây sẽ tạo một StreetViewService để phản hồi các lượt nhấp của người dùng trên một bản đồ bằng cách tạo ra các điểm đánh dấu mà khi được nhấp vào, bạn sẽ thấy một StreetViewPanorama của vị trí đó. Mã này sử dụng nội dung của StreetViewPanoramaData được trả về từ dịch vụ.

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>
Xem ví dụ

Thử dùng mẫu

Cung cấp ảnh toàn cảnh tuỳ chỉnh trong Chế độ xem đường phố

API JavaScript của Maps hỗ trợ hiển thị ảnh toàn cảnh tuỳ chỉnh trong đối tượng StreetViewPanorama. Khi sử dụng ảnh toàn cảnh tuỳ chỉnh, bạn có thể hiển thị nội thất của toà nhà, cảnh quan nhìn từ địa điểm tuyệt đẹp hoặc bất cứ thứ gì theo trí tưởng tượng của bạn. Bạn thậm chí có thể liên kết các ảnh toàn cảnh tuỳ chỉnh này với ảnh toàn cảnh hiện có của Google trong Chế độ xem đường phố.

Việc thiết lập một bộ hình ảnh toàn cảnh tuỳ chỉnh bao gồm các bước sau:

  • Tạo ảnh toàn cảnh nền cho mỗi ảnh toàn cảnh tuỳ chỉnh. Hình ảnh gốc này phải là hình ảnh có độ phân giải cao nhất mà bạn muốn phân phát hình ảnh phóng to.
  • (Không bắt buộc, nhưng nên dùng) Tạo một bộ ô toàn cảnh ở các mức thu phóng khác nhau so với hình ảnh cơ bản.
  • Tạo liên kết giữa các ảnh toàn cảnh tuỳ chỉnh.
  • (Không bắt buộc) Chỉ định ảnh toàn cảnh "mục nhập" trong hình ảnh Chế độ xem phố hiện có của Google và tùy chỉnh các đường liên kết từ/đến bộ tuỳ chỉnh thành bộ tiêu chuẩn.
  • Xác định siêu dữ liệu cho từng ảnh toàn cảnh trong đối tượng StreetViewPanoramaData.
  • Triển khai một phương thức xác định dữ liệu và hình ảnh ảnh toàn cảnh tuỳ chỉnh, đồng thời chỉ định phương thức đó làm trình xử lý tuỳ chỉnh trong đối tượng StreetViewPanorama.

Các phần sau đây sẽ giải thích quy trình này.

Tạo ảnh toàn cảnh tùy chỉnh

Mỗi ảnh toàn cảnh trong Chế độ xem đường phố là một hình ảnh hoặc một tập hợp ảnh cung cấp góc nhìn 360 độ đầy đủ từ một vị trí. Đối tượng StreetViewPanorama sử dụng những hình ảnh phù hợp với phép chiếu hình cầu toàn cảnh (Plate Carree). Phép chiếu như vậy có góc xem 360 độ theo chiều ngang (bao quanh toàn bộ) và 180 độ của chế độ xem dọc (từ thẳng lên đến thẳng xuống). Các trường khung hiển thị này sẽ tạo ra một hình ảnh có tỷ lệ khung hình là 2:1. Dưới đây là ảnh toàn cảnh bao quanh toàn bộ.

Khung cảnh toàn cảnh đường phố của thành phố

Ảnh toàn cảnh thường thu được bằng cách chụp nhiều ảnh từ một vị trí rồi ghép các ảnh đó lại với nhau bằng phần mềm ảnh toàn cảnh. (Hãy xem phần So sánh các ứng dụng ghép ảnh trên Wikipedia để biết thêm thông tin.) Những hình ảnh đó phải có chung một quỹ tích "máy ảnh" duy nhất để mỗi bức ảnh toàn cảnh được chụp từ đó. Sau đó, ảnh toàn cảnh 360 độ thu được có thể xác định một phép chiếu trên một hình cầu với hình ảnh đó được gói vào bề mặt hai chiều của hình cầu đó.

Hình cầu với ảnh toàn cảnh một con phố trên bề mặt

Việc xem ảnh toàn cảnh là một phép chiếu trên hình cầu có hệ toạ độ thẳng hàng sẽ thuận lợi khi chia hình ảnh thành các ô thẳng và phân phát hình ảnh dựa trên toạ độ ô đã tính.

Tạo các ô toàn cảnh tùy chỉnh

Chế độ xem đường phố cũng hỗ trợ nhiều mức độ chi tiết của hình ảnh thông qua việc sử dụng bộ điều khiển thu phóng, cho phép bạn phóng to và thu nhỏ từ chế độ xem mặc định. Nhìn chung, Chế độ xem đường phố cung cấp 5 mức độ phân giải thu phóng cho bất kỳ hình ảnh toàn cảnh nào. Nếu bạn phải dựa vào một ảnh toàn cảnh duy nhất để đáp ứng mọi mức thu phóng, thì một hình ảnh như vậy nhất thiết phải khá lớn và làm chậm ứng dụng đáng kể, hoặc có độ phân giải kém ở mức thu phóng cao hơn nên bạn sẽ phân phát hình ảnh có pixel kém. Tuy nhiên, thật may là chúng tôi có thể dùng một mẫu thiết kế tương tự dùng để phân phát các ô bản đồ của Google ở các mức thu phóng khác nhau để cung cấp hình ảnh có độ phân giải thích hợp cho ảnh toàn cảnh ở mỗi mức thu phóng.

Theo mặc định, khi StreetViewPanorama tải lần đầu, nó sẽ hiển thị một hình ảnh bao gồm 25% (90 độ vòng cung) chiều rộng ngang của ảnh toàn cảnh ở mức thu phóng 1. Khung hiển thị này gần tương ứng với trường nhìn thông thường của con người. Thao tác phóng to "thu nhỏ" từ khung hiển thị mặc định này về cơ bản sẽ tạo ra một vòng cung rộng hơn, còn thao tác phóng to sẽ thu hẹp trường của khung hiển thị thành một vòng cung nhỏ hơn. StreetViewPanorama tự động tính toán trường nhìn thích hợp cho mức thu phóng đã chọn, sau đó chọn hình ảnh phù hợp nhất với độ phân giải đó bằng cách chọn một tập thẻ thông tin tương đương với kích thước của trường nhìn theo chiều ngang. Các trường chế độ xem sau đây liên kết với mức thu phóng trong Chế độ xem đường phố:

Mức thu phóng của Chế độ xem phố Trường nhìn (độ)
0 180
1 (mặc định) 90
2 45
3 22,5
4 11,25

Xin lưu ý rằng kích thước của hình ảnh hiển thị trong Chế độ xem đường phố hoàn toàn phụ thuộc vào kích thước màn hình (chiều rộng) của vùng chứa Chế độ xem đường phố. Nếu bạn cung cấp một vùng chứa rộng hơn, thì dịch vụ sẽ vẫn cung cấp cùng một trường nhìn cho mọi mức thu phóng cụ thể, mặc dù dịch vụ có thể chọn các thẻ thông tin phù hợp hơn với độ phân giải đó.

Vì mỗi ảnh toàn cảnh bao gồm một phép chiếu hình cầu toàn cảnh, nên việc tạo ô ảnh toàn cảnh tương đối dễ dàng. Vì phép chiếu cung cấp hình ảnh có tỷ lệ khung hình là 2:1, nên ô có tỷ lệ 2:1 sẽ dễ sử dụng hơn, mặc dù ô vuông có thể mang lại hiệu suất tốt hơn trên bản đồ hình vuông (vì trường nhìn sẽ là hình vuông).

Đối với thẻ thông tin 2:1, một hình ảnh bao quanh toàn bộ ảnh toàn cảnh sẽ đại diện cho toàn bộ "thế giới" (hình ảnh gốc) ở mức thu phóng 0, với mỗi mức thu phóng tăng dần cung cấp các ô 4zoomLevel. (Ví dụ: ở mức thu phóng 2, toàn bộ ảnh toàn cảnh bao gồm 16 ô.) Lưu ý: Mức thu phóng trong ô xếp của Chế độ xem đường phố không khớp trực tiếp với mức thu phóng được cung cấp như được cung cấp thông qua tuỳ chọn kiểm soát Chế độ xem đường phố. Thay vào đó, mức thu phóng của Chế độ xem đường phố sẽ chọn Trường nhìn (FoV) để chọn các ô thích hợp.

Toàn cảnh một con phố thành phố chia thành các ô gạch

Thông thường, bạn sẽ muốn đặt tên cho các ô hình ảnh để có thể chọn theo phương thức lập trình. Cách đặt tên như vậy sẽ được thảo luận dưới đây trong bài viết Xử lý yêu cầu ảnh toàn cảnh tuỳ chỉnh.

Xử lý yêu cầu ảnh toàn cảnh tùy chỉnh

Để sử dụng ảnh toàn cảnh tuỳ chỉnh, hãy gọi StreetViewPanorama.registerPanoProvider(), chỉ định tên của phương thức trình cung cấp ảnh toàn cảnh tuỳ chỉnh. Phương thức trình cung cấp ảnh toàn cảnh phải trả về đối tượng StreetViewPanoramaData và có chữ ký sau:

Function(pano):StreetViewPanoramaData

StreetViewPanoramaData là một đối tượng của biểu mẫu sau:

{
  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
  ]
}

Hiển thị ảnh toàn cảnh tuỳ chỉnh như sau:

  • Đặt thuộc tính StreetViewPanoramaOptions.pano thành một giá trị tuỳ chỉnh.
  • Gọi StreetViewPanorama.registerPanoProvider() để cung cấp hàm nhà cung cấp ảnh toàn cảnh tuỳ chỉnh.
  • Triển khai hàm trình cung cấp ảnh toàn cảnh tuỳ chỉnh để xử lý giá trị pano được chỉ định.
  • Tạo một đối tượng StreetViewPanoramaData.
  • Đặt thuộc tính StreetViewTileData.getTileUrl thành tên của hàm nhà cung cấp thẻ thông tin tuỳ chỉnh mà bạn cung cấp. Ví dụ: getCustomPanoramaTileUrl.
  • Triển khai hàm trình cung cấp thẻ thông tin tuỳ chỉnh, như trong các mẫu dưới đây.
  • Trả về đối tượng StreetViewPanoramaData.

Lưu ý: Đừng đặt trực tiếp position trên StreetViewPanorama khi bạn muốn hiển thị ảnh toàn cảnh tuỳ chỉnh, vì khi bạn muốn hiển thị ảnh toàn cảnh tuỳ chỉnh, dịch vụ Chế độ xem đường phố sẽ yêu cầu hình ảnh mặc định trong Chế độ xem đường phố gần vị trí đó. Thay vào đó, hãy đặt vị trí này trong trường location.latLng của đối tượng StreetViewPanoramaData tuỳ chỉnh.

Ví dụ sau đây hiển thị ảnh toàn cảnh tuỳ chỉnh về văn phòng của Google Sydney. Xin lưu ý rằng ví dụ này không sử dụng bản đồ hoặc hình ảnh mặc định trong Chế độ xem đường phố:

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>
Xem ví dụ

Thử dùng mẫu

Trình cung cấp ảnh toàn cảnh tuỳ chỉnh sẽ trả về thẻ thông tin thích hợp, dựa trên mã nhận dạng ảnh toàn cảnh, mức thu phóng và toạ độ của ô ảnh toàn cảnh đã chuyển. Vì lựa chọn hình ảnh phụ thuộc vào các giá trị được truyền này, nên bạn nên đặt tên cho những hình ảnh có thể được chọn theo phương thức lập trình dựa trên các giá trị đã truyền đó, chẳng hạn như pano_zoom_tileX_tileY.png.

Ví dụ sau đây sẽ thêm một mũi tên khác vào hình ảnh (bên cạnh các mũi tên điều hướng mặc định của Chế độ xem đường phố) trỏ vào Google Sydney và liên kết đến hình ảnh tuỳ chỉnh:

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>
Xem ví dụ

Thử dùng mẫu