PlaceListElement는 장소 검색 결과를 목록에 렌더링하는 HTML 요소입니다. gmp-place-list
요소를 구성하는 방법에는 두 가지가 있습니다.
- 텍스트 요청으로 검색: Places 텍스트 검색의 검색 결과를 렌더링하도록 위젯을 구성합니다.
- Nearby Search 요청: Places Nearby Search의 검색 결과를 렌더링하도록 위젯을 구성합니다.
텍스트로 검색 요청
다음 예는 사용자 텍스트 검색에 대한 응답으로 장소 목록 요소를 렌더링합니다. 결과를 선택하면 선택한 장소의 장소 세부정보를 보여주는 정보 창이 표시됩니다. 지도에 장소 목록 요소를 추가하려면 다음 스니펫과 같이 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
가 호출되고 장소 목록 요소가 결과를 렌더링합니다 (마커는 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
를 사용한 텍스트 검색을 기반으로 장소를 표시하고 클릭 가능한 마커를 지도에 추가하여 선택 시 장소 세부정보를 표시합니다.
자바스크립트
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>
주변 검색 요청
다음 예는 주변 검색에 대한 응답으로 장소 목록 요소를 렌더링합니다. 편의상 카페, 레스토랑, 전기자동차 충전소 등 세 가지 장소 유형만 표시됩니다. 결과를 선택하면 선택한 장소의 장소 세부정보를 보여주는 정보 창이 표시됩니다. 지도에 장소 목록 요소를 추가하려면 다음 스니펫과 같이 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
가 호출되고 장소 목록 요소에 결과가 표시됩니다 (마커는 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
를 사용하여 주변 검색을 기반으로 장소를 표시하고 클릭 가능한 마커를 지도에 추가하여 선택 시 장소 세부정보를 표시합니다.
자바스크립트
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>