PlaceListElement 是一種 HTML 元素,可在清單中算繪地點搜尋結果。設定 gmp-place-list
元素的方法有兩種:
- Search by text request:設定小工具,以便顯示 Places Text Search 的搜尋結果。
- 搜尋附近要求:設定小工具,以便顯示來自 Places Nearby Search 的搜尋結果。
依文字搜尋要求
以下範例會根據使用者的文字搜尋,算繪 Place List 元素。選取結果後,系統會顯示資訊視窗,顯示所選地點的詳細資料。如要在地圖中新增地點清單元素,請在 HTML 網頁中新增 gmp-place-list
元素,如以下程式碼片段所示:
<gmp-map center="-37.813,144.963" zoom="2" map-id="DEMO_MAP_ID"> <div class="overlay" slot="control-inline-start-block-start"> <div class="controls"> <input type="text" class="query-input" /> <button class="search-button">Search</button> </div> <div class="list-container"> <gmp-place-list selectable></gmp-place-list> </div> </div> <gmp-place-details size="large"></gmp-place-details> </gmp-map>
系統會使用多個 querySelector
呼叫,選取要互動的網頁元素:
const map = document.querySelector('gmp-map'); const placeList = document.querySelector('gmp-place-list'); const queryInput = document.querySelector('.query-input'); const searchButton = document.querySelector('.search-button'); const placeDetails = document.querySelector('gmp-place-details');
當使用者按下搜尋按鈕時,系統會呼叫
configureFromSearchByTextRequest
,並透過 Place List 元素顯示結果 (標記會新增至 addMarkers
輔助函式)。下列程式碼片段顯示處理點擊事件的程式碼:
searchButton.addEventListener('click', () => { for (marker in markers) { markers[marker].map = null; } markers = {}; if (queryInput.value) { placeList .configureFromSearchByTextRequest({ textQuery: queryInput.value, locationBias: map.innerMap.getBounds() }) .then(addMarkers); } });
查看完整程式碼範例
以下範例使用地點清單 UI 元件,根據使用
configureFromSearchByTextRequest
進行的文字搜尋顯示地點,並在地圖上新增可點選的標記,在選取時顯示地點詳細資料。
JavaScript
const map = document.querySelector('gmp-map'); const placeList = document.querySelector('gmp-place-list'); const queryInput = document.querySelector('.query-input'); const searchButton = document.querySelector('.search-button'); const placeDetails = document.querySelector('gmp-place-details'); let markers = {}; let infowindow = {}; async function init() { await google.maps.importLibrary('places'); const { InfoWindow } = await google.maps.importLibrary('maps'); infowindow = new InfoWindow(); // Call geolocation helper function to center map. findCurrentLocation(); map.innerMap.setOptions({ mapTypeControl: false, clickableIcons: false, }); // Handle click on search button. searchButton.addEventListener('click', () => { for (marker in markers) { markers[marker].map = null; } markers = {}; if (queryInput.value) { placeList .configureFromSearchByTextRequest({ textQuery: queryInput.value, locationBias: map.innerMap.getBounds() }) .then(addMarkers); } }); // Handle the user's selection on the Place List. placeList.addEventListener('gmp-placeselect', ({ place }) => { markers[place.id].click(); }); } // Helper function to add markers. async function addMarkers() { const { AdvancedMarkerElement } = await google.maps.importLibrary('marker'); const { LatLngBounds } = await google.maps.importLibrary('core'); const bounds = new LatLngBounds(); if (placeList.places.length > 0) { placeList.places.forEach((place) => { let marker = new AdvancedMarkerElement({ map: map.innerMap, position: place.location }); marker.metadata = { id: place.id }; markers[place.id] = marker; bounds.extend(place.location); marker.addListener('click', (event) => { if (infowindow.isOpen) { infowindow.close(); } placeDetails.configureFromPlace(place); placeDetails.style.width = '350px'; infowindow.setOptions({ content: placeDetails }); infowindow.open({ anchor: marker, map: map.innerMap }); placeDetails.addEventListener('gmp-load', () => { map.innerMap.fitBounds( place.viewport, { top: placeDetails.offsetHeight || 206, left: 200 }); }); }); map.innerMap.setCenter(bounds.getCenter()); map.innerMap.fitBounds(bounds); }); } } // Helper function to center map on current device location. async function findCurrentLocation() { const { LatLng } = await google.maps.importLibrary('core'); if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( (position) => { const pos = new LatLng(position.coords.latitude, position.coords.longitude); map.innerMap.panTo(pos); map.innerMap.setZoom(16); }, () => { console.log('The Geolocation service failed.'); map.innerMap.setZoom(16); }, ); } else { console.log('Your browser doesn\'t support geolocation'); map.innerMap.setZoom(16); } } init();
CSS
html, body { height: 100%; margin: 0; } body { display: flex; flex-direction: column; font-family: Arial, Helvetica, sans-serif; } h1 { font-size: 16px; text-align: center; } gmp-map { box-sizing: border-box; padding: 0 20px 20px; } .overlay { margin: 20px; width: 400px; } .controls { display: flex; gap: 10px; margin-bottom: 10px; height: 32px; } .search-button { background-color: #5491f5; color: #fff; border: 1px solid #ccc; border-radius: 5px; width: 100px; } .query-input { border: 1px solid #ccc; border-radius: 5px; flex-grow: 1; padding: 10px; } .list-container { height: 600px; overflow: auto; border-radius: 10px; } gmp-place-list { background-color: #fff; } gmp-place-details { width: 320px; }
HTML
<!DOCTYPE html> <html> <head> <title>Place List Text Search with Google Maps</title> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <h1>Place List Text Search with Google Maps</h1> <gmp-map center="-37.813,144.963" zoom="2" map-id="DEMO_MAP_ID"> <div class="overlay" slot="control-inline-start-block-start"> <div class="controls"> <input type="text" class="query-input" /> <button class="search-button">Search</button> </div> <div class="list-container"> <gmp-place-list selectable></gmp-place-list> </div> </div> <gmp-place-details size="large"></gmp-place-details> </gmp-map> <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: "YOUR_API_KEY", v: "alpha" }); </script> </body> </html>
搜尋附近地區要求
以下範例會在回應附近搜尋時,算繪 Place List 元素。為簡化說明,我們只列出三種地點類型:咖啡廳、餐廳和電動車充電站。選取結果後,系統會顯示資訊視窗,顯示所選地點的詳細資料。如要在地圖中加入地點清單元素,請在 HTML 網頁中新增 gmp-place-list
元素,如以下程式碼片段所示:
<gmp-map center="-37.813,144.963" zoom="10" map-id="DEMO_MAP_ID"> <div class="overlay" slot="control-inline-start-block-start"> <div class="controls"> <select name="types" class="type-select"> <option value="">Select a place type</option> <option value="cafe">Cafe</option> <option value="restaurant">Restaurant</option> <option value="electric_vehicle_charging_station"> EV charging station </option> </select> <button class="search-button">Search</button> </div> <div class="list-container"> <gmp-place-list selectable></gmp-place-list> </div> </div> <gmp-place-details size="large"></gmp-place-details> </gmp-map>
系統會使用多個 querySelector
呼叫,選取要互動的網頁元素:
const map = document.querySelector("gmp-map"); const placeList = document.querySelector('gmp-place-list'); const typeSelect = document.querySelector('.type-select'); const searchButton = document.querySelector('.search-button'); const placeDetails = document.querySelector('gmp-place-details');
當使用者點選搜尋按鈕時,系統會呼叫
configureFromSearchNearbyRequest
,並透過 Place List 元素顯示結果 (標記會在 addMarkers
輔助函式中新增)。下列程式碼片段也顯示了使用 gmp-placeselect
事件處理地點清單上點擊事件的程式碼:
searchButton.addEventListener('click', () => { for (marker in markers) { markers[marker].map = null; } markers = {}; if (typeSelect.value) { placeList .configureFromSearchNearbyRequest({ locationRestriction: getContainingCircle(map.innerMap.getBounds()), includedPrimaryTypes: [typeSelect.value], }) .then(addMarkers); placeList.addEventListener('gmp-placeselect', ({place}) => { markers[place.id].click(); }); } });
查看完整程式碼範例
以下範例使用地點清單 UI 元件,根據使用
configureFromSearchNearbyRequest
進行附近搜尋,顯示地點,並在地圖上加入可點選的標記,在選取時顯示地點詳細資料。
JavaScript
const map = document.querySelector("gmp-map"); const placeList = document.querySelector("gmp-place-list"); const typeSelect = document.querySelector(".type-select"); const searchButton = document.querySelector(".search-button"); const placeDetails = document.querySelector("gmp-place-details"); let markers = {}; let infowindow = {}; let mapCenter; async function init() { await google.maps.importLibrary("places"); const {InfoWindow} = await google.maps.importLibrary("maps"); const { spherical } = await google.maps.importLibrary("geometry"); infowindow = new InfoWindow(); function getContainingCircle(bounds) { const diameter = spherical.computeDistanceBetween( bounds.getNorthEast(), bounds.getSouthWest() ); return { center: bounds.getCenter(), radius: diameter / 2 }; } findCurrentLocation(); map.innerMap.setOptions({ mapTypeControl: false, clickableIcons: false, }); searchButton.addEventListener("click", () => { for(marker in markers){ markers[marker].map = null; } markers = {}; if (typeSelect.value) { placeList.configureFromSearchNearbyRequest({ locationRestriction: getContainingCircle( map.innerMap.getBounds() ), includedPrimaryTypes: [typeSelect.value], }).then(addMarkers); placeList.addEventListener("gmp-placeselect", ({ place }) => { markers[place.id].click(); }); } }); } async function addMarkers(){ const { AdvancedMarkerElement } = await google.maps.importLibrary("marker"); const { LatLngBounds } = await google.maps.importLibrary("core"); const bounds = new LatLngBounds(); if(placeList.places.length > 0){ placeList.places.forEach((place) => { let marker = new AdvancedMarkerElement({ map: map.innerMap, position: place.location }); marker.metadata = {id: place.id}; markers[place.id] = marker; bounds.extend(place.location); // pinMarkers.push(marker); marker.addListener('click',(event) => { if(infowindow.isOpen){ infowindow.close(); } placeDetails.configureFromPlace(place); placeDetails.style.width = "350px"; infowindow.setOptions({ content: placeDetails }); infowindow.open({ anchor: marker, map: map.innerMap }); placeDetails.addEventListener('gmp-load',() => { map.innerMap.fitBounds(place.viewport, {top: placeDetails.offsetHeight || 206, left: 200}); }); }); map.innerMap.setCenter(bounds.getCenter()); map.innerMap.fitBounds(bounds); }); } } async function findCurrentLocation(){ const { LatLng } = await google.maps.importLibrary("core") if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( (position) => { const pos = new LatLng(position.coords.latitude,position.coords.longitude); map.innerMap.panTo(pos); map.innerMap.setZoom(14); }, () => { console.log('The Geolocation service failed.'); map.innerMap.setZoom(14); }, ); } else { console.log("Your browser doesn't support geolocation"); map.innerMap.setZoom(14); } } init();
CSS
html, body { height: 100%; margin: 0; } body { display: flex; flex-direction: column; font-family: Arial, Helvetica, sans-serif; } h1 { font-size: 16px; text-align: center; } gmp-map { box-sizing: border-box; padding: 0 20px 20px; } .overlay { margin: 20px; width: 400px; } .controls { display: flex; gap: 10px; margin-bottom: 10px; height: 32px; } .search-button { background-color: #5491f5; color: #fff; border: 1px solid #ccc; border-radius: 5px; width: 100px; } .type-select { border: 1px solid #ccc; border-radius: 5px; flex-grow: 1; padding: 0 10px; } .list-container { height: 600px; overflow: auto; border-radius: 10px; } gmp-place-list { background-color: #fff; }
HTML
<!DOCTYPE html> <html> <head> <title>Place List Nearby Search with Google Maps</title> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <h1>Place List Nearby Search with Google Maps</h1> <gmp-map center="-37.813,144.963" zoom="10" map-id="DEMO_MAP_ID"> <div class="overlay" slot="control-inline-start-block-start"> <div class="controls"> <select name="types" class="type-select"> <option value="">Select a place type</option> <option value="cafe">Cafe</option> <option value="restaurant">Restaurant</option> <option value="electric_vehicle_charging_station"> EV charging station </option> </select> <button class="search-button">Search</button> </div> <div class="list-container"> <gmp-place-list selectable></gmp-place-list> </div> </div> <gmp-place-details size="large"></gmp-place-details> </gmp-map> <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: "YOUR_API_KEY", v: "alpha" }); </script> </body> </html>