خدمة "التجوّل الافتراضي"

نظرة عامة

اختيار النظام الأساسي: Android iOS JavaScript

توفّر ميزة "التجوّل الافتراضي من Google" صورًا بانورامية بزاوية 360 درجة من الطرق المخصّصة في كامل مساحة التغطية. إنّ تغطية واجهة برمجة التطبيقات لميزة "التجوّل الافتراضي" هي نفسها تغطية تطبيق "خرائط Google" (https://maps.google.com/). وتتوفّر قائمة المدن التي تتوفّر فيها ميزة "التجوّل الافتراضي" حاليًا على الموقع الإلكتروني لتطبيق "خرائط Google".

يظهر أدناه نموذج لصورة التجوّل الافتراضي.


توفّر واجهة برمجة تطبيقات JavaScript للخرائط خدمة "التجوّل الافتراضي" للحصول على الصور المستخدمة في ميزة "التجوّل الافتراضي" ضمن "خرائط Google" ومعالجتها. تتوافق خدمة "التجوّل الافتراضي" هذه في المتصفّح بشكل مضمّن.

استخدام خريطة "التجوّل الافتراضي"

على الرغم من إمكانية استخدام "التجوّل الافتراضي" ضمن عنصر DOM المستقل، إلا أنه مفيد للغاية عند الإشارة إلى موقع جغرافي على الخريطة. يتم تفعيل "التجوّل الافتراضي" تلقائيًا على الخريطة، ويظهر عنصر تحكم الدليل في "التجوّل الافتراضي" مدمجًا في عناصر التحكم في التنقل (التكبير/التصغير والتحريك). يمكنك إخفاء عنصر التحكّم هذا ضمن MapOptions على الخريطة عن طريق ضبط streetViewControl على false. يمكنك أيضًا تغيير الموضع التلقائي لعنصر التحكّم في "التجوّل الافتراضي" من خلال ضبط السمة streetViewControlOptions.position في Map على ControlPosition جديدة.

يتيح لك عنصر التحكم في دليل "التجوّل الافتراضي" عرض الصور البانورامية للتجوّل الافتراضي داخل الخريطة مباشرةً. عندما ينقر المستخدم مع الاستمرار على رمز الدليل، يتم تعديل الخريطة لعرض المخططات الزرقاء حول الشوارع التي تم تفعيل ميزة "التجوّل الافتراضي" فيها، ما يوفّر تجربة مستخدم مشابهة لتطبيق "خرائط Google".

عندما يضع المستخدم علامة "الدليل" في أحد الشوارع، يتم تعديل الخريطة لعرض صورة "التجوّل الافتراضي" البانورامية للموقع الجغرافي المُشار إليه.

صور بانورامية لميزة "التجوّل الافتراضي"

يمكن عرض صور "التجوّل الافتراضي" من خلال استخدام العنصر StreetViewPanorama الذي يوفّر واجهة برمجة تطبيقات لمشاهد في ميزة "التجوّل الافتراضي". تحتوي كل خريطة على صورة بانورامية تلقائية للتجوّل الافتراضي، يمكنك استردادها من خلال استدعاء طريقة getStreetView() للخريطة. عند إضافة عنصر تحكّم في "التجوّل الافتراضي" إلى الخريطة من خلال ضبط خيار streetViewControl الخاص به على true، يتم تلقائيًا ربط عنصر تحكم الدليل بهذه البانوراما التلقائية في "التجوّل الافتراضي".

يمكنك أيضًا إنشاء كائن StreetViewPanorama خاصتك وضبط الخريطة على استخدامه بدلاً من السمة التلقائية، وذلك من خلال ضبط السمة streetView للخريطة بشكل صريح على ذلك الكائن الذي تم إنشاؤه. وقد ترغب في إلغاء الصورة البانورامية الافتراضية إذا كنت ترغب في تعديل السلوك الافتراضي، مثل المشاركة التلقائية للتراكبات بين الخريطة والبانوراما. (اطّلِع على تراكبات الإعلانات في "التجوّل الافتراضي" أدناه).

حاويات ميزة "التجوّل الافتراضي"

يمكنك بدلاً من ذلك عرض StreetViewPanorama داخل عنصر DOM منفصل، والذي يكون غالبًا عنصر <div>. ما عليك سوى تمرير عنصر DOM في الدالة الإنشائية StreetViewPanorama. للحصول على أفضل عرض للصور، ننصح بأن يكون الحد الأدنى للحجم 200 × 200 بكسل.

ملاحظة: على الرغم من أنّ وظيفة "التجوّل الافتراضي" مصمّمة لاستخدامها مع الخريطة، فإن هذا الاستخدام غير مطلوب. يمكنك استخدام عنصر "تجوّل افتراضي" مستقل بدون خريطة.

المواقع الجغرافية ونقاط المشاهدة في ميزة "التجوّل الافتراضي"

تسمح لك دالة إنشاء StreetViewPanorama أيضًا بتحديد موقع "التجوّل الافتراضي" ووجهة نظره باستخدام المعلَمة StreetViewOptions. يمكنك استدعاء setPosition() وsetPov() على الكائن بعد الإنشاء لتغيير موقعه الجغرافي وجهة نظره.

يحدد موقع "التجوّل الافتراضي" موضع تركيز الكاميرا لإحدى الصور، ولكنه لا يحدد اتجاه الكاميرا لتلك الصورة. لهذا الغرض، يحدّد الكائن StreetViewPov خاصيتَين:

  • تحدّد السمة 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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 callback 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>
الاطّلاع على مثال

تجربة العينة

تتبع الحركة على الأجهزة الجوّالة

على الأجهزة التي تتيح أحداث اتجاه الجهاز، توفّر واجهة برمجة التطبيقات للمستخدمين إمكانية تغيير وجهة نظر "التجوّل الافتراضي" استنادًا إلى حركة الجهاز. يمكن للمستخدمين التجول عن طريق تحريك أجهزتهم. ويُعرف ذلك باسم تتبُّع الحركة أو تتبُّع دوران الجهاز.

بصفتك مطوِّر تطبيقات، يمكنك تغيير السلوك التلقائي على النحو التالي:

  • تفعيل وظيفة تتبُّع الحركة أو إيقافها تكون ميزة تتبُّع الحركة مفعَّلة تلقائيًا على أي جهاز متوافق معها. يوقف النموذج التالي تتبُّع الحركة، ولكنه يترك عنصر التحكم في تتبُّع الحركة مرئيًا. (يُرجى العلم أنّه يمكن للمستخدم تفعيل ميزة "تتبُّع الحركة" من خلال النقر على عنصر التحكّم).
    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 تلقائي، تتم مشاركة أي علامات تم إنشاؤها على الخريطة تلقائيًا مع الصورة البانورامية المرتبطة بالخريطة على "التجوّل الافتراضي"، بشرط أن تكون البانوراما مرئية. لاسترداد الصورة البانورامية التلقائية للتجوّل الافتراضي، يمكنك استدعاء getStreetView() على الكائن Map. يُرجى العِلم أنّه إذا تم ضبط السمة 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);

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

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

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

  // We get the map's default panorama and set up some defaults.
  // Note that we don't yet set it visible.
  panorama = map.getStreetView()!; // 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);

  // Set up the markers on the map
  const cafeMarker = new google.maps.Marker({
    position: { lat: 40.730031, lng: -73.991428 },
    map,
    icon: "https://chart.apis.google.com/chart?chst=d_map_pin_icon&chld=cafe|FFFF00",
    title: "Cafe",
  });
  const bankMarker = new google.maps.Marker({
    position: { lat: 40.729681, lng: -73.991138 },
    map,
    icon: "https://chart.apis.google.com/chart?chst=d_map_pin_icon&chld=dollar|FFFF00",
    title: "Bank",
  });
  const busMarker = new google.maps.Marker({
    position: { lat: 40.729559, lng: -73.990741 },
    map,
    icon: "https://chart.apis.google.com/chart?chst=d_map_pin_icon&chld=bus|FFFF00",
    title: "Bus Stop",
  });

  // We get the map's default panorama and set up some defaults.
  // Note that we don't yet set it visible.
  panorama = map.getStreetView(); // 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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 callback 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>
