عکس مکان

توسعه‌دهندگان منطقه اقتصادی اروپا (EEA)

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

مشاهده کد منبع نمونه کامل

این نسخه نمایشی عکسی تصادفی از یکی از پنج شهر را نمایش می‌دهد و ارجاع‌های لازم به نویسنده را در گوشه پایین سمت چپ عکس نشان می‌دهد.

TypeScript

const CITIES = [
    { name: 'New York', id: 'ChIJOwg_06VPwokRYv534QaPC8g' },
    { name: 'London', id: 'ChIJdd4hrwug2EcRmSrV3Vo6llI' },
    { name: 'Paris', id: 'ChIJD7fiBh9u5kcRYJSMaMOCCwQ' },
    { name: 'Tokyo', id: 'ChIJ51cu8IcbXWARiRtXIothAS4' },
    { name: 'Rome', id: 'ChIJu46S-ZZhLxMROG5lkwZ3D7k' },
];

async function init() {
    const { Place } = await google.maps.importLibrary('places');

    const heading = document.getElementById('heading')!;
    const summary = document.getElementById('summary')!;
    const expandedImageDiv = document.getElementById('expanded-image')!;
    const randomizeBtn = document.getElementById(
        'randomize-btn'
    ) as HTMLButtonElement;

    async function showRandomCityPhoto() {
        randomizeBtn.disabled = true;

        // Pick a random city
        const city = CITIES[Math.floor(Math.random() * CITIES.length)];

        try {
            const place = new Place({ id: city.id });
            await place.fetchFields({
                fields: ['displayName', 'photos', 'editorialSummary'],
            });

            heading.textContent = place.displayName ?? city.name;
            summary.textContent = place.editorialSummary ?? '';
            expandedImageDiv.innerHTML = '';

            if (place.photos && place.photos.length > 0) {
                // Pick one of the first 10 photos
                const maxPhotos = Math.min(10, place.photos.length);
                const randomIndex = Math.floor(Math.random() * maxPhotos);
                const photo = place.photos[randomIndex];

                const img = document.createElement('img');
                img.alt = `Photo of ${place.displayName ?? city.name}`;
                img.src = photo.getURI({ maxHeight: 800 });
                expandedImageDiv.appendChild(img);

                if (photo.authorAttributions.length) {
                    expandedImageDiv.appendChild(
                        createAttribution(photo.authorAttributions[0])
                    );
                }
            } else {
                expandedImageDiv.textContent =
                    'No photos available for this location.';
            }
        } catch (error) {
            console.error('Failed to fetch place details:', error);
            summary.textContent = 'Failed to load data.';
        }

        // Re-enable button after 2 seconds
        setTimeout(() => {
            randomizeBtn.disabled = false;
        }, 2000);
    }

    // Helper function to create attribution DIV.
    function createAttribution(
        attribution: google.maps.places.AuthorAttribution
    ) {
        const attributionLabel = document.createElement('a');
        attributionLabel.classList.add('attribution-label');
        attributionLabel.textContent = attribution.displayName;
        attributionLabel.href = attribution.uri!;
        attributionLabel.target = '_blank';
        attributionLabel.rel = 'noopener noreferrer';
        return attributionLabel;
    }

    randomizeBtn.addEventListener('click', () => void showRandomCityPhoto());

    // Initial load
    void showRandomCityPhoto();
}

void init();

JavaScript

const CITIES = [
    { name: 'New York', id: 'ChIJOwg_06VPwokRYv534QaPC8g' },
    { name: 'London', id: 'ChIJdd4hrwug2EcRmSrV3Vo6llI' },
    { name: 'Paris', id: 'ChIJD7fiBh9u5kcRYJSMaMOCCwQ' },
    { name: 'Tokyo', id: 'ChIJ51cu8IcbXWARiRtXIothAS4' },
    { name: 'Rome', id: 'ChIJu46S-ZZhLxMROG5lkwZ3D7k' },
];

