خدمات «نمای خیابان»

نمای کلی

پلاتفرم را انتخاب کنید: Android iOS JavaScript

«نمای خیابان Google» نماهای تمام‌نمای ۳۶۰ درجه از جاده‌های تعیین‌شده در سراسر منطقه تحت پوشش خود ارائه می‌دهد. پوشش API «نمای خیابان» همانند پوشش برنامه Google Maps است (https://maps.google.com/). فهرست شهرهایی که درحال‌حاضر از «نمای خیابان» پشتیبانی می‌کنند در وب‌سایت Google Maps دردسترس است.

نمونه‌ای از تصویر «نمای خیابان» در زیر نشان داده شده است.


‫Maps JavaScript API سرویس «نمای خیابان» را برای دریافت و دستکاری تصاویر استفاده‌شده در «نمای خیابان» Google Maps ارائه می‌دهد. این سرویس «نمای خیابان» به‌طور بومی در مرورگر پشتیبانی می‌شود.

استفاده از نقشه «نمای خیابان»

اگرچه «نمای خیابان» را می‌توان در یک عنصر DOM مستقل استفاده کرد، اما هنگام نشان دادن مکان روی نقشه بسیار مفید است. به‌طور پیش‌فرض، «نمای خیابان» در نقشه فعال است و کنترل آدمک «نمای خیابان» به‌صورت ادغام‌شده در کنترل‌های پیمایش (بزرگ‌نمایی و حرکت افقی) ظاهر می‌شود. می‌توانید این کنترل را در MapOptions نقشه با تنظیم streetViewControl روی false پنهان کنید. همچنین می‌توانید موقعیت پیش‌فرض کنترل «نمای خیابان» را با تنظیم ویژگی Map streetViewControlOptions.position به ControlPosition جدید تغییر دهید.

کنترل آدمک «نمای خیابان» به شما امکان می‌دهد تمام‌نماهای «نمای خیابان» را مستقیماً در نقشه مشاهده کنید. وقتی کاربر روی «آدمک» کلیک می‌کند و نگه می‌دارد، نقشه به‌روز می‌شود تا خطوط آبی را در اطراف خیابان‌های فعال‌شده در «نمای خیابان» نشان دهد، و تجربه کاربری مشابهی با برنامه Google Maps ارائه دهد.

وقتی کاربر نشانگر «آدمک» را روی خیابانی رها می‌کند، نقشه به‌روز می‌شود تا نمای تمام‌نمای «نمای خیابان» را برای مکان مشخص‌شده نمایش دهد.

تمام‌نماهای «نمای خیابان»

تصاویر «نمای خیابان» ازطریق استفاده از شیء StreetViewPanorama پشتیبانی می‌شوند که میانای API را برای «نمایانگر» «نمای خیابان» ارائه می‌دهد. هر نقشه حاوی یک تمام‌نمای «نمای خیابان» پیش‌فرض است که می‌توانید با فراخوانی روش getStreetView() نقشه آن را بازیابی کنید. وقتی با تنظیم گزینه streetViewControl روی true، کنترل «نمای خیابان» را به نقشه اضافه می‌کنید، به‌طور خودکار کنترل «آدمک» را به این تمام‌نمای پیش‌فرض «نمای خیابان» متصل می‌کنید.

همچنین می‌توانید شیء StreetViewPanorama خودتان را ایجاد کنید و نقشه را طوری تنظیم کنید که به‌جای پیش‌فرض از آن استفاده کند، با تنظیم صریح ویژگی streetView نقشه روی آن شیء ساخته‌شده. اگر می‌خواهید رفتار پیش‌فرض را تغییر دهید، مثلاً هم‌رسانی خودکار هم‌پوشانی‌ها بین نقشه و تمام‌نما، شاید بخواهید تمام‌نمای پیش‌فرض را لغو کنید. (لایه‌های رویی در «نمای خیابان» را در زیر ببینید.)

Street View Containers

ممکن است بخواهید StreetViewPanorama را در عنصر DOM جداگانه‌ای نمایش دهید که معمولاً عنصر <div> است. به‌سادگی عنصر DOM را در سازنده StreetViewPanorama عبور دهید. برای نمایش بهینه تصاویر، حداقل اندازه ۲۰۰ پیکسل در ۲۰۰ پیکسل را توصیه می‌کنیم.

توجه: اگرچه عملکرد «نمای خیابان» برای استفاده همراه با نقشه طراحی شده است، اما این استفاده الزامی نیست. می‌توانید از شیء مستقل «نمای خیابان» بدون نقشه استفاده کنید.

مکان‌های «نمای خیابان» و نقطه دید (POV)

سازنده StreetViewPanorama همچنین به شما امکان می‌دهد مکان و نقطه دید «نمای خیابان» را بااستفاده از پارامتر StreetViewOptions تنظیم کنید. می‌توانید setPosition() و setPov() را روی شیء پس‌از ساخت فراخوانی کنید تا مکان و POV آن را تغییر دهید.

مکان «نمای خیابان» جای قرارگیری کانون دوربین را برای تصویر مشخص می‌کند، اما جهت دوربین را برای آن تصویر مشخص نمی‌کند. برای این منظور، شیء StreetViewPov دو ویژگی را تعریف می‌کند:

  • heading (پیش‌فرض 0) زاویه چرخش را اطراف مکان دوربین برحسب درجه نسبت به شمال واقعی تعریف می‌کند. جهت‌ها در جهت عقربه‌های ساعت اندازه‌گیری می‌شوند (۹۰ درجه شرق واقعی است).
  • pitch (پیش‌فرض 0) واریانس زاویه «بالا» یا «پایین» را از گام پیش‌فرض اولیه دوربین تعریف می‌کند که اغلب (اما نه همیشه) افقی تخت است. (برای مثال، تصویری که روی تپه گرفته شده است احتمالاً زاویه پیش‌فرضی را نشان می‌دهد که افقی نیست.) زاویه‌های گام با مقادیر مثبت برای نگاه کردن به بالا (تا ۹۰+ درجه مستقیم به بالا و متعامد با گام پیش‌فرض) و مقادیر منفی برای نگاه کردن به پایین (تا ۹۰- درجه مستقیم به پایین و متعامد با گام پیش‌فرض) اندازه‌گیری می‌شوند.

شیء StreetViewPov اغلب برای تعیین نقطه دید دوربین «نمای خیابان» استفاده می‌شود. همچنین می‌توانید زاویه دید عکاس را (معمولاً جهتی که خودرو یا سه‌چرخه به آن سمت بوده است) با روش StreetViewPanorama.getPhotographerPov() تعیین کنید.

کد زیر نقشه‌ای از بوستون را با نمای اولیه از Fenway Park نمایش می‌دهد. انتخاب آدمک و کشیدن آن به مکان پشتیبانی‌شده‌ای روی نقشه تمام‌نمای «نمای خیابان» را تغییر خواهد داد:

TypeScript

async function init(): Promise<void> {
    // Request needed libraries.
    const [{ StreetViewPanorama }] = await Promise.all([
        google.maps.importLibrary('streetView'),
        google.maps.importLibrary('maps'),
    ]);

    // Get the gmp-map element and its innerMap.
    const mapElement = document.querySelector('gmp-map')!;
    const innerMap = mapElement.innerMap;

    // Get the center of the map.
    const position = mapElement.center as google.maps.LatLng;

    // Create a new StreetViewPanorama, set its position, and attach it to the map.
    const panorama = new StreetViewPanorama(document.getElementById('pano')!, {
        position,
        pov: {
            heading: 34,
            pitch: 10,
        },
    });

    /**
     * Set the StreetViewPanorama so it displays in the pano element
     * rather than taking over the map.
     * This creates a link between the map and the panorama so that
     * the map is updated when the StreetViewPanorama position changes,
     * and the StreetViewPanorama is updated when the map changes.
     */
    innerMap.setStreetView(panorama);
}

void init();

JavaScript

async function init() {
    // Request needed libraries.
    const [{ StreetViewPanorama }] = await Promise.all([
        google.maps.importLibrary('streetView'),
        google.maps.importLibrary('maps'),
    ]);

    // Get the gmp-map element and its innerMap.
    const mapElement = document.querySelector('gmp-map');
    const innerMap = mapElement.innerMap;

    // Get the center of the map.
    const position = mapElement.center;

    // Create a new StreetViewPanorama, set its position, and attach it to the map.
    const panorama = new StreetViewPanorama(document.getElementById('pano'), {
        position,
        pov: {
            heading: 34,
            pitch: 10,
        },
    });

    /**
     * Set the StreetViewPanorama so it displays in the pano element
     * rather than taking over the map.
     * This creates a link between the map and the panorama so that
     * the map is updated when the StreetViewPanorama position changes,
     * and the StreetViewPanorama is updated when the map changes.
     */
    innerMap.setStreetView(panorama);
}

void init();

CSS

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

body {
    display: flex;
}

gmp-map,
#pano {
    flex: 1;
    height: 100%;
}

