借助 Place Photos,您可以向网页添加高品质照片内容。访问地点数据库中存储的数百万张照片,并使用“查找地点”“附近搜索”“文本搜索”“自动补全”和“地点详情”获取可调整大小的图片。
查看完整的示例源代码
此演示会显示来自五个城市之一的随机照片,并在照片的右下角显示所需的作者署名。
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: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8"
});
</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>试用示例
获取照片
如需获取某个地点的照片,请在 fetchFields() 请求参数中添加 photos 字段。生成的 Place 实例包含一个最多包含 10 个 Photo 对象的数组,您可以从中访问图片及其所需的提供方信息。
调用 getURI() 可返回源照片 URI,使用 PhotoOptions 可设置返回的图片的最大高度和/或宽度。如果您同时为 maxHeight 和 maxWidth 指定值,照片服务会将图片大小调整为两种尺寸中的较小者,同时保留原始宽高比。如果未指定任何维度,则返回全尺寸图片。
Photo 类公开了以下属性:
authorAttributions:一个AuthorAttribution对象数组,其中包含所需的提供方信息文字和网址。flagContentURI:用户可用于标记照片存在问题的链接。googleMapsURI:用于在 Google 地图中显示相应照片的链接。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 地图个人资料的 URI (uri) 和作者的照片的 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;