องค์ประกอบรายการสถานที่ (การค้นหาสถานที่)

PlaceListElement หรือที่เรียกว่าการค้นหาสถานที่เป็นองค์ประกอบ HTML ที่แสดงผลลัพธ์ของการค้นหาสถานที่เป็นรายการ การกำหนดค่าองค์ประกอบ gmp-place-list ทำได้ 2 วิธีดังนี้

ค้นหาคำขอในบริเวณใกล้เคียง

ตัวอย่างต่อไปนี้แสดงผลองค์ประกอบรายการสถานที่เพื่อตอบสนองการค้นหาในพื้นที่ใกล้เคียง เพื่อความสะดวก เราจะแสดงเฉพาะสถานที่ 3 ประเภท ได้แก่ คาเฟ่ ร้านอาหาร และสถานีชาร์จ EV เมื่อเลือกผลการค้นหาแล้ว หน้าต่างข้อมูลจะแสดงรายละเอียดสถานที่สำหรับสถานที่ที่เลือก หากต้องการเพิ่มองค์ประกอบรายการสถานที่ลงในแผนที่ ให้เพิ่มองค์ประกอบ 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 style="display: none;"></gmp-place-list>
    </div>
  </div>
</gmp-map>

<gmp-place-details style="display: none;">
  <gmp-place-details-place-request></gmp-place-details-place-request>
  <gmp-place-all-content></gmp-place-all-content> 
</gmp-place-details>

การเรียกใช้ 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");
const placeDetailsRequest = document.querySelector('gmp-place-details-place-request');

เมื่อผู้ใช้คลิกปุ่มค้นหา ระบบจะเรียกใช้ configureFromSearchNearbyRequest และองค์ประกอบรายการสถานที่จะแสดงผลลัพธ์ (ระบบจะเพิ่มเครื่องหมายในฟังก์ชันตัวช่วย addMarkers) ข้อมูลโค้ดต่อไปนี้ยังแสดงโค้ดสําหรับการจัดการเหตุการณ์การคลิกในรายการสถานที่โดยใช้เหตุการณ์ gmp-placeselect ด้วย