الاطّلاع على مثال

تجربة العينة

أحداث "التجوّل الافتراضي"

عند التنقّل بين ميزة "التجوّل الافتراضي" أو التلاعب باتجاهه، قد تحتاج إلى مراقبة عدة أحداث تشير إلى حدوث تغييرات في حالة StreetViewPanorama:

  • ويتم تنشيط pano_changed كلما تم تغيير معرّف البانوراما الفردي. لا يضمن هذا الحدث تغيير أي بيانات مرتبطة ضمن العرض البانورامي (مثل الروابط) عند بدء هذا الحدث، ولا يشير هذا الحدث إلا إلى تغيير رقم تعريف البانوراما. وتجدُر الإشارة إلى أنّ معرّف pano (الذي يمكنك استخدامه للإشارة إلى هذه البانوراما) ثابت فقط ضمن جلسة المتصفِّح الحالية.
  • يتم تنشيط position_changed عندما يتغير الموضع الأساسي (LatLng) للصورة البانورامية. ولن يؤدي تدوير الصورة البانورامية إلى بدء هذا الحدث. وتجدُر الإشارة إلى أنّه يمكنك تغيير الموضع الأساسي لصورة بانوراما بدون تغيير معرّف البانوراما المرتبط بها، لأنّ واجهة برمجة التطبيقات ستعمل تلقائيًا على ربط أقرب معرّف بانوراما بوضع البانوراما.
  • يتم تنشيط pov_changed كلما طرأ تغيير على StreetViewPov في "التجوّل الافتراضي". تجدر الإشارة إلى أنّ هذا الحدث قد يتم تنشيطه عندما يظل الموضع ورقم تعريف البانوراما مستقرة.
  • يتم تنشيط links_changed كلما تغيّرت روابط "التجوّل الافتراضي". تجدر الإشارة إلى أنّ هذا الحدث قد يتم تنشيطه بشكلٍ غير متزامن بعد تغيير في رقم تعريف pano المُشار إليه من خلال pano_changed.
  • يتم تنشيط visible_changed كلما تغيّر مستوى رؤية "التجوّل الافتراضي". تجدر الإشارة إلى أنّ هذا الحدث قد يتم تنشيطه بشكلٍ غير متزامن بعد تغيير في رقم تعريف pano المُشار إليه من خلال pano_changed.

