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

نظرة عامة

اختيار النظام الأساسي: 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() لتحديد منظور المصوِّر، أي الاتجاه الذي تتجه إليه السيارة أو الدراجة الثلاثية العجلات عادةً.

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

TypeScript

function initialize() {
  const fenway = { lat: 42.345573, lng: -71.098326 };
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      center: fenway,
      zoom: 14,
    }
  );
  const panorama = new google.maps.StreetViewPanorama(
    document.getElementById("pano") as HTMLElement,
    {
      position: fenway,
      pov: {
        heading: 34,
        pitch: 10,
      },
    }
  );

  map.setStreetView(panorama);
}

declare global {
  interface Window {
    initialize: () => void;
  }
}
window.initialize = initialize;

JavaScript

function initialize() {
  const fenway = { lat: 42.345573, lng: -71.098326 };
  const map = new google.maps.Map(document.getElementById("map"), {
    center: fenway,
    zoom: 14,
  });
  const panorama = new google.maps.StreetViewPanorama(
    document.getElementById("pano"),
    {
      position: fenway,
      pov: {
        heading: 34,
        pitch: 10,
      },
    },
  );

  map.setStreetView(panorama);
}

window.initialize = initialize;

CSS

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#map,
#pano {
  float: left;
  height: 100%;
  width: 50%;
}

HTML

<html>
  <head>
    <title>Street View split-map-panes</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map"></div>
    <div id="pano"></div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initialize&v=weekly"
      defer
    ></script>
  </body>
</html>
الاطّلاع على مثال

تجربة "عيّنة"

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

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

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

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

  const cafeIcon = document.createElement("img");
  cafeIcon.src = "https://developers.google.com/maps/documentation/javascript/examples/full/images/cafe_icon.svg";

  const dollarIcon = document.createElement("img");
  dollarIcon.src = "https://developers.google.com/maps/documentation/javascript/examples/full/images/bank_icon.svg";

  const busIcon = document.createElement("img");
  busIcon.src = "https://developers.google.com/maps/documentation/javascript/examples/full/images/bus_icon.svg";


  // Set up the markers on the map
  const cafeMarker = new google.maps.Marker({
    position: { lat: 40.730031, lng: -73.991428 },
    map,
    title: "Cafe",
    icon: cafeIcon.src,
  });

  const bankMarker = new google.maps.Marker({
    position: { lat: 40.729681, lng: -73.991138 },
    map,
    title: "Bank",
    icon: dollarIcon.src,
  });

  const busMarker = new google.maps.Marker({
    position: { lat: 40.729559, lng: -73.990741 },
    map,
    title: "Bus Stop",
    icon: busIcon.src,
  });

  // We get the map's default panorama and set up some defaults.
  // Note that we don't yet set it visible.
  panorama = map.getStreetView()!; // TODO fix type
  panorama.setPosition(astorPlace);
  panorama.setPov(
    /** @type {google.maps.StreetViewPov} */ {
      heading: 265,
      pitch: 0,
    }
  );
}

function toggleStreetView(): void {
  const toggle = panorama.getVisible();

  if (toggle == false) {
    panorama.setVisible(true);
  } else {
    panorama.setVisible(false);
  }
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

let panorama;

function initMap() {
  const astorPlace = { lat: 40.729884, lng: -73.990988 };
  // Set up the map
  const map = new google.maps.Map(document.getElementById("map"), {
    center: astorPlace,
    zoom: 18,
    streetViewControl: false,
  });

  document.getElementById("toggle").addEventListener("click", toggleStreetView);

  const cafeIcon = document.createElement("img");

  cafeIcon.src =
    "https://developers.google.com/maps/documentation/javascript/examples/full/images/cafe_icon.svg";

  const dollarIcon = document.createElement("img");

  dollarIcon.src =
    "https://developers.google.com/maps/documentation/javascript/examples/full/images/bank_icon.svg";

  const busIcon = document.createElement("img");

  busIcon.src =
    "https://developers.google.com/maps/documentation/javascript/examples/full/images/bus_icon.svg";

  // Set up the markers on the map
  const cafeMarker = new google.maps.Marker({
    position: { lat: 40.730031, lng: -73.991428 },
    map,
    title: "Cafe",
    icon: cafeIcon.src,
  });
  const bankMarker = new google.maps.Marker({
    position: { lat: 40.729681, lng: -73.991138 },
    map,
    title: "Bank",
    icon: dollarIcon.src,
  });
  const busMarker = new google.maps.Marker({
    position: { lat: 40.729559, lng: -73.990741 },
    map,
    title: "Bus Stop",
    icon: busIcon.src,
  });

  // We get the map's default panorama and set up some defaults.
  // Note that we don't yet set it visible.
  panorama = map.getStreetView(); // TODO fix type
  panorama.setPosition(astorPlace);
  panorama.setPov(
    /** @type {google.maps.StreetViewPov} */ {
      heading: 265,
      pitch: 0,
    },
  );
}

function toggleStreetView() {
  const toggle = panorama.getVisible();

  if (toggle == false) {
    panorama.setVisible(true);
  } else {
    panorama.setVisible(false);
  }
}

window.initMap = initMap;

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#floating-panel {
  position: absolute;
  top: 10px;
  left: 25%;
  z-index: 5;
  background-color: #fff;
  padding: 5px;
  border: 1px solid #999;
  text-align: center;
  font-family: "Roboto", "sans-serif";
  line-height: 30px;
  padding-left: 10px;
}