async function init() {
    const { Place } = await google.maps.importLibrary('places');

    const heading = document.getElementById('heading');
    const summary = document.getElementById('summary');
    const expandedImageDiv = document.getElementById('expanded-image');
    const randomizeBtn = document.getElementById('randomize-btn');

    async function showRandomCityPhoto() {
        randomizeBtn.disabled = true;

        // Pick a random city
        const city = CITIES[Math.floor(Math.random() * CITIES.length)];

        try {
            const place = new Place({ id: city.id });
            await place.fetchFields({
                fields: ['displayName', 'photos', 'editorialSummary'],
            });

            heading.textContent = place.displayName ?? city.name;
            summary.textContent = place.editorialSummary ?? '';
            expandedImageDiv.innerHTML = '';

            if (place.photos && place.photos.length > 0) {
                // Pick one of the first 10 photos
                const maxPhotos = Math.min(10, place.photos.length);
                const randomIndex = Math.floor(Math.random() * maxPhotos);
                const photo = place.photos[randomIndex];

                const img = document.createElement('img');
                img.alt = `Photo of ${place.displayName ?? city.name}`;
                img.src = photo.getURI({ maxHeight: 800 });
                expandedImageDiv.appendChild(img);

                if (photo.authorAttributions.length) {
                    expandedImageDiv.appendChild(
                        createAttribution(photo.authorAttributions[0])
                    );
                }
            } else {
                expandedImageDiv.textContent =
                    'No photos available for this location.';
            }
        } catch (error) {
            console.error('Failed to fetch place details:', error);
            summary.textContent = 'Failed to load data.';
        }

        // Re-enable button after 2 seconds
        setTimeout(() => {
            randomizeBtn.disabled = false;
        }, 2000);
    }

    // Helper function to create attribution DIV.
    function createAttribution(attribution) {
        const attributionLabel = document.createElement('a');
        attributionLabel.classList.add('attribution-label');
        attributionLabel.textContent = attribution.displayName;
        attributionLabel.href = attribution.uri;
        attributionLabel.target = '_blank';
        attributionLabel.rel = 'noopener noreferrer';
        return attributionLabel;
    }

    randomizeBtn.addEventListener('click', () => void showRandomCityPhoto());

    // Initial load
    void showRandomCityPhoto();
}

void init();

CSS

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
    font-family: 'Inter', sans-serif;
    background: linear-gradient(135deg, #1e1e2f, #252540);
    display: flex;
    align-items: center;
    justify-content: center;
}

#container {
    display: flex;
    background: rgba(255, 255, 255, 0.05);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 20px;
    padding: 30px;
    max-width: 900px;
    width: 100%;
    box-sizing: border-box;
    box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3);
    color: white;
}

.place-overview {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    margin-right: 40px;
}

#info {
    position: relative;
}

#heading {
    font-size: 2.5rem;
    font-weight: 700;
    margin-top: 0;
    margin-bottom: 15px;
    background: linear-gradient(90deg, #fff, #a5b4fc);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}

#summary {
    font-size: 1.1rem;
    line-height: 1.6;
    color: #cbd5e1;
}

#expanded-image {
    position: relative;
    width: 400px;
    height: 400px;
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
    transform: perspective(1000px) rotateY(-5deg);
    transition: transform 0.5s ease;
}

#expanded-image:hover {
    transform: perspective(1000px) rotateY(0deg) scale(1.02);
}

#expanded-image img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

#randomize-btn {
    margin-top: 20px;
    padding: 12px 24px;
    font-size: 1.1rem;
    font-weight: bold;
    color: white;
    background: linear-gradient(90deg, #4f46e5, #3b82f6);
    border: none;
    border-radius: 12px;
    cursor: pointer;
    transition:
        transform 0.2s,
        background 0.3s;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
    font-family: 'Inter', sans-serif;
    align-self: flex-start;
}

#randomize-btn:hover:not(:disabled) {
    transform: scale(1.05);
}

#randomize-btn:disabled {
    background: #475569;
    cursor: not-allowed;
    opacity: 0.7;
}