HTML

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

        <link rel="stylesheet" type="text/css" href="./style.css" />
        <script type="module" src="./index.ts"></script>
        <script>
            // prettier-ignore
            (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
                key: "GOOGLE_MAPS_API_KEY",
            });
        </script>
    </head>
    <body>
        <gmp-map
            center="42.345573,-71.098326"
            zoom="14"
            map-id="DEMO_MAP_ID"></gmp-map>
        <div id="pano"></div>
    </body>
</html>
مشاهده نمونه

امتحان کردن نمونه

ردگیری حرکت در دستگاه‌های همراه

در دستگاه‌هایی که از رویدادهای جهت‌یابی دستگاه پشتیبانی می‌کنند، این API به کاربران امکان می‌دهد نقطه دید «نمای خیابان» را براساس حرکت دستگاه تغییر دهند. کاربران می‌توانند با حرکت دادن دستگاهشان اطراف را نگاه کنند. به این کار ردیابی حرکت یا ردیابی چرخش دستگاه می‌گویند.

به‌عنوان توسعه‌دهنده نرم‌افزار، می‌توانید رفتار پیش‌فرض را به‌صورت زیر تغییر دهید:

  • عملکرد ردیابی حرکت را فعال یا غیرفعال کنید. به‌طور پیش‌فرض، ردیابی حرکت در هر دستگاهی که از آن پشتیبانی می‌کند فعال است. نمونه زیر ردگیری حرکت را غیرفعال می‌کند، اما کنترل ردگیری حرکت را نمایان می‌گذارد. (توجه داشته باشید که کاربر می‌تواند با تک‌ضرب زدن روی کنترل، ردگیری حرکت را روشن کند.)
    var panorama = new google.maps.StreetViewPanorama(
        document.getElementById('pano'), {
          position: {lat: 37.869260, lng: -122.254811},
          pov: {heading: 165, pitch: 0},
          motionTracking: false
        });
  • کنترل ردیابی حرکت را پنهان یا آشکار کنید. به‌طور پیش‌فرض، این کنترل در دستگاه‌هایی که از ردیابی حرکت پشتیبانی می‌کنند نشان داده می‌شود. کاربر می‌تواند روی کنترل ضربه بزند تا ردیابی حرکت را روشن یا خاموش کند. توجه داشته باشید که اگر دستگاه از ردیابی حرکت پشتیبانی نکند، کنترل هرگز ظاهر نخواهد شد، صرف‌نظر از مقدار motionTrackingControl.

    نمونه زیر هم ردیابی حرکت و هم کنترل ردیابی حرکت را غیرفعال می‌کند. در این مورد، کاربر نمی‌تواند ردیابی حرکت را روشن کند:

    var panorama = new google.maps.StreetViewPanorama(
        document.getElementById('pano'), {
          position: {lat: 37.869260, lng: -122.254811},
          pov: {heading: 165, pitch: 0},
          motionTracking: false,
          motionTrackingControl: false
        });
  • موقعیت پیش‌فرض کنترل ردیابی حرکت را تغییر دهید. به‌طور پیش‌فرض، کنترل نزدیک پایین سمت راست تمام‌نما (موقعیت RIGHT_BOTTOM) ظاهر می‌شود. نمونه زیر موقعیت کنترل را روی پایین سمت چپ تنظیم می‌کند:
    var panorama = new google.maps.StreetViewPanorama(
        document.getElementById('pano'), {
          position: {lat: 37.869260, lng: -122.254811},
          pov: {heading: 165, pitch: 0},
          motionTrackingControlOptions: {
            position: google.maps.ControlPosition.LEFT_BOTTOM
          }
        });

