場所の写真

欧州経済領域(EEA)のデベロッパー

Place Photo を使用すると、ウェブページに質の高い写真コンテンツを追加できます。プレイス データベースに保存されている数多くの写真にアクセスし、Find Place、Nearby Search、テキスト検索、予測入力、Place Details を使用してサイズ変更可能な画像を取得することができます。

サンプル ソースコードの全文を見る

この初歩的な写真カルーセルには指定した場所の写真が表示され、選択した写真の左上隅には必要な著作者の帰属情報が表示されます。

TypeScript

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

    // 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: ['displayName', 'photos', 'editorialSummary'],
    });

    // Get the various HTML elements.
    const heading = document.getElementById('heading') as HTMLElement;
    const summary = document.getElementById('summary') as HTMLElement;
    const gallery = document.getElementById('gallery') as HTMLElement;
    const expandedImageDiv = document.getElementById(
        'expanded-image'
    ) as HTMLElement;

    // Show the display name and summary for the place.
    heading.textContent = place.displayName as string;
    summary.textContent = place.editorialSummary as string;

    // Add photos to the gallery.
    place.photos?.forEach((photo) => {
        const altText = 'Photo of ' + place.displayName;
        const img = document.createElement('img');
        const imgButton = document.createElement('button');
        const expandedImage = document.createElement('img');
        img.src = photo?.getURI({ maxHeight: 380 });
        img.alt = altText;
        imgButton.addEventListener('click', (event) => {
            centerSelectedThumbnail(imgButton);
            event.preventDefault();
            expandedImage.src = img.src;
            expandedImage.alt = altText;
            expandedImageDiv.innerHTML = '';
            expandedImageDiv.appendChild(expandedImage);
            const attributionLabel = createAttribution(
                photo.authorAttributions[0]
            )!;
            expandedImageDiv.appendChild(attributionLabel);
        });

        imgButton.addEventListener('focus', () => {
            centerSelectedThumbnail(imgButton);
        });

        imgButton.appendChild(img);
        gallery.appendChild(imgButton);
    });

    // Display the first photo.
    if (place.photos && place.photos.length > 0) {
        const photo = place.photos[0];
        const img = document.createElement('img');
        img.alt = 'Photo of ' + place.displayName;
        img.src = photo.getURI();
        expandedImageDiv.appendChild(img);

        if (photo.authorAttributions && photo.authorAttributions.length > 0) {
            expandedImageDiv.appendChild(
                createAttribution(photo.authorAttributions[0])
            );
        }
    }

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

    // Helper function to center the selected thumbnail in the gallery.
    function centerSelectedThumbnail(element: HTMLElement) {
        element.scrollIntoView({
            behavior: 'smooth',
            block: 'center',
            inline: 'center',
        });
    }
}

init();

JavaScript

async function init() {
    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: ['displayName', 'photos', 'editorialSummary'],
    });
    // Get the various HTML elements.
    const heading = document.getElementById('heading');
    const summary = document.getElementById('summary');
    const gallery = document.getElementById('gallery');
    const expandedImageDiv = document.getElementById('expanded-image');
    // Show the display name and summary for the place.
    heading.textContent = place.displayName;
    summary.textContent = place.editorialSummary;
    // Add photos to the gallery.
    place.photos?.forEach((photo) => {
        const altText = 'Photo of ' + place.displayName;
        const img = document.createElement('img');
        const imgButton = document.createElement('button');
        const expandedImage = document.createElement('img');
        img.src = photo?.getURI({ maxHeight: 380 });
        img.alt = altText;
        imgButton.addEventListener('click', (event) => {
            centerSelectedThumbnail(imgButton);
            event.preventDefault();
            expandedImage.src = img.src;
            expandedImage.alt = altText;
            expandedImageDiv.innerHTML = '';
            expandedImageDiv.appendChild(expandedImage);
            const attributionLabel = createAttribution(photo.authorAttributions[0]);
            expandedImageDiv.appendChild(attributionLabel);
        });
        imgButton.addEventListener('focus', () => {
            centerSelectedThumbnail(imgButton);
        });
        imgButton.appendChild(img);
        gallery.appendChild(imgButton);
    });
    // Display the first photo.
    if (place.photos && place.photos.length > 0) {
        const photo = place.photos[0];
        const img = document.createElement('img');
        img.alt = 'Photo of ' + place.displayName;
        img.src = photo.getURI();
        expandedImageDiv.appendChild(img);
        if (photo.authorAttributions && photo.authorAttributions.length > 0) {
            expandedImageDiv.appendChild(createAttribution(photo.authorAttributions[0]));
        }
    }
    // 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;
    }
    // Helper function to center the selected thumbnail in the gallery.
    function centerSelectedThumbnail(element) {
        element.scrollIntoView({
            behavior: 'smooth',
            block: 'center',
            inline: 'center',
        });
    }
}
init();