.attribution-label {
    position: absolute;
    bottom: 10px;
    right: 10px;
    background-color: rgba(0, 0, 0, 0.6);
    color: white;
    padding: 6px 12px;
    border-radius: 20px;
    font-size: 0.8rem;
    text-decoration: none;
    backdrop-filter: blur(4px);
    transition: background-color 0.3s;
}

.attribution-label:hover {
    background-color: rgba(0, 0, 0, 0.8);
}

HTML

<html lang="en">
    <head>
        <title>Place Photos</title>
        <link
            href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap"
            rel="stylesheet" />
        <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="container">
            <div class="place-overview">
                <div id="info">
                    <h1 id="heading"></h1>
                    <div id="summary"></div>
                </div>
                <button id="randomize-btn">Random City Photo</button>
            </div>
            <div id="expanded-image"></div>
        </div>
    </body>
</html>

دریافت عکس

برای دریافت عکس‌های یک مکان، فیلد photos را در پارامترهای درخواست fetchFields() خود اضافه کنید. نمونه «مکان» حاصل حاوی آرایه‌ای از حداکثر ۱۰ شیء Photo است که ازطریق آن‌ها می‌توانید به تصاویر و اطلاعات ارجاع لازم آن‌ها دسترسی پیدا کنید. getURI() را فراخوانی کنید تا URI عکس منبع را برگرداند، بااستفاده از PhotoOptions بیشینه ارتفاع و/یا عرض تصویر برگردانده‌شده را تنظیم کنید. اگر برای هر دو maxHeight و maxWidth مقداری مشخص کنید، سرویس عکس اندازه تصویر را به اندازه کوچک‌تر از بین این دو اندازه تغییر می‌دهد و درعین‌حال نسبت ابعادی اصلی را حفظ می‌کند. اگر ابعادی مشخص نشده باشد، تصویر با اندازه کامل برگردانده می‌شود.

کلاس Photo ویژگی‌های زیر را نشان می‌دهد:

  • authorAttributions: آرایه‌ای از اشیای AuthorAttribution که حاوی نشانی‌های وب و نوشتار ارجاع لازم است.
  • flagContentURI: پیوندی که کاربر می‌تواند ازطریق آن مشکلی را در عکس پرچم‌گذاری کند.
  • googleMapsURI: پیوندی برای نمایش عکس در Google Maps.
  • ‫heightPx: ارتفاع عکس به پیکسل.
  • ‫widthPx: عرض عکس به پیکسل.

مثال زیر نحوه ایجاد درخواست «جزئیات جا» برای عکس‌ها، فراخوانی getURI() در نمونه عکس برای برگرداندن URI منبع تصویر، و سپس افزودن اولین نتیجه عکس به عنصر img را نشان می‌دهد (ارجاع‌ها برای اختصار حذف شده‌اند):

const { Place } = await google.maps.importLibrary('places');

// Use a place ID to create a new Place instance.
const place = new Place({
    id: 'ChIJydSuSkkUkFQRsqhB-cEtYnw', // Woodland Park Zoo, Seattle WA
});

// Call fetchFields, passing the desired data fields.
await place.fetchFields({ fields: ['photos'] });

// Add the first photo to an img element.
const photoImg = document.getElementById('image-container');
photoImg.src = place.photos[0].getURI({maxHeight: 400});

ارجاع‌های نویسنده

وقتی عکسی را نمایش می‌دهید، باید ارجاع‌های نویسنده را نیز برای آن عکس نمایش دهید. از کلاس AuthorAttribution برای برگرداندن ارجاع‌ها استفاده کنید. ارجاع شامل نام نویسنده (displayName)، شناسه منبع یکسان برای نمایه Google Maps او (uri)، و شناسه منبع یکسان برای عکس نویسنده (photoURI) است. قطعه کد زیر برگرداندن displayName، uri، و photoURI را برای عکس مکان نشان می‌دهد.

  let name = place.photos[0].authorAttributions[0].displayName;
  let url = place.photos[0].authorAttributions[0].uri;
  let authorPhoto = place.photos[0].authorAttributions[0].photoURI;