برای دیدن ردیابی حرکت در عمل، نمونه زیر را در دستگاه همراه (یا هر دستگاهی که از رویدادهای جهت‌یابی دستگاه پشتیبانی می‌کند) مشاهده کنید:


مشاهده نمونه

هم‌پوشانی‌ها در «نمای خیابان»

شیء پیش‌فرض StreetViewPanorama از نمایش بومی برافزاهای نقشه پشتیبانی می‌کند. لایه‌های رویی معمولاً در «سطح خیابان» ظاهر می‌شوند و در LatLng موقعیت لنگر می‌اندازند. (برای مثال، نشانگرها با انتهایشان که به صفحه افقی مکان در تمام‌نمای «نمای خیابان» متصل است، ظاهر می‌شوند.)

درحال‌حاضر، انواع هم‌پوشانی‌هایی که در تمام‌نماهای «نمای خیابان» پشتیبانی می‌شوند به Marker، InfoWindow، و OverlayView سفارشی محدود هستند. با درنظر گرفتن تمام‌نما به‌عنوان جایگزینی برای شیء Map، فراخوانی setMap()، و ارسال StreetViewPanorama به‌عنوان آرگومان به‌جای نقشه، می‌توان هم‌پوشانی‌هایی را که روی نقشه نمایش می‌دهید در تمام‌نمای «نمای خیابان» نمایش داد. پنجره‌های اطلاعاتی را نیز می‌توان با فراخوانی open() و ارسال StreetViewPanorama() به‌جای نقشه، در یک تمام‌نمای «نمای خیابان» باز کرد.