يوضّح الرمز التالي كيفية التعامل مع هذه الأحداث لجمع البيانات عن 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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 callback 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". يمكنك تغيير مظهر عنصر التحكّم من خلال توفير StreetViewAddressControlOptions داخل الحقل addressControlOptions.
  • يعرض 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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 callback 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 تحتاج إلى الاتصال بخادم خارجي. لهذا السبب، يجب ضبط طريقة معاودة الاتصال ليتم تنفيذها عند اكتمال الطلب. تعالج طريقة معاودة الاتصال هذه النتيجة.

يمكنك تقديم طلبات إلى StreetViewService باستخدام StreetViewPanoRequest أو StreetViewLocationRequest.

ويعرض الطلب الذي يتم باستخدام StreetViewPanoRequest بيانات بانوراما يتم منحها معرّفًا مرجعيًا يحدد الصورة البانورامية بشكل فريد. تجدر الإشارة إلى أنّ معرّفات المراجع هذه مستقرة فقط طوال عمر الصور في تلك البانوراما.

يبحث الطلب الذي يستخدم StreetViewLocationRequest عن بيانات بانوراما في موقع محدد، باستخدام المعلمات التالية:

  • تحدّد السمة location الموقع الجغرافي (خط العرض وخط الطول) للبحث عن صورة بانوراما.
  • يحدّد preference تفضيلاً للبانوراما التي يجب العثور عليها ضمن نصف القطر: أقرب موقع إلى الموقع المحدد، أو أفضل ضمن النطاق الجغرافي المحدد.
  • يضبط radius نطاقًا جغرافيًا محددًا بالمتر، حيث يمكن البحث عن بانوراما، في وسط خط العرض وخط الطول المحددَين. ويتم الإعداد تلقائيًا على 50 عند عدم توفيره.
  • تحدّد source مصدر الصور البانورامية المراد البحث عنها. في ما يلي القيم الصالحة:
    • يستخدم default المصادر التلقائية لميزة "التجوّل الافتراضي"، ولا تقتصر عمليات البحث على مصادر معيّنة فقط.
    • تقتصر عمليات البحث على outdoor على المجموعات الخارجية. لاحظ أن الصور البانورامية الخارجية قد لا تكون موجودة للموقع المحدد.