#floating-panel {
  margin-left: -100px;
}

HTML

<html>
  <head>
    <title>Overlays Within Street View</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="floating-panel">
      <input type="button" value="Toggle Street View" id="toggle" />
    </div>
    <div id="map"></div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&libraries=marker&v=weekly"
      defer
    ></script>
  </body>
</html>
الاطّلاع على مثال

تجربة "عيّنة"

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

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

  • يتم تنشيط pano_changed كلما تم تغيير معرّف الصورة البانورامية الفردي. لا يضمن هذا الحدث تغيير أي بيانات مرتبطة في البانوراما (مثل الروابط) عند بدء هذا الحدث، ويشير هذا الحدث فقط إلى حدوث تغيير في رقم تعريف الصورة البانورامية. تجدر الإشارة إلى أنّ معرّف البانوراما (الذي يمكنك استخدامه للإشارة إلى هذه البانوراما) ثابت فقط ضمن جلسة المتصفّح الحالية.
  • يتم تنشيط 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>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="pano"></div>
    <div id="floating-panel">
      <table>
        <tr>
          <td><b>Position</b></td>
          <td id="position-cell">&nbsp;</td>
        </tr>
        <tr>
          <td><b>POV Heading</b></td>
          <td id="heading-cell">270</td>
        </tr>
        <tr>
          <td><b>POV Pitch</b></td>
          <td id="pitch-cell">0.0</td>
        </tr>
        <tr>
          <td><b>Pano ID</b></td>
          <td id="pano-cell">&nbsp;</td>
        </tr>
        <table id="links_table"></table>
      </table>
    </div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initPano&v=weekly"
      defer
    ></script>
  </body>
</html>
الاطّلاع على مثال

تجربة "عيّنة"

عناصر التحكّم في "التجوّل الافتراضي"

عند عرض 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>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map"></div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initPano&v=weekly"
      defer
    ></script>
  </body>
</html>
الاطّلاع على مثال

تجربة "عيّنة"

الوصول إلى بيانات التجوّل الافتراضي مباشرةً

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

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

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

يمكنك بدء طلبات إلى 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>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map" style="width: 45%; height: 100%; float: left"></div>
    <div id="pano" style="width: 45%; height: 100%; float: left"></div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly"
      defer
    ></script>
  </body>
</html>
الاطّلاع على مثال

تجربة "عيّنة"

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

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

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

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

توضح الأقسام التالية هذه العملية.

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

كل بانوراما "التجوّل الافتراضي" هي صورة أو مجموعة من الصور التي تقدّم عرضًا كاملاً بزاوية 360 درجة من موقع واحد. يستخدم الكائن StreetViewPanorama صورًا تتوافق مع إسقاط متساوي المستطيلات (اللوحة كاريه). يتضمّن هذا الإسقاط بزاوية 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>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map"></div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initPano&v=weekly"
      defer
    ></script>
  </body>
</html>
الاطّلاع على مثال

تجربة "عيّنة"

يعرض موفِّر البانوراما المخصّص المربّع المناسب وفقًا لمعرّف البانوراما الذي تم تمريره ومستوى التكبير/التصغير وإحداثيات مربّع البانوراما. وبما أنّ اختيار الصور يعتمد على هذه القيم التي تم تمريرها، من المفيد تسمية الصور التي يمكن اختيارها آليًا استنادًا إلى القيم التي تم تمريرها، مثل pano_zoom_tileX_tileY.png.

يضيف المثال التالي سهمًا آخر إلى الصورة، بالإضافة إلى أسهم التنقل التلقائية في "التجوّل الافتراضي"، والذي يشير إلى Google سيدني ويربط بالصور المخصّصة:

TypeScript

let panorama: google.maps.StreetViewPanorama;

// StreetViewPanoramaData of a panorama just outside the Google Sydney office.
let outsideGoogle: google.maps.StreetViewPanoramaData;

