Elemen Place Search

Elemen HTML PlaceSearchElement merender hasil penelusuran tempat dalam daftar. Ada dua cara untuk mengonfigurasi elemen gmp-place-search:

Menelusuri permintaan terdekat

Pilih jenis tempat dari menu untuk melihat hasil penelusuran terdekat untuk jenis tempat tersebut.

Contoh berikut merender elemen Place Search sebagai respons terhadap penelusuran di sekitar. Untuk mempermudah, hanya tiga jenis tempat yang tercantum: kafe, restoran, dan SPKLU. Saat hasil dipilih, penanda dan PlaceDetailsCompactElement ditampilkan untuk tempat yang dipilih. Untuk menambahkan elemen Penelusuran Tempat ke peta, tambahkan elemen gmp-place-search yang berisi elemen gmp-place-nearby-search-request ke halaman HTML seperti yang ditunjukkan dalam cuplikan berikut:

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

Beberapa panggilan querySelector digunakan untuk memilih elemen halaman untuk interaksi:

  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");

Saat pengguna memilih jenis tempat dari menu, elemen gmp-place-nearby-search-request akan diperbarui, dan elemen Penelusuran Tempat akan menampilkan hasilnya (penanda ditambahkan dalam fungsi helper 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 });
  }
}

Lihat contoh kode lengkap

 
   

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>
 

Permintaan penelusuran menurut teks

Masukkan istilah penelusuran di kolom input, lalu klik tombol Telusuri untuk mendapatkan daftar tempat yang cocok dengan istilah tersebut.

Contoh ini merender elemen Penelusuran Tempat sebagai respons terhadap penelusuran teks pengguna. Saat hasil dipilih, penanda dan PlaceDetailsCompactElement ditampilkan untuk tempat yang dipilih. Untuk menambahkan elemen Penelusuran Tempat ke peta, tambahkan elemen gmp-place-search yang berisi elemen gmp-place-search-text-search-request ke halaman HTML seperti yang ditunjukkan dalam cuplikan berikut:

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

Beberapa panggilan querySelector digunakan untuk memilih elemen halaman untuk interaksi:

  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");

Saat fungsi penelusuran dijalankan setelah pengguna memasukkan kueri penelusuran, elemen gmp-place-text-search-request akan diperbarui, dan elemen Place Search akan menampilkan hasilnya (penanda ditambahkan dalam fungsi helper 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 });
  }
}

Lihat contoh kode lengkap

 
   

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>