الردود على خدمة "التجوّل الافتراضي"

تحتاج الدالة getPanorama() إلى وظيفة callback ليتم تنفيذها عند استرداد إحدى النتائج من خدمة "التجوّل الافتراضي". تعرض وظيفة معاودة الاتصال هذه مجموعة من بيانات البانوراما داخل كائن StreetViewPanoramaData ورمز StreetViewStatus الذي يشير إلى حالة الطلب بهذا الترتيب.

تتضمن مواصفات الكائن StreetViewPanoramaData بيانات وصفية حول بانوراما في "التجوّل الافتراضي" بالنموذج التالي:

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

يُرجى العِلم أنّ كائن البيانات هذا ليس عنصر StreetViewPanorama في حد ذاته. لإنشاء عنصر في "التجوّل الافتراضي" باستخدام هذه البيانات، عليك إنشاء StreetViewPanorama واستدعاء setPano()، مع تمرير رقم التعريف له كما هو موضّح في حقل location.pano الذي يتم عرضه.

قد يعرض رمز 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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 callback 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>
الاطّلاع على مثال

تجربة العينة

توفير صور بانورامية مخصصة للتجوّل الافتراضي

تتيح واجهة برمجة تطبيقات JavaScript للخرائط إمكانية عرض صور بانورامية مخصّصة داخل الكائن StreetViewPanorama. باستخدام الصور البانورامية المخصّصة، يمكنك عرض التصميم الداخلي للمباني، أو المناظر من المواقع الخلّابة، أو عرض أي شيء من خيالك. ويمكنك أيضًا ربط هذه الصور البانورامية المخصّصة بصور بانورامية حالية لميزة "التجوّل الافتراضي" من Google.

يتضمن إعداد مجموعة من صور بانوراما المخصصة الخطوات التالية:

  • إنشاء صورة بانورامية أساسية لكل صورة بانورامية مخصصة. يجب أن تكون هذه الصورة الأساسية بأعلى صورة تريد عرض الصور المكبرة بها.
  • (اختياري، ولكن ننصح به) يمكنك إنشاء مجموعة من المربّعات البانورامية بمستويات تكبير مختلفة من الصورة الأساسية.
  • أنشئ روابط بين الصور البانورامية المخصصة.
  • (اختياري) عيّن صور "الدخول" البانورامية ضمن صور التجوّل الافتراضي الحالية من Google وخصِّص الروابط المؤدية إلى المجموعة المخصّصة أو إليها بالمجموعة العادية.
  • حدد البيانات الوصفية لكل صورة بانورامية داخل عنصر StreetViewPanoramaData.
  • نفِّذ طريقة تحدد بيانات وصور البانوراما المخصصة وعيِّن هذه الطريقة كمعالج مخصص لك داخل كائن StreetViewPanorama.