CSS

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

#container {
    display: flex;
    border: 2px solid black;
    border-radius: 10px;
    padding: 10px;
    max-width: 950px;
    height: 100%;
    max-height: 400px;
    box-sizing: border-box;
}

.place-overview {
    width: 400px;
    height: 380px;
    overflow-x: auto;
    position: relative;
    margin-right: 20px;
}

#info {
    font-family: sans-serif;
    position: sticky;
    position: -webkit-sticky;
    left: 0;
    padding-bottom: 10px;
}

#heading {
    width: 500px;
    font-size: x-large;
    margin-bottom: 20px;
}

#summary {
    width: 100%;
}

#gallery {
    display: flex;
    padding-top: 10px;
}

#gallery img {
    width: 200px;
    height: 200px;
    margin: 10px;
    border-radius: 10px;
    cursor: pointer;
    object-fit: cover; /* fill the area without distorting the image */
}

#expanded-image {
    display: flex;
    height: 370px;
    overflow: hidden;
    background-color: #000;
    border-radius: 10px;
    margin: 0 auto;
}

.attribution-label {
    background-color: rgba(255, 255, 255, 0.7);
    font-size: 10px;
    font-family: sans-serif;
    margin: 2px;
    position: absolute;
}

button {
    display: flex;
    outline: none;
    border: none;
    padding: 0;
    background: none;
    cursor: pointer;
}

button:focus {
    border: 2px solid blue;
    border-radius: 10px;
}

HTML

<html lang="en">
    <head>
        <title>Place Photos</title>

        <link rel="stylesheet" type="text/css" href="./style.css" />
        <script type="module" src="./index.js"></script>
        <!-- prettier-ignore -->
        <script>(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: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "weekly" });</script>
    </head>
    <body>
        <div id="container">
            <div class="place-overview">
                <div id="info">
                    <h1 id="heading"></h1>
                    <div id="summary"></div>
                </div>
                <div id="gallery"></div>
            </div>
            <div id="expanded-image"></div>
        </div>
    </body>
</html>

サンプルを試す

写真をダウンロード

ある場所の写真を取得するには、fetchFields() リクエスト パラメータの photos フィールドを指定します。その結果、Place インスタンスに最大 10 個の Photo オブジェクトの配列が含まれるようになるため、画像や必要な帰属情報にアクセスできます。getURI() を呼び出して、写真のソース URI を返します。PhotoOptions を使用して、返される画像の最大の高さや幅を設定します。maxHeightmaxWidth の両方に値を指定すると、写真サービスでは、元のアスペクト比を維持しながら、この 2 つの値の小さい方を基準に画像サイズが変更されます。ディメンションが指定されていない場合は、フルサイズの画像が返されます。

Photo クラスは次のプロパティを公開します。

  • authorAttributions: 必要な帰属表示テキストと URL を含む AuthorAttribution オブジェクトの配列。
  • flagContentURI: ユーザーが写真の問題を報告できるリンク。
  • googleMapsURI: Google マップで写真を表示するリンク。
  • heightPx: 写真の高さ(ピクセル単位)。
  • widthPx: 写真の幅(ピクセル単位)。

次の例では、写真の Place Details のリクエストを行い、写真インスタンスの 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 マップ プロフィールの URI(uri)、著作者の写真の URI(photoURI)が含まれます。次のスニペットは、ある場所の写真の displayNameuriphotoURI を返す方法を示しています。

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