PlaceSearchElement
הוא אלמנט HTML שמציג את תוצאות החיפוש של מקום ברשימה. יש שתי דרכים להגדיר את רכיב gmp-place-search
:
- משתמשים בבקשה לחיפוש בסביבה כדי להציג תוצאות חיפוש באמצעות
PlaceNearbySearchRequestElement
- אפשר להשתמש בבקשה לחיפוש באמצעות טקסט כדי להציג תוצאות חיפוש באמצעות
PlaceTextSearchRequestElement
חיפוש בקשה בקרבת מקום
בוחרים סוג מקום מהתפריט כדי לראות תוצאות חיפוש של מקומות מהסוג הזה שנמצאים בקרבת מקום.
בדוגמה הבאה מוצג רכיב Place Search בתגובה לחיפוש בקרבת מקום. לצורך פשטות, מפורטים רק שלושה סוגי מקומות:
בית קפה, מסעדה ותחנת טעינה לרכב חשמלי. כשבוחרים תוצאה, מוצג סמן ו-
PlaceDetailsCompactElement עבור המקום שנבחר. כדי להוסיף את הרכיב Place Search למפה, מוסיפים את הרכיב gmp-place-search
שמכיל את הרכיב gmp-place-nearby-search-request
לדף ה-HTML, כמו שמוצג בקטע הקוד הבא:
<div class="list-container"> <div id="map-container"></div> <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-search orientation="vertical" selectable> <gmp-place-all-content> </gmp-place-all-content> <gmp-place-nearby-search-request ></gmp-place-nearby-search-request> </gmp-place-search> </div> <div id="details-container"> <gmp-place-details-compact orientation="horizontal"> <gmp-place-details-place-request></gmp-place-details-place-request> <gmp-place-all-content></gmp-place-all-content> </gmp-place-details-compact> </div>
כמה קריאות ל-querySelector
משמשות לבחירת רכיבי הדף לאינטראקציה:
const mapContainer = document.getElementById("map-container"); const placeSearch = document.querySelector("gmp-place-search"); const placeSearchQuery = document.querySelector("gmp-place-nearby-search-request"); const detailsContainer = document.getElementById("details-container"); const placeDetails = document.querySelector("gmp-place-details-compact"); const placeRequest = document.querySelector("gmp-place-details-place-request"); const typeSelect = document.querySelector(".type-select");
כשהמשתמש בוחר סוג מקום מהתפריט, הרכיב gmp-place-nearby-search-request
מתעדכן והרכיב Place Search מציג את התוצאות (סמנים מתווספים בפונקציית העזר addMarkers
):
typeSelect.addEventListener('change', (event) => { event.preventDefault(); searchPlaces(); }); function searchPlaces(){ const bounds = gMap.getBounds(); placeDetailsPopup.map = null; if (typeSelect.value) { placeSearch.style.display = 'block'; placeSearchQuery.maxResultCount = 10; placeSearchQuery.locationRestriction = { center: cent, radius: 1000 }; placeSearchQuery.includedTypes = [typeSelect.value]; placeSearch.addEventListener('gmp-load', addMarkers, { once: true }); } }
הצגת הקוד המלא לדוגמה
JavaScript
const mapContainer = document.getElementById("map-container"); const placeSearch = document.querySelector("gmp-place-search"); const placeSearchQuery = document.querySelector("gmp-place-nearby-search-request"); const detailsContainer = document.getElementById("details-container"); const placeDetails = document.querySelector("gmp-place-details-compact"); const placeRequest = document.querySelector("gmp-place-details-place-request"); const typeSelect = document.querySelector(".type-select"); let markers = {}; let gMap; let placeDetailsPopup; let spherical; let AdvancedMarkerElement; let LatLngBounds; let LatLng; async function init() { console.log("init"); ({ spherical } = await google.maps.importLibrary('geometry')); const {Map} = await google.maps.importLibrary("maps"); await google.maps.importLibrary("places"); ({AdvancedMarkerElement} = await google.maps.importLibrary("marker")); ({LatLngBounds, LatLng} = await google.maps.importLibrary("core")); let mapOptions = { center: {lat: -37.813, lng: 144.963}, zoom: 16, mapTypeControl: false, clickableIcons: false, mapId: 'DEMO_MAP_ID' }; gMap = new Map(mapContainer, mapOptions); placeDetailsPopup = new AdvancedMarkerElement({ map: null, content: placeDetails, zIndex: 100 }); findCurrentLocation(); gMap.addListener('click', (e) => { hidePlaceDetailsPopup(); }); typeSelect.addEventListener('change', (event) => { event.preventDefault(); searchPlaces(); }); placeSearch.addEventListener("gmp-select", ({ place }) => { if (markers[place.id]) { markers[place.id].click(); } }); } function searchPlaces(){ const bounds = gMap.getBounds(); const cent = gMap.getCenter(); const ne = bounds.getNorthEast(); const sw = bounds.getSouthWest(); const diameter = spherical.computeDistanceBetween(ne, sw); const cappedRadius = Math.min((diameter / 2 ), 50000); // Radius cannot be more than 50000. placeDetailsPopup.map = null; for(const markerId in markers){ if (Object.prototype.hasOwnProperty.call(markers, markerId)) { markers[markerId].map = null; } } markers = {}; if (typeSelect.value) { mapContainer.style.height = '75vh'; placeSearch.style.display = 'block'; placeSearchQuery.maxResultCount = 10; placeSearchQuery.locationRestriction = { center: cent, radius: cappedRadius }; placeSearchQuery.includedTypes = [typeSelect.value]; placeSearch.addEventListener('gmp-load', addMarkers, { once: true }); console.log("selection!"); console.log(cappedRadius); } } async function addMarkers(){ const bounds = new LatLngBounds(); placeSearch.style.display = 'block'; if(placeSearch.places.length > 0){ placeSearch.places.forEach((place) => { let marker = new AdvancedMarkerElement({ map: gMap, position: place.location }); marker.metadata = {id: place.id}; markers[place.id] = marker; bounds.extend(place.location); marker.addListener('click',(event) => { placeRequest.place = place; placeDetails.style.display = 'block'; placeDetailsPopup.position = place.location; placeDetailsPopup.map = gMap; gMap.fitBounds(place.viewport, {top: 0, left: 400}); placeDetails.addEventListener('gmp-load',() => { gMap.fitBounds(place.viewport, {top: 0, right: 450}); }, { once: true }); }); gMap.setCenter(bounds.getCenter()); gMap.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); gMap.panTo(pos); gMap.setZoom(16); }, () => { console.log('The Geolocation service failed.'); gMap.setZoom(16); }, ); } else { console.log("Your browser doesn't support geolocation"); gMap.setZoom(16); } } function hidePlaceDetailsPopup() { if (placeDetailsPopup.map) { placeDetailsPopup.map = null; placeDetails.style.display = 'none'; } } init();
CSS
html, body { height: 100%; margin: 0; } body { display: flex; flex-direction: column; font-family: Arial, Helvetica, sans-serif; } h1 { font-size: large; text-align: center; } #map-container { flex-grow: 1; max-height:600px; box-sizing: border-box; width: 100%; height: 100vh; } .controls { position: absolute; top: 40px; right: 40px; } .list-container { display: flex; position: absolute; max-height: 500px; top: 80px; right: 40px; overflow-y: none; } .type-select { width: 400px; height: 32px; border: 1px solid #000; border-radius: 10px; flex-grow: 1; padding: 0 10px; } gmp-place-search { width: 400px; margin: 0; border-radius: 10px; display: none; border: none; } gmp-place-details-compact { width: 350px; max-height: 800px; margin-right: 20px; display: none; border: none; } gmp-place-details-compact::after { content: ''; position: absolute; bottom: -18px; left: 50%; transform: translateX(-50%); width: 20px; height: 20px; background-color: white; box-shadow: 2px 2px 5px 0 rgba(0,0,0,0.2); z-index: 1; clip-path: polygon(0% 0%, 100% 0%, 50% 100%); transform-origin: center center; } @media (prefers-color-scheme: dark) { /* Style for Dark mode */ gmp-place-details-compact::after { background-color: #131314; } }
HTML
<!DOCTYPE html> <html> <head> <title>Place Search with Compact Place Details Element</title> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> <script type="module" src="./index.js"></script> </head> <body> <div id="map-container"></div> <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-search orientation="vertical" selectable> <gmp-place-all-content> </gmp-place-all-content> <gmp-place-nearby-search-request ></gmp-place-nearby-search-request> </gmp-place-search> </div> <div id="details-container"> <gmp-place-details-compact orientation="horizontal"> <gmp-place-details-place-request></gmp-place-details-place-request> <gmp-place-all-content></gmp-place-all-content> </gmp-place-details-compact> </div> <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: "weekly"}); </script> </body> </html>
חיפוש לפי בקשת טקסט
מזינים מונח חיפוש בשדה הקלט ולוחצים על לחצן החיפוש כדי לקבל רשימה של מקומות שתואמים למונח.
בדוגמה הזו, רכיב חיפוש המקומות מוצג בתגובה לחיפוש טקסט של משתמש. כשבוחרים תוצאה, מוצגים סמן ו-
PlaceDetailsCompactElement עבור המקום שנבחר. כדי להוסיף את הרכיב Place Search למפה, מוסיפים לדף ה-HTML רכיב gmp-place-search
שמכיל רכיב gmp-place-search-text-search-request
, כמו שמוצג בקטע הקוד הבא:
<div id="map-container"></div> <div class="controls"> <input type="text" class="query-input" /> <button class="search-button">Search</button> </div> <div class="list-container"> <gmp-place-search orientation="vertical" selectable> <gmp-place-all-content> </gmp-place-all-content> <gmp-place-text-search-request></gmp-place-text-search-request> </gmp-place-search> </div> <div id="details-container"> <gmp-place-details-compact orientation="horizontal"> <gmp-place-details-place-request></gmp-place-details-place-request> <gmp-place-all-content></gmp-place-all-content> </gmp-place-details-compact> </div>
כמה קריאות ל-querySelector
משמשות לבחירת רכיבי הדף לאינטראקציה:
const mapContainer = document.getElementById("map-container"); const placeSearch = document.querySelector("gmp-place-search"); const placeSearchQuery = document.querySelector("gmp-place-text-search-request"); const queryInput = document.querySelector(".query-input"); const searchButton = document.querySelector(".search-button"); const detailsContainer = document.getElementById("details-container"); const placeDetails = document.querySelector("gmp-place-details-compact"); const placeRequest = document.querySelector("gmp-place-details-place-request");
כשמריצים את פונקציית החיפוש אחרי שהמשתמש מזין שאילתת חיפוש, הרכיב
gmp-place-text-search-request
מתעדכן, וברכיב Place Search מוצגות התוצאות (סמנים מתווספים בפונקציית העזר addMarkers
):
searchButton.addEventListener("click", searchPlaces); queryInput.addEventListener("keydown", (event) => { if (event.key == 'Enter') { event.preventDefault(); searchPlaces(); } }); function searchPlaces(){ if (queryInput.value) { placeSearch.style.display = 'block'; placeSearchQuery.textQuery = queryInput.value; placeSearchQuery.locationBias = gMap.getBounds(); placeSearch.addEventListener('gmp-load', addMarkers, { once: true }); } }
הצגת הקוד המלא לדוגמה
JavaScript
const mapContainer = document.getElementById("map-container"); const placeSearch = document.querySelector("gmp-place-search"); const placeSearchQuery = document.querySelector("gmp-place-text-search-request"); const queryInput = document.querySelector(".query-input"); const searchButton = document.querySelector(".search-button"); const detailsContainer = document.getElementById("details-container"); const placeDetails = document.querySelector("gmp-place-details-compact"); const placeRequest = document.querySelector("gmp-place-details-place-request"); let markers = {}; let previousSearchQuery = ''; let gMap; let placeDetailsPopup; let AdvancedMarkerElement; let LatLngBounds; let LatLng; async function init() { const {Map} = await google.maps.importLibrary("maps"); await google.maps.importLibrary("places"); ({AdvancedMarkerElement} = await google.maps.importLibrary("marker")); ({LatLngBounds, LatLng} = await google.maps.importLibrary("core")); let mapOptions = { center: {lat: 37.422, lng: -122.085}, zoom: 2, mapTypeControl: false, clickableIcons: false, mapId: 'DEMO_MAP_ID' }; gMap = new Map(mapContainer, mapOptions); placeDetailsPopup = new AdvancedMarkerElement({ map: null, content: placeDetails, zIndex: 100 }); findCurrentLocation(); gMap.addListener('click', (e) => { hidePlaceDetailsPopup(); }); searchButton.addEventListener("click", searchPlaces); queryInput.addEventListener("keydown", (event) => { if (event.key == 'Enter') { event.preventDefault(); searchPlaces(); } }); placeSearch.addEventListener("gmp-select", ({ place }) => { if (markers[place.id]) { markers[place.id].click(); } }); } function searchPlaces(){ if (queryInput.value.trim() === previousSearchQuery) { return; } previousSearchQuery = queryInput.value.trim(); placeDetailsPopup.map = null; for(const markerId in markers){ if (Object.prototype.hasOwnProperty.call(markers, markerId)) { markers[markerId].map = null; } } markers = {}; if (queryInput.value) { // mapContainer.style.height = '75vh'; placeSearch.style.display = 'block'; placeSearchQuery.textQuery = queryInput.value; placeSearchQuery.locationBias = gMap.getBounds(); placeSearch.addEventListener('gmp-load', addMarkers, { once: true }); } } async function addMarkers(){ const bounds = new LatLngBounds(); if(placeSearch.places.length > 0){ placeSearch.places.forEach((place) => { let marker = new AdvancedMarkerElement({ map: gMap, position: place.location }); marker.metadata = {id: place.id}; markers[place.id] = marker; bounds.extend(place.location); marker.addListener('click',(event) => { placeRequest.place = place; placeDetails.style.display = 'block'; placeDetailsPopup.position = place.location; placeDetailsPopup.map = gMap; gMap.fitBounds(place.viewport, {top: 200, right: 450}); }); gMap.setCenter(bounds.getCenter()); gMap.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); gMap.panTo(pos); gMap.setZoom(16); }, () => { console.log('The Geolocation service failed.'); gMap.setZoom(16); }, ); } else { console.log("Your browser doesn't support geolocation"); gMap.setZoom(16); } } function hidePlaceDetailsPopup() { if (placeDetailsPopup.map) { placeDetailsPopup.map = null; placeDetails.style.display = 'none'; } } init();
CSS
html, body { height: 100%; margin: 0; } body { display: flex; flex-direction: column; font-family: Arial, Helvetica, sans-serif; } h1 { font-size: large; text-align: center; } #map-container { flex-grow: 1; max-height:600px; box-sizing: border-box; width: 100%; height: 100vh; } .controls { border-radius: 5px; position: absolute; top: 40px; right: 40px; } .search-button { background-color: #4b4b4b; color: #fff; border: 1px solid #000; border-radius: 10px; width: 80px; height: 40px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.35); } .query-input { border: 1px solid #ccc; border-radius: 10px; width: 315px; height: 40px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.35); } .list-container { display: flex; position: absolute; max-height: 500px; top: 100px; right: 40px; overflow-y: none; } gmp-place-search { width: 400px; margin: 0; border-radius: 10px; display: none; border: none; } gmp-place-details-compact { width: 350px; max-height: 800px; display: none; border: none; transform: translateY(calc(-40%)); } gmp-place-details-compact::after { content: ''; position: absolute; bottom: -18px; left: 50%; transform: translateX(-50%); width: 20px; height: 20px; background-color: white; box-shadow: 2px 2px 5px 0 rgba(0,0,0,0.2); z-index: 1; clip-path: polygon(0% 0%, 100% 0%, 50% 100%); transform-origin: center center; } @media (prefers-color-scheme: dark) { /* Style for Dark mode */ gmp-place-details-compact::after { background-color: #131314; } }
HTML
<!DOCTYPE html> <html> <head> <title>Place Search with a Details Popup</title> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> <script type="module" src="./index.js"></script> </head> <body> <div id="map-container"></div> <div class="controls"> <input type="text" class="query-input" /> <button class="search-button">Search</button> </div> <div class="list-container"> <gmp-place-search orientation="vertical" selectable> <gmp-place-all-content> </gmp-place-all-content> <gmp-place-text-search-request></gmp-place-text-search-request> </gmp-place-search> </div> <div id="details-container"> <gmp-place-details-compact orientation="horizontal"> <gmp-place-details-place-request></gmp-place-details-place-request> <gmp-place-all-content></gmp-place-all-content> </gmp-place-details-compact> </div> <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: "weekly"}); </script> </body> </html>