تشرح الأقسام التالية هذه العملية.

إنشاء صور بانورامية مخصصة

كل بانوراما في "التجوّل الافتراضي" هي صورة أو مجموعة من الصور التي توفر عرضًا كاملاً بزاوية 360 درجة من مكان واحد. يستخدم الكائن StreetViewPanorama صورًا تتوافق مع الإسقاط المتساوي المستطيلات (Plate Carrée). يشتمل هذا الإسقاط على 360 درجة من العرض الأفقي (الالتفاف الكامل) و180 درجة من العرض الرأسي (من أعلى إلى أسفل بشكل مستقيم). تؤدي حقول العرض هذه إلى الحصول على صورة بنسبة عرض إلى ارتفاع تبلغ 2:1. وفيما يلي عرض بانورامي كامل حول الدوران.

منظر بانورامي لشارع في المدينة

يتم الحصول على الصور البانورامية بشكل عام من خلال التقاط عدة صور من موضع واحد وتركيبها معًا باستخدام برنامج بانوراما. (اطّلِع على مقارنة تطبيقات تركيب الصور على Wikipedia للحصول على مزيد من المعلومات). ويجب أن تشترك هذه الصور في موقع "كاميرا" واحد يتم التقاط كل صورة من صور البانوراما منه. ويمكن عندئذٍ للبانوراما الناتجة بزاوية 360 درجة تحديد إسقاط على الكرة مع التفاف الصورة على السطح الثنائي الأبعاد للكرة.

صورة بانورامية 360 درجة مع عرض بانورامي لشارع على سطحه

من المفيد اعتبار البانوراما كإسقاط على كرة ذات نظام إحداثي مستقيم خطي عند تقسيم الصورة إلى مربّعات مستقيمة، وعرض الصور استنادًا إلى إحداثيات المربعات المحسوبة.

إنشاء مربعات بانوراما مخصصة

توفّر ميزة "التجوّل الافتراضي" أيضًا مستويات مختلفة من تفاصيل الصور من خلال استخدام عنصر التحكم في التكبير أو التصغير، ما يتيح لك التكبير والتصغير من العرض التلقائي. بشكل عام، توفر ميزة "التجوّل الافتراضي" خمسة مستويات من دقة التكبير أو التصغير لأي صورة بانورامية محددة. إذا كنت ستعتمد على صورة بانورامية واحدة لعرض جميع مستويات التكبير أو التصغير، قد تكون هذه الصورة إما كبيرة إلى حد ما ويؤدي إلى إبطاء تطبيقك بشكل كبير، أو إلى درجة دقة رديئة مع مستويات تكبير أعلى قد يؤدي إلى عرض صورة ذات تقطيع سيئ. مع ذلك، يمكننا استخدام نمط تصميم مشابه لعرض مربّعات خرائط Google بمستويات تكبير/تصغير مختلفة، وذلك لتوفير صور ذات دقة مناسبة للصور البانورامية في كل مستوى من مستويات التكبير أو التصغير.

عند تحميل StreetViewPanorama لأول مرة، يتم تلقائيًا عرض صورة بنسبة 25% (90 درجة من القوس) من العرض الأفقي للبانوراما بمستوى التكبير 1. ويتجاوب هذا العرض تقريبًا مع مجال الرؤية البشري الطبيعي. إنّ التصغير من طريقة العرض التلقائية هذا يوفر بشكل أساسي قوسًا أوسع، بينما يؤدي التكبير إلى تضييق مجال العرض إلى قوس أصغر. وتحسب StreetViewPanorama تلقائيًا مجال الرؤية المناسب لمستوى التكبير/التصغير المحدد، ثم تختار الصور الأكثر ملاءمة لهذه الدقة من خلال اختيار مجموعة تجانب تتطابق بشكل تقريبي مع أبعاد مجال العرض الأفقي. الحقول التالية لخريطة عرض الخريطة لمستويات التكبير أو التصغير في "التجوّل الافتراضي":