// StreetViewPanoramaData for a custom panorama: the Google Sydney reception.
function getReceptionPanoramaData(): google.maps.StreetViewPanoramaData {
  return {
    location: {
      pano: "reception", // The ID for this custom panorama.
      description: "Google Sydney - Reception",
      latLng: new google.maps.LatLng(-33.86684, 151.19583),
    },
    links: [
      {
        heading: 195,
        description: "Exit",
        pano: (outsideGoogle.location as google.maps.StreetViewLocation).pano,
      },
    ],
    copyright: "Imagery (c) 2010 Google",
    tiles: {
      tileSize: new google.maps.Size(1024, 512),
      worldSize: new google.maps.Size(2048, 1024),
      centerHeading: 105,
      getTileUrl: function (
        pano: string,
        zoom: number,
        tileX: number,
        tileY: number
      ): string {
        return (
          "https://developers.google.com/maps/documentation/javascript/examples/full/images/" +
          "panoReception1024-" +
          zoom +
          "-" +
          tileX +
          "-" +
          tileY +
          ".jpg"
        );
      },
    },
  };
}

function initPanorama() {
  panorama = new google.maps.StreetViewPanorama(
    document.getElementById("street-view") as HTMLElement,
    { pano: (outsideGoogle.location as google.maps.StreetViewLocation).pano }
  );
  // Register a provider for the custom panorama.
  panorama.registerPanoProvider(
    (pano: string): google.maps.StreetViewPanoramaData => {
      if (pano === "reception") {
        return getReceptionPanoramaData();
      }
      // @ts-ignore TODO fix typings
      return null;
    }
  );

  // Add a link to our custom panorama from outside the Google Sydney office.
  panorama.addListener("links_changed", () => {
    if (
      panorama.getPano() ===
      (outsideGoogle.location as google.maps.StreetViewLocation).pano
    ) {
      panorama.getLinks().push({
        description: "Google Sydney",
        heading: 25,
        pano: "reception",
      });
    }
  });
}

function initMap(): void {
  // Use the Street View service to find a pano ID on Pirrama Rd, outside the
  // Google office.
  new google.maps.StreetViewService()
    .getPanorama({ location: { lat: -33.867386, lng: 151.195767 } })
    .then(({ data }: google.maps.StreetViewResponse) => {
      outsideGoogle = data;
      initPanorama();
    });
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

let panorama;
// StreetViewPanoramaData of a panorama just outside the Google Sydney office.
let outsideGoogle;

// StreetViewPanoramaData for a custom panorama: the Google Sydney reception.
function getReceptionPanoramaData() {
  return {
    location: {
      pano: "reception", // The ID for this custom panorama.
      description: "Google Sydney - Reception",
      latLng: new google.maps.LatLng(-33.86684, 151.19583),
    },
    links: [
      {
        heading: 195,
        description: "Exit",
        pano: outsideGoogle.location.pano,
      },
    ],
    copyright: "Imagery (c) 2010 Google",
    tiles: {
      tileSize: new google.maps.Size(1024, 512),
      worldSize: new google.maps.Size(2048, 1024),
      centerHeading: 105,
      getTileUrl: function (pano, zoom, tileX, tileY) {
        return (
          "https://developers.google.com/maps/documentation/javascript/examples/full/images/" +
          "panoReception1024-" +
          zoom +
          "-" +
          tileX +
          "-" +
          tileY +
          ".jpg"
        );
      },
    },
  };
}

function initPanorama() {
  panorama = new google.maps.StreetViewPanorama(
    document.getElementById("street-view"),
    { pano: outsideGoogle.location.pano },
  );
  // Register a provider for the custom panorama.
  panorama.registerPanoProvider((pano) => {
    if (pano === "reception") {
      return getReceptionPanoramaData();
    }
    // @ts-ignore TODO fix typings
    return null;
  });
  // Add a link to our custom panorama from outside the Google Sydney office.
  panorama.addListener("links_changed", () => {
    if (panorama.getPano() === outsideGoogle.location.pano) {
      panorama.getLinks().push({
        description: "Google Sydney",
        heading: 25,
        pano: "reception",
      });
    }
  });
}

function initMap() {
  // Use the Street View service to find a pano ID on Pirrama Rd, outside the
  // Google office.
  new google.maps.StreetViewService()
    .getPanorama({ location: { lat: -33.867386, lng: 151.195767 } })
    .then(({ data }) => {
      outsideGoogle = data;
      initPanorama();
    });
}

window.initMap = initMap;

CSS

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#street-view {
  height: 100%;
}

HTML

<html>
  <head>
    <title>Custom Street View Panorama Tiles</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="street-view"></div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly"
      defer
    ></script>
  </body>
</html>
الاطّلاع على مثال

تجربة "عيّنة"