placeDetails.addEventListener('gmp-load', (event) => {
    // Center the info window on the map.
    map.innerMap.fitBounds(placeDetails.place.viewport, { top: 500, left: 400 });
});
typeSelect.addEventListener('change', (event) => {
    // First remove all existing markers.
    for (marker in markers) {
        markers[marker].map = null;
    }
    markers = {};
    if (typeSelect.value) {
        placeList.style.display = 'block';
        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");
const placeDetailsRequest = document.querySelector('gmp-place-details-place-request');
let markers = {};
let infoWindow;
async function initMap() {
    await google.maps.importLibrary('places');
    const { LatLngBounds } = await google.maps.importLibrary('core');
    const { InfoWindow } = await google.maps.importLibrary('maps');
    const { spherical } = await google.maps.importLibrary('geometry');
    infoWindow = new InfoWindow;
    let marker;
    function getContainingCircle(bounds) {
        const diameter = spherical.computeDistanceBetween(bounds.getNorthEast(), bounds.getSouthWest());
        const calculatedRadius = diameter / 2;
        const cappedRadius = Math.min(calculatedRadius, 50000); // Radius cannot be more than 50000.
        return { center: bounds.getCenter(), radius: cappedRadius };
    }
    findCurrentLocation();
    map.innerMap.setOptions({
        mapTypeControl: false,
        clickableIcons: false,
    });
    placeDetails.addEventListener('gmp-load', (event) => {
        // Center the info window on the map.
        map.innerMap.fitBounds(placeDetails.place.viewport, { top: 500, left: 400 });
    });
    typeSelect.addEventListener('change', (event) => {
        // First remove all existing markers.
        for (marker in markers) {
            markers[marker].map = null;
        }
        markers = {};
        if (typeSelect.value) {
            placeList.style.display = 'block';
            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();
                }
                placeDetailsRequest.place = place.id;
                placeDetails.style.display = 'block';
                placeDetails.style.width = '350px';
                infoWindow.setOptions({
                    content: placeDetails,
                });
                infoWindow.open({
                    anchor: marker,
                    map: map.innerMap
                });
            });
            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: large;
      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;
      font-size: large
  }

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 style="display: none;"></gmp-place-list>
        </div>
      </div>
    </gmp-map>

    <gmp-place-details style="display: none;">
      <gmp-place-details-place-request></gmp-place-details-place-request>
      <gmp-place-all-content></gmp-place-all-content> 
    </gmp-place-details>

    <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>

ลองใช้ตัวอย่าง

ค้นหาตามคำขอข้อความ

ตัวอย่างนี้จะแสดงผลองค์ประกอบรายการสถานที่เพื่อตอบสนองต่อการค้นหาข้อความของผู้ใช้ เมื่อเลือกผลการค้นหาแล้ว หน้าต่างข้อมูลจะแสดงรายละเอียดสถานที่สำหรับสถานที่ที่เลือก หากต้องการเพิ่มองค์ประกอบรายการสถานที่ลงในแผนที่ ให้เพิ่มองค์ประกอบ 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="text-search-container">
      <input type="text" id="textSearchInput" placeholder="Enter text search...">
      <button id="textSearchButton">Search</button>
    </div>
    <div class="list-container">
      <gmp-place-list selectable style="display: none;"></gmp-place-list>
    </div>
  </div>
  <gmp-place-details style="display: none;">
    <gmp-place-details-place-request></gmp-place-details-place-request>
    <gmp-place-all-content></gmp-place-all-content> 
  </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');
const textSearchInput = document.getElementById('textSearchInput');
const textSearchButton = document.getElementById('textSearchButton');
const placeDetailsRequest = document.querySelector('gmp-place-details-place-request');

เมื่อเรียกใช้ฟังก์ชันการค้นหาหลังจากที่ผู้ใช้ป้อนข้อความค้นหา ระบบจะเรียกใช้ configureFromSearchByTextRequest และองค์ประกอบรายการสถานที่จะแสดงผลลัพธ์ (มีการเพิ่มเครื่องหมายในฟังก์ชันตัวช่วย addMarkers) ข้อมูลโค้ดต่อไปนี้แสดงโค้ดของฟังก์ชัน

async function searchByTextRequest() {
    if (textSearchInput.value !== "") {
        placeList.style.display = "block";
        placeList.configureFromSearchByTextRequest({
            locationRestriction: bounds,
            textQuery: textSearchInput.value,
        }).then(addMarkers);
        // Handle user selection in Place Details.
        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 placeDetails = document.querySelector("gmp-place-details");
let marker = document.querySelector('gmp-advanced-marker');
const textSearchInput = document.getElementById('textSearchInput');
const textSearchButton = document.getElementById('textSearchButton');
const placeDetailsRequest = document.querySelector('gmp-place-details-place-request');
let markers = {};
let infoWindow;
let center = { lat: 37.395641, lng: -122.077627 }; // Mountain View, CA.
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
    map.innerMap.panTo(center);
    map.innerMap.setZoom(14);
    map.innerMap.setOptions({
        mapTypeControl: false,
        clickableIcons: false,
    });
    // Fire when the Place Details Element is loaded.
    placeDetails.addEventListener('gmp-load', (event) => {
        // Center the info window on the map.
        map.innerMap.fitBounds(placeDetails.place.viewport, { top: 500, left: 400 });
    });
    // Handle clicks on the search button.
    textSearchButton.addEventListener('click', searchByTextRequest);
    // Handle enter key on text input.
    textSearchInput.addEventListener('keydown', (event) => {
        if (event.key === 'Enter') {
            searchByTextRequest();
        }
    });
}
async function searchByTextRequest() {
    if (textSearchInput.value !== "") {
        placeList.style.display = "block";
        placeList.configureFromSearchByTextRequest({
            locationRestriction: bounds,
            textQuery: textSearchInput.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();
    // First remove all existing markers.
    for (marker in markers) {
        markers[marker].map = null;
    }
    markers = {};
    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();
                }
                // Set the Place Details request to the selected place.
                placeDetailsRequest.place = place.id;
                placeDetails.style.display = "block";
                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);
        });
    }
}
initMap();

CSS

html,
  body {
      height: 100%;
      margin: 0;
  }

  gmp-map {
      box-sizing: border-box;
      height: 500px;
  }

  gmp-place-list {
    background-color: #fff;
    font-size: large
  }

  .overlay {
      position: relative;
      top: 20px;
      margin: 20px;
      width: 400px;
  }

  .list-container {
    height: 400px;
    overflow: auto;
    border-radius: 10px;
  }

  /* Styles for the text search container and its elements */
  .text-search-container {
    display: flex; /* Arrange input and button side-by-side */
    gap: 8px; /* Space between input and button */
    padding-bottom: 10px; /* Space below the search bar */
    border-bottom: 1px solid #eee; /* Separator line */
  }

  #textSearchInput {
    flex-grow: 1; /* Allow input to take available space */
    padding: 8px 12px;
    border: 1px solid #ccc;
    border-radius: 4px;
    font-size: 1rem;
  }

  #textSearchInput:focus {
    outline: none;
    border-color: #4a80e8; /* Highlight on focus */
    box-shadow: 0 0 0 2px rgba(74, 128, 232, 0.2);
  }

  #textSearchButton {
    padding: 8px 15px;
    background-color: #4a80e8; /* Example button color */
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 1rem;
    transition: background-color 0.2s ease-in-out;
  }

  #textSearchButton:hover {
    background-color: #356ac0; /* Darker shade on hover */
  }

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="text-search-container">
          <input type="text" id="textSearchInput" placeholder="Enter text search...">
          <button id="textSearchButton">Search</button>
        </div>
        <div class="list-container">
          <gmp-place-list selectable style="display: none;"></gmp-place-list>
        </div>
      </div>
      <gmp-place-details style="display: none;">
        <gmp-place-details-place-request></gmp-place-details-place-request>
        <gmp-place-all-content></gmp-place-all-content> 
      </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>

ลองใช้ตัวอย่าง