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

تنظيم صفحاتك في مجموعات يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.

نظرة عامة

اختيار نظام أساسي: 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 بكسل كحد أدنى.

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

مواقع التجوّل الافتراضي ونقطة المشاهدة (POV)

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

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

  • تحدِّد heading (القيمة التلقائية 0) زاوية الدوران حول موضع الكاميرا بدرجات نسبية من الشمال الصحيح. يتم قياس العناوين باتجاه عقارب الساعة (90 درجة صحيحة شرقًا).
  • تحدّد pitch (القيمة التلقائية 0) تباين الزاوية "لأعلى" أو "لأسفل" من درجة الصوت التلقائية الأولية للكاميرا، والتي تكون غالبًا (ولكن ليس دائمًا) مسطّحة أفقية. (على سبيل المثال، ستُظهر الصورة الملتقطة على تلة حدّة صوت تلقائية غير أفقية.) ويتم قياس زوايا العرض التقديمي المخطّط وقِيَم النقاط الإيجابية من خلال النظر إلى الأعلى (تصل إلى أعلى من 90 درجة بشكل عمودي ومستوفٍ إلى درجة الصوت التلقائية) والقيم السالبة المتّجهة للأسفل (من حاصل إلى -90 درجة أفقيًا ومستوفًى وصولاً إلى درجة الصوت التلقائية).

غالبًا ما يتم استخدام الكائن StreetViewPov لتحديد وجهة نظر كاميرا "التجوّل الافتراضي". يمكنك أيضًا تحديد وجهة نظر المصوّر، أي الاتجاه الذي تواجهه السيارة أو الدراجة ثلاثية العجلات عادةً، باستخدام طريقة StreetViewPanorama.getPhotographerPov().

يعرض الرمز التالي خريطة لمدينة بوسطن تعرض عرضًا مبدئيًا لحديقة Fenway Park. يؤدي تحديد الدليل وسحبه إلى موقع معتمد على الخريطة إلى تغيير الصورة البانورامية للتجوّل الافتراضي:

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
     with https://www.npmjs.com/package/@googlemaps/js-api-loader.
    -->
    <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
     with https://www.npmjs.com/package/@googlemaps/js-api-loader.
    -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly"
      defer
    ></script>
  </body>
</html>
عرض مثال

تجربة النموذج

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

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

  • يتم تنشيط pano_changed كلما تغيّر رقم تعريف البانوراما الفردي. لا يضمن هذا الحدث أن أي بيانات مرتبطة في البانوراما (مثل الروابط) قد تغيّرت أيضًا بحلول وقت تشغيل هذه الفعالية، ويشير هذا الحدث فقط إلى أن رقم تعريف البانوراما قد تغيّر. لاحظ أن رقم تعريف البانوراما (الذي يمكنك استخدامه للإشارة إلى هذه البانوراما) ثابت فقط خلال جلسة المتصفح الحالية.
  • يتم تنشيط position_changed كلما طرأ تغيير على الموضع الأساسي (LatLng) للصورة البانورامية. لن يؤدي تدوير صورة بانورامية إلى تشغيل هذا الحدث. تجدر الإشارة إلى أنه يمكنك تغيير الموضع الأساسي للصورة البانورامية بدون تغيير معرّف البانوراما المرتبط، نظرًا لأن واجهة برمجة التطبيقات ستربط تلقائيًا أقرب رقم تعريف للبانوراما إلى موضع البانوراما.
  • يتم تنشيط pov_changed كلما طرأ تغيير على StreetViewPov في التجوّل الافتراضي. يُرجى العِلم أنّ هذا الحدث قد يتم إطلاقه بينما يظل الموضع ورقم تعريف البانوراما ثابتَين.
  • يتم تنشيط links_changed عند تغيير روابط التجوّل الافتراضي. تجدر الإشارة إلى أن هذا الحدث قد يتم إطلاقه بشكل غير متزامن بعد تغيير في رقم تعريف البانوراما المشار إليه في pano_changed.
  • يتم تنشيط visible_changed كلما طرأ تغيير على مستوى رؤية التجوّل الافتراضي. تجدر الإشارة إلى أن هذا الحدث قد يتم إطلاقه بشكل غير متزامن بعد تغيير في رقم تعريف البانوراما المشار إليه في 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
     with https://www.npmjs.com/package/@googlemaps/js-api-loader.
    -->
    <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
     with https://www.npmjs.com/package/@googlemaps/js-api-loader.
    -->
    <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() إلى تنفيذ وظيفة معاودة الاتصال عند استرجاع نتيجة من خدمة "التجوّل الافتراضي". تعرض دالة رد الاتصال هذه مجموعة من بيانات البانوراما ضمن كائن 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
     with https://www.npmjs.com/package/@googlemaps/js-api-loader.
    -->
    <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. يتم عرض بانوراما كاملة ملتفة أدناه.

ويتم الحصول على صور البانوراما عمومًا عن طريق التقاط صور متعددة من موضع واحد وتركيبها معًا باستخدام برامج الصور البانورامية. (يمكنك الاطّلاع على مقارنة بين تطبيقات تركيب الصور على "ويكيبيديا" لمزيد من المعلومات). ويجب أن تشارك هذه الصور مكانًا واحدًا للكاميرا، يتم من خلاله التقاط كل صورة من الصور البانورامية. ويمكن حينئذٍ للصورة البانورامية الناتجة بزاوية 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
     with https://www.npmjs.com/package/@googlemaps/js-api-loader.
    -->
    <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
     with https://www.npmjs.com/package/@googlemaps/js-api-loader.
    -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly"
      defer
    ></script>
  </body>
</html>
عرض مثال

تجربة النموذج