مستوى تكبير أو تصغير "التجوّل الافتراضي" مجال العرض (بالدرجات)
0 180
1 (افتراضي) 90
2 45
3 22.5
4 11.25

وتجدر الإشارة إلى أنّ حجم الصورة المعروضة في ميزة "التجوّل الافتراضي" يعتمد بشكل كامل على حجم شاشة (عرض) حاوية "التجوّل الافتراضي". في حال توفير حاوية أوسع نطاقًا، ستظل الخدمة توفّر حقل العرض نفسه لأي مستوى تكبير أو تصغير معيّن، إلا أنّها قد تختار مربّعات أكثر ملاءمة لهذه الدقة بدلاً من ذلك.

بما أنّ كل صورة بانورامية تتكوّن من إسقاط متساوي المستطيلات، يكون إنشاء مربّعات بانوراما أمرًا سهلاً نسبيًا. وبما أنّ الإسقاط يوفر صورة بنسبة عرض إلى ارتفاع تبلغ 2:1، يمكن بسهولة استخدام المربّعات التي تبلغ نسبتها 2:1، إلا أنّ المربّعات المربّعة قد تحقق أداءً أفضل على الخرائط المربّعة (لأن مجال الرؤية سيكون مربعًا).

بالنسبة إلى المربّعات 2:1، تمثّل الصورة الواحدة التي تشمل الصورة البانورامية بأكملها "العالم" للبانوراما بالكامل (الصورة الأساسية) عند التكبير أو التصغير المستوى 0، ويوفّر كل مستوى تكبير يتزايد 4 مربّعاتzoomLevel. (على سبيل المثال، في مستوى التكبير/التصغير 2، تتكون البانوراما بالكامل من 16 مربعًا.) ملاحظة: مستويات التكبير أو التصغير في "التجوّل الافتراضي" لا تتطابق مباشرةً مع مستويات التكبير أو التصغير كما يتم توفيرها باستخدام عنصر التحكم في "التجوّل الافتراضي"، وبدلاً من ذلك، تختار مستويات التكبير أو التصغير في عنصر التحكم في "التجوّل الافتراضي" حقل العرض (FoV)، الذي يتم من خلاله اختيار المربعات المناسبة.

منظر بانورامي لشارع مقسّم إلى أجزاء في المدينة

بشكل عام، ننصحك بتسمية أقسام الصور لكي يتم اختيارها بشكل آلي. تتم مناقشة نظام التسمية هذا أدناه في التعامل مع طلبات الصور البانورامية المخصّصة.

معالجة طلبات صور البانوراما المخصصة

لاستخدام صورة بانورامية مخصّصة، عليك استدعاء 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 عندما تريد عرض صور بانورامية مخصّصة، لأنّ هذا الموضع سيوجه خدمة "التجوّل الافتراضي" لطلب صور "التجوّل الافتراضي" التلقائية بالقرب من ذلك الموقع الجغرافي. بدلاً من ذلك، يمكنك ضبط هذا الموضع في الحقل location.latLng لكائن StreetViewPanoramaData المخصّص.

يعرض المثال التالي صورة بانورامية مخصّصة لمكتب 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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 callback 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>
الاطّلاع على مثال

تجربة العينة

يعرض موفِّر خدمة البانوراما المخصصة المربّع المناسب مع مراعاة معرّف البانوراما الذي تم تمريره ومستوى التكبير/التصغير وإحداثيات مربّع بانوراما. وبما أنّ اختيار الصور يعتمد على هذه القيم التي تم تمريرها، من المفيد تسمية الصور التي يمكن اختيارها بشكل آلي باستخدام القيم التي تم تمريرها، مثل 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",
      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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 callback 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>
الاطّلاع على مثال

تجربة العينة