علاوه‌براین، هنگام ایجاد نقشه با StreetViewPanorama پیش‌فرض، هر نشانگری که روی نقشه ایجاد می‌شود به‌طور خودکار با تمام‌نمای «نمای خیابان» مرتبط با نقشه هم‌رسانی می‌شود، به‌شرطی که تمام‌نما نمایان باشد. برای بازیابی تمام‌نمای پیش‌فرض «نمای خیابان»، getStreetView() را در شیء Map فراخوانی کنید. توجه داشته باشید که اگر ویژگی streetView نقشه را صریحاً روی StreetViewPanorama ساخت خودتان تنظیم کنید، تمام‌نمای پیش‌فرض را لغو خواهید کرد.

مثال زیر نشانگرهایی را نشان می‌دهد که مکان‌های مختلف اطراف Astor Place، شهر نیویورک را نشان می‌دهند. نمایشگر را به «نمای خیابان» تغییر دهید تا نشانگرهای هم‌رسانی‌شده در StreetViewPanorama نمایش داده شود.

TypeScript

const ASSET_BASE_URL = new URL('https://maps-docs-team.web.app/samples/streetview-overlays/dist/');

let panorama: google.maps.StreetViewPanorama;
let innerMap: google.maps.Map;

async function init() {
    // Request needed libraries.
    const [{ Marker }] = await Promise.all([
        google.maps.importLibrary('marker'),
        google.maps.importLibrary('maps'),
    ]);

    // Set the location of Astor Place.
    const astorPlace = { lat: 40.729884, lng: -73.990988 };

    const mapElement = document.querySelector('gmp-map')!;

    innerMap = mapElement.innerMap;

    document
        .getElementById('streetview-toggle-button')!
        .addEventListener('click', toggleStreetView);

    const cafeIcon = document.createElement('img');
    cafeIcon.src = new URL('./cafe_icon.svg', ASSET_BASE_URL).href;

    const dollarIcon = document.createElement('img');
    dollarIcon.src = new URL('./bank_icon.svg', ASSET_BASE_URL).href;

    const busIcon = document.createElement('img');
    busIcon.src = new URL('./bus_icon.svg', ASSET_BASE_URL).href;

    // Set up the markers on the map
    new Marker({
        position: { lat: 40.730031, lng: -73.991428 },
        map: innerMap,
        title: 'Cafe',
        icon: cafeIcon.src,
    });

    new Marker({
        position: { lat: 40.729681, lng: -73.991138 },
        map: innerMap,
        title: 'Bank',
        icon: dollarIcon.src,
    });

    new Marker({
        position: { lat: 40.729559, lng: -73.990741 },
        map: innerMap,
        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 = innerMap.getStreetView()!; // TODO fix type
    panorama.setPosition(astorPlace);
    panorama.setPov({
        heading: 265,
        pitch: 0,
    });
}

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

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

void init();

JavaScript

const ASSET_BASE_URL = new URL('https://maps-docs-team.web.app/samples/streetview-overlays/dist/');

let panorama;
let innerMap;

async function init() {
    // Request needed libraries.
    const [{ Marker }] = await Promise.all([
        google.maps.importLibrary('marker'),
        google.maps.importLibrary('maps'),
    ]);

    // Set the location of Astor Place.
    const astorPlace = { lat: 40.729884, lng: -73.990988 };

    const mapElement = document.querySelector('gmp-map');

    innerMap = mapElement.innerMap;

    document
        .getElementById('streetview-toggle-button')
        .addEventListener('click', toggleStreetView);

    const cafeIcon = document.createElement('img');
    cafeIcon.src = new URL('./cafe_icon.svg', ASSET_BASE_URL).href;

    const dollarIcon = document.createElement('img');
    dollarIcon.src = new URL('./bank_icon.svg', ASSET_BASE_URL).href;

    const busIcon = document.createElement('img');
    busIcon.src = new URL('./bus_icon.svg', ASSET_BASE_URL).href;

    // Set up the markers on the map
    new Marker({
        position: { lat: 40.730031, lng: -73.991428 },
        map: innerMap,
        title: 'Cafe',
        icon: cafeIcon.src,
    });

    new Marker({
        position: { lat: 40.729681, lng: -73.991138 },
        map: innerMap,
        title: 'Bank',
        icon: dollarIcon.src,
    });

    new Marker({
        position: { lat: 40.729559, lng: -73.990741 },
        map: innerMap,
        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 = innerMap.getStreetView(); // TODO fix type
    panorama.setPosition(astorPlace);
    panorama.setPov({
        heading: 265,
        pitch: 0,
    });
}

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

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

void init();
export {};

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;
}

#streetview-toggle-button {
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 17px;
    border: none;
    background: white;
    cursor: pointer;
    border-radius: 2px;
    box-shadow: 0 1px 4px -1px rgba(0, 0, 0, 0.3);
    margin: 10px 0px 10px -2px;
    font-family: Roboto, Arial, sans-serif;
    font-size: 18px;
    font-weight: 400;
    color: rgb(86, 86, 86);
}

#streetview-toggle-button:hover {
    background: #f4f4f4;
    color: #000;
}

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>
        <script>
            // prettier-ignore
            (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
                key: "GOOGLE_MAPS_API_KEY"
            });
        </script>
    </head>
    <body>
        <gmp-map map-id="DEMO_MAP_ID" center="40.729884, -73.990988" zoom="18">
            <input
                type="button"
                value="Toggle Street View"
                id="streetview-toggle-button"
                slot="control-block-start-inline-start" />
        </gmp-map>
    </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 Maps ارائه می‌دهد. می‌توانید ظاهر کنترل را با ارائه 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 Maps API باید با سرور خارجی تماس برقرار کند. به همین دلیل، باید روش فراخوانی را برای اجرا پس‌از تکمیل درخواست ارسال کنید. این روش فراخوانی نتیجه را پردازش می‌کند.

