PlaceListElement הוא אלמנט HTML שדרכו מוצגות תוצאות החיפוש של המקומות ברשימה. יש שתי דרכים להגדיר את הרכיב gmp-place-list
:
- בקשה לחיפוש בקרבת מקום כדי להגדיר שהווידג'ט יציג תוצאות חיפוש מחיפוש בקרבת מקום ב-Places.
- חיפוש לפי בקשת טקסט כדי להגדיר שהווידג'ט ידפיס תוצאות חיפוש מחיפוש טקסט ב-Places.
בקשה לחיפוש בקרבת מקום
בדוגמה הבאה מוצג רכיב רשימת המקומות בתגובה לחיפוש בקרבת מקום. כדי לפשט את התהליך, מוצגים רק שלושה סוגי מקומות: בית קפה, מסעדה ותחנת טעינה לרכב חשמלי. כשבוחרים תוצאה, מוצג חלון מידע עם פרטי המקום שנבחר. כדי להוסיף את הרכיב 'רשימת מקומות' למפה, מוסיפים את הרכיב gmp-place-list
לדף ה-HTML, כפי שמתואר בקטע הקוד הבא:
<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> </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 placeDetails = document.querySelector("gmp-place-details"); let marker = document.querySelector('gmp-advanced-marker');
כשהמשתמש לוחץ על לחצן החיפוש, מתבצעת קריאה לפונקציה
configureFromSearchNearbyRequest
, והתוצאות מוצגות ברכיב Place List (הסמנים מתווספים בפונקציית העזרה addMarkers
). בקטע הקוד הבא מוצג גם הקוד לטיפול באירועי קליקים ברשימת המקומות באמצעות האירוע gmp-placeselect
:
typeSelect.addEventListener("change", (event) => { // First remove all existing markers. for (marker in markers) { markers[marker].map = null; } markers = {}; if (typeSelect.value) { placeList.configureFromSearchNearbyRequest({ locationRestriction: getContainingCircle(map.innerMap.getBounds()), includedPrimaryTypes: [typeSelect.value], }).then(addMarkers); // Handle user selection in Place Details. placeList.addEventListener("gmp-placeselect", ({ place }) => { markers[place.id].click(); }); } });
הצגת דוגמת הקוד המלאה
JavaScript
const map = document.querySelector("gmp-map"); const placeList = document.querySelector("gmp-place-list"); const typeSelect = document.querySelector(".type-select"); const placeDetails = document.querySelector("gmp-place-details"); let marker = document.querySelector('gmp-advanced-marker'); let markers = {}; let infoWindow; let mapCenter; async function initMap() { await google.maps.importLibrary("places"); const { InfoWindow } = await google.maps.importLibrary("maps"); const { spherical } = await google.maps.importLibrary("geometry"); infoWindow = new google.maps.InfoWindow; function getContainingCircle(bounds) { const diameter = spherical.computeDistanceBetween(bounds.getNorthEast(), bounds.getSouthWest()); const calculatedRadius = diameter / 2; const cappedRadius = Math.min(calculatedRadius, 50000); // Cap the radius to avoid an error. return { center: bounds.getCenter(), radius: cappedRadius }; } findCurrentLocation(); map.innerMap.setOptions({ mapTypeControl: false, clickableIcons: false, }); typeSelect.addEventListener("change", (event) => { // First remove all existing markers. for (marker in markers) { markers[marker].map = null; } markers = {}; if (typeSelect.value) { placeList.configureFromSearchNearbyRequest({ locationRestriction: getContainingCircle(map.innerMap.getBounds()), includedPrimaryTypes: [typeSelect.value], }).then(addMarkers); // Handle user selection in Place Details. 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 }); markers[place.id] = marker; bounds.extend(place.location); marker.addListener('gmp-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: 500, left: 400 }); }); }); 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); } } initMap();
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; height: 600px; } .overlay { position: relative; top: 40px; 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; cursor: pointer; } .type-select { border: 1px solid #ccc; border-radius: 5px; flex-grow: 1; padding: 0 10px; } .list-container { height: 400px; 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"> <script type="module" src="./index.js"></script> </head> <body> <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> </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: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "alpha"});</script> </body> </html>
ניסיון של דוגמה
חיפוש לפי בקשת טקסט
בדוגמה הזו, הרכיב 'רשימת מקומות' מוצג בתגובה לחיפוש טקסט מקודד מראש. כשבוחרים תוצאה, מוצג חלון מידע עם פרטי המקום שנבחר. כדי להוסיף את האלמנט Place List למפה, מוסיפים אלמנט gmp-place-list
לדף ה-HTML, כפי שמתואר בקטע הקוד הבא:
<gmp-map center="37.395641,-122.077627" zoom="10" map-id="DEMO_MAP_ID"> <div class="overlay" slot="control-inline-start-block-start"> <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 placeDetails = document.querySelector("gmp-place-details"); let marker = document.querySelector('gmp-advanced-marker');
כשפונקציית החיפוש מופעלת בזמן טעינת הדף, מתבצעת קריאה לפונקציה
configureFromSearchByTextRequest
, והרכיב Place List מציג את התוצאות (הסמנים מתווספים בפונקציית העזרה addMarkers
). קטע הקוד הבא מציג את הקוד של הפונקציה:
async function searchByTextRequest(textQuery) { if (textQuery) { placeList.configureFromSearchByTextRequest({ locationRestriction: bounds, includedType: "restaurant", textQuery: textQuery, }).then(addMarkers); // Handle user selection in Place Details. placeList.addEventListener("gmp-placeselect", ({ place }) => { markers[place.id].click(); }); } }
הצגת דוגמת הקוד המלאה
בדוגמה הבאה נעשה שימוש ברכיב ממשק המשתמש של רשימת המקומות כדי להציג מקומות על סמך חיפוש בקרבת מקום באמצעות
configureFromSearchNearbyRequest
, ומוסיפים למפה סמנים שניתן ללחוץ עליהם כדי להציג את פרטי המקום שנבחר.
JavaScript
const map = document.querySelector("gmp-map"); const placeList = document.querySelector("gmp-place-list"); const placeDetails = document.querySelector("gmp-place-details"); let marker = document.querySelector('gmp-advanced-marker'); let markers = {}; let infoWindow; let center = { lat: 37.395641, lng: -122.077627 }; let bounds; async function initMap() { const { Map, InfoWindow } = await google.maps.importLibrary("maps"); const { Place } = await google.maps.importLibrary("places"); // Set bounds for location restriction. bounds = new google.maps.LatLngBounds({ lat: 37.37808200917261, lng: -122.13741583377849 }, { lat: 37.416676154341324, lng: -122.02261728794109 }); infoWindow = new google.maps.InfoWindow; // Center the map let adjustedCenter = offsetLatLngRight(center, -0.005); map.innerMap.panTo(adjustedCenter); map.innerMap.setZoom(14); map.innerMap.setOptions({ mapTypeControl: false, clickableIcons: false, }); searchByTextRequest('tacos in Mountain View'); } async function searchByTextRequest(textQuery) { if (textQuery) { placeList.configureFromSearchByTextRequest({ locationRestriction: bounds, includedType: "restaurant", textQuery: textQuery, }).then(addMarkers); // Handle user selection in Place Details. 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, }); markers[place.id] = marker; bounds.extend(place.location); marker.collisionBehavior = google.maps.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL; marker.addListener('gmp-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: 400, left: 400 }); }); }); map.innerMap.setCenter(bounds.getCenter()); map.innerMap.fitBounds(bounds); }); } } // Helper function to offset the map center. function offsetLatLngRight(latLng, longitudeOffset) { const newLng = latLng.lng + longitudeOffset; return new google.maps.LatLng(latLng.lat, newLng); } initMap();
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; height: 500px; } .overlay { position: relative; top: 20px; 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; cursor: pointer; } .type-select { border: 1px solid #ccc; border-radius: 5px; flex-grow: 1; padding: 0 10px; } .list-container { height: 400px; overflow: auto; border-radius: 10px; } gmp-place-list { background-color: #fff; }
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"> <script type="module" src="./index.js"></script> </head> <body> <gmp-map center="37.395641,-122.077627" zoom="10" map-id="DEMO_MAP_ID"> <div class="overlay" slot="control-inline-start-block-start"> <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: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "alpha"});</script> </body> </html>