می‌توانید درخواست‌های StreetViewService را بااستفاده از StreetViewPanoRequest یا StreetViewLocationRequest شروع کنید.

درخواست بااستفاده از StreetViewPanoRequest، داده‌های تمام‌نما را با شناسه مرجع که به‌طور منحصربه‌فرد تمام‌نما را شناسایی می‌کند برمی‌گرداند. توجه داشته باشید که این شناسه‌های مرجع فقط در طول عمر تصاویر آن تمام‌نما پایدار هستند.

درخواستی که از StreetViewLocationRequest استفاده می‌کند، بااستفاده از پارامترهای زیر، داده‌های تمام‌نما را در مکان مشخص‌شده جستجو می‌کند:

  • location مکان (طول و عرض جغرافیایی) را برای جستجوی تمام‌نما مشخص می‌کند.
  • preference اولویتی را برای اینکه کدام تمام‌نما باید در شعاع پیدا شود تنظیم می‌کند: نزدیک‌ترین تمام‌نما به مکان ارائه‌شده، یا بهترین تمام‌نما در شعاع.
  • radius شعاعی را برحسب متر تنظیم می‌کند که در آن تمام‌نما جستجو می‌شود، و مرکز آن در طول و عرض جغرافیایی داده‌شده قرار دارد. اگر ارائه نشود، به‌طور پیش‌فرض ۵۰ است.
  • ‫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>
مشاهده نمونه

ارائه تمام‌نماهای سفارشی «نمای خیابان»

‫Maps JavaScript API از نمایش تمام‌نماهای سفارشی در شیء StreetViewPanorama پشتیبانی می‌کند. بااستفاده از تمام‌نماهای سفارشی، می‌توانید فضای داخلی ساختمان‌ها، مناظر مکان‌های دیدنی، یا هر چیزی را که در تخیلتان است نمایش دهید. حتی می‌توانید این تمام‌نماهای سفارشی را به تمام‌نماهای «نمای خیابان» موجود Google پیوند دهید.

راه‌اندازی مجموعه‌ای از تصاویر تمام‌نمای سفارشی شامل مراحل زیر است:

  • برای هر سراسرنمای سفارشی، یک تصویر سراسرنمای پایه ایجاد کنید. این تصویر پایه باید بالاترین وضوح تصویری باشد که می‌خواهید تصاویر بزرگ‌نمایی‌شده را با آن ارائه دهید.
  • (اختیاری، اما توصیه می‌شود) مجموعه‌ای از کاشی‌های تمام‌نما در سطوح بزرگ‌نمایی مختلف از تصویر پایه ایجاد کنید.
  • بین تمام‌نماهای سفارشی‌تان پیوند ایجاد کنید.
  • (اختیاری) تمام‌نماهای «ورودی» را در تصاویر «نمای خیابان» موجود Google تعیین کنید و پیوندهای به/از مجموعه سفارشی به مجموعه استاندارد را سفارشی‌سازی کنید.
  • فراداده را برای هر تصویر تمام‌نما در شیء StreetViewPanoramaData تعریف کنید.
  • روشی را پیاده‌سازی کنید که داده‌ها و تصاویر تمام‌نمای سفارشی را تعیین کند و آن روش را به‌عنوان گرداننده سفارشی‌تان در شیء StreetViewPanorama تعیین کنید.

بخش‌های زیر این فرایند را توضیح می‌دهند.

ایجاد تمام‌نماهای سفارشی

هر تمام‌نمای «نمای خیابان» یک تصویر یا مجموعه‌ای از تصاویر است که نمای کامل ۳۶۰ درجه‌ای از یک مکان ارائه می‌دهد. شیء StreetViewPanorama از تصاویری استفاده می‌کند که با تصویرسازی استوانه‌ای هم‌فاصله (Plate Carrée) مطابقت دارد. چنین تصویری شامل ۳۶۰ درجه نمای افقی (یک چرخش کامل) و ۱۸۰ درجه نمای عمودی (از بالا به پایین) است. این میدان‌های دید منجر به تصویری با نسبت ابعادی ۲:۱ می‌شود. یک تمام‌نمای کامل در زیر نشان داده شده است.

نمای تمام‌نما از خیابان شهر

تصاویر تمام‌نما معمولاً با گرفتن چندین عکس از یک موقعیت و به‌هم چسباندن آن‌ها بااستفاده از نرم‌افزار تمام‌نما به‌دست می‌آیند. (برای اطلاعات بیشتر، به مقایسه برنامه‌های وصله‌دوزی عکس در ویکی‌پدیا مراجعه کنید.) این تصاویر باید دارای یک کانون «دوربین» واحد باشند که هرکدام از تصاویر تمام‌نما از آن گرفته شده است. سپس تمام‌نمای ۳۶۰ درجه حاصل می‌تواند تصویری را روی یک کره تعریف کند که تصویر روی سطح دوبعدی کره پیچیده شده است.

کره‌ای با نمای تمام‌نما از خیابانی روی سطح آن

درنظر گرفتن سراسرنما به‌عنوان تصویری روی کره با سیستم مختصات راست‌خطی هنگام تقسیم تصویر به کاشی‌های راست‌خطی و ارائه تصاویر براساس مختصات کاشی محاسبه‌شده مفید است.

ایجاد کاشی‌های تمام‌نمای سفارشی

«نمای خیابان» همچنین ازطریق استفاده از کنترل بزرگ‌نمایی، از سطوح مختلف جزئیات تصویر پشتیبانی می‌کند که به شما امکان می‌دهد از نمای پیش‌فرض بزرگ‌نمایی و کوچک‌نمایی کنید. به‌طور کلی، «نمای خیابان» پنج سطح وضوح بزرگ‌نمایی برای هر تصویر تمام‌نما ارائه می‌دهد. اگر بخواهید برای ارائه همه سطوح بزرگ‌نمایی به یک تصویر تمام‌نما تکیه کنید، چنین تصویری یا لزوماً بسیار بزرگ خواهد بود و سرعت برنامه‌تان را به‌طور قابل‌توجهی کاهش می‌دهد، یا در سطوح بزرگ‌نمایی بالاتر وضوح بسیار پایینی خواهد داشت که باعث می‌شود تصویری با پیکسل‌های ضعیف ارائه دهید. خوشبختانه، می‌توانیم از الگوی طراحی مشابهی استفاده کنیم که برای ارائه کاشی‌های نقشه Google در سطوح بزرگ‌نمایی مختلف استفاده می‌شود تا تصاویری با وضوح مناسب برای تمام‌نماها در هر سطح بزرگ‌نمایی ارائه دهیم.

وقتی StreetViewPanorama برای اولین‌بار بار می‌شود، به‌طور پیش‌فرض تصویری را نمایش می‌دهد که شامل ۲۵٪ (۹۰ درجه قوس) از عرض افقی تمام‌نما در سطح بزرگ‌نمایی ۱ است. این نما تقریباً با میدان دید طبیعی انسان مطابقت دارد. نمای پیش‌فرض را کوچک‌نمایی کنید تا اساساً قوس وسیع‌تری ارائه شود، درحالی‌که بزرگ‌نمایی کردن میدان دید را به قوس کوچک‌تری محدود می‌کند. ‫StreetViewPanorama به‌طور خودکار میدان دید مناسب را برای سطح بزرگ‌نمایی انتخاب‌شده محاسبه می‌کند و سپس با انتخاب مجموعه کاشی‌ای که تقریباً با ابعاد میدان دید افقی مطابقت دارد، مناسب‌ترین تصاویر را برای آن وضوح انتخاب می‌کند. میدان‌های دید زیر با سطوح بزرگ‌نمایی «نمای خیابان» مطابقت دارند:

سطح بزرگ‌نمایی «نمای خیابان» میدان دید (درجه)
0 ۱۸۰
۱ (پیش‌فرض) ۹۰
2 ۴۵
3 ۲۲٫۵
4 ‫۱۱.۲۵

توجه داشته باشید که اندازه تصویر نشان‌داده‌شده در «نمای خیابان» کاملاً به اندازه صفحه‌نمایش (عرض) محفظه «نمای خیابان» بستگی دارد. اگر محفظه عریض‌تری ارائه دهید، سرویس همچنان همان میدان دید را برای هر سطح بزرگ‌نمایی ارائه خواهد داد، هرچند ممکن است کاشی‌های مناسب‌تری برای آن وضوح انتخاب کند.

چون هر تمام‌نما از یک تصویر استوانه‌ای هم‌زاویه تشکیل شده است، ایجاد کاشی‌های تمام‌نما نسبتاً آسان است. ازآنجایی‌که تصویر پیش‌بینی‌شده دارای نسبت ابعادی ۲:۱ است، استفاده از کاشی‌هایی با نسبت ۲:۱ آسان‌تر است، اگرچه کاشی‌های مربعی ممکن است عملکرد بهتری در نقشه‌های مربعی ارائه دهند (زیرا میدان دید مربعی خواهد بود).

برای کاشی‌های ۲:۱، یک تصویر واحد که کل تمام‌نما را دربرمی‌گیرد، کل «جهان» تمام‌نما (تصویر پایه) را در سطح بزرگ‌نمایی ۰ نشان می‌دهد، و هر سطح بزرگ‌نمایی افزایشی، zoomLevel کاشی ارائه می‌دهد. (مثلاً در سطح بزرگ‌نمایی ۲، کل تمام‌نما از ۱۶ کاشی تشکیل شده است.) توجه: سطوح بزرگ‌نمایی در کاشی‌کاری «نمای خیابان» مستقیماً با سطوح بزرگ‌نمایی ارائه‌شده بااستفاده از کنترل «نمای خیابان» مطابقت ندارند؛ درعوض، سطوح بزرگ‌نمایی کنترل «نمای خیابان» یک «میدان دید» (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

async function init(): Promise<void> {
    // Request needed libraries.
    const [{ StreetViewPanorama }, { Size }] = await Promise.all([
        google.maps.importLibrary('streetView'),
        google.maps.importLibrary('core'),
    ]);

    // Construct the appropriate StreetViewPanoramaData given
    // the passed pano IDs.
    function getCustomPanorama(
        pano: string
    ): google.maps.StreetViewPanoramaData | null {
        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 Size(1024, 512),
                    worldSize: new Size(2048, 1024),
                    // The heading in degrees at the origin of the panorama
                    // tile set.
                    centerHeading: 105,
                    getTileUrl: getCustomPanoramaTileUrl,
                },
            };
        }
        return null;
    }

    // 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 StreetViewPanorama(document.getElementById('map')!, {
        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-${String(zoom)}-${String(tileX)}-${String(tileY)}.jpg`;
}

void init();

JavaScript

async function init() {
    // Request needed libraries.
    const [{ StreetViewPanorama }, { Size }] = await Promise.all([
        google.maps.importLibrary('streetView'),
        google.maps.importLibrary('core'),
    ]);

    // 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 Size(1024, 512),
                    worldSize: new Size(2048, 1024),
                    // The heading in degrees at the origin of the panorama
                    // tile set.
                    centerHeading: 105,
                    getTileUrl: getCustomPanoramaTileUrl,
                },
            };
        }
        return null;
    }

    // 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 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-${String(zoom)}-${String(tileX)}-${String(tileY)}.jpg`;
}

void init();

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>
        <script>
            // prettier-ignore
            (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
                key: "GOOGLE_MAPS_API_KEY"
            });
        </script>
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>
مشاهده نمونه

امتحان کردن نمونه

ارائه‌دهنده تمام‌نمای سفارشی کاشی مناسب را با شناسه تمام‌نما، سطح بزرگ‌نمایی، و مختصات کاشی تمام‌نمای ارائه‌شده برمی‌گرداند. ازآنجایی‌که انتخاب تصویر به این مقادیر ارسال‌شده بستگی دارد، مفید است که نام تصاویری را که می‌توانند به‌صورت برنامه‌نویسی‌شده با توجه به آن مقادیر ارسال‌شده انتخاب شوند، مانند pano_zoom_tileX_tileY.png، نام‌گذاری کنید.

مثال زیر پیکان دیگری را به تصویر اضافه می‌کند، علاوه‌بر پیکان‌های پیمایش پیش‌فرض «نمای خیابان»، که به Google Sydney اشاره می‌کند و به تصاویر سفارشی پیوند می‌دهد:

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>
مشاهده نمونه