[Javascript][Google Map API] searchbox 이용하여 검색 구현

Kim Tae Won·2021년 12월 27일
1
post-thumbnail

해당 공식 문서를 주로 참고하였습니다[places api-place search]
https://developers.google.com/maps/documentation/javascript/examples/places-searchbox?hl=ko

검색 구현

  • 지도 자동완성 검색 기능을 구현하기 위해선 크게 2가지 방법이 있다
  1. Autocomplete
  2. SearchBox

처음에는 Autocomplete를 이용해 구현을 하였다.
https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete?hl=ko
위 사이트의 예시대로 javascript, css, html을 적용하면 손쉽게 가능한 것이 장점이다. 아래는 자바스크립트 코드이다. 나머지 코드는 위 사이트에서 보면 된다.

// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40.749933, lng: -73.98633 },
    zoom: 13,
    mapTypeControl: false,
  });
  const card = document.getElementById("pac-card");
  const input = document.getElementById("pac-input");
  const biasInputElement = document.getElementById("use-location-bias");
  const strictBoundsInputElement = document.getElementById("use-strict-bounds");
  const options = {
    fields: ["formatted_address", "geometry", "name"],
    strictBounds: false,
    types: ["establishment"],
  };

  map.controls[google.maps.ControlPosition.TOP_LEFT].push(card);

  const autocomplete = new google.maps.places.Autocomplete(input, options);

  // Bind the map's bounds (viewport) property to the autocomplete object,
  // so that the autocomplete requests use the current map bounds for the
  // bounds option in the request.
  autocomplete.bindTo("bounds", map);

  const infowindow = new google.maps.InfoWindow();
  const infowindowContent = document.getElementById("infowindow-content");

  infowindow.setContent(infowindowContent);

  const marker = new google.maps.Marker({
    map,
    anchorPoint: new google.maps.Point(0, -29),
  });

  autocomplete.addListener("place_changed", () => {
    infowindow.close();
    marker.setVisible(false);

    const place = autocomplete.getPlace();

    if (!place.geometry || !place.geometry.location) {
      // User entered the name of a Place that was not suggested and
      // pressed the Enter key, or the Place Details request failed.
      window.alert("No details available for input: '" + place.name + "'");
      return;
    }

    // If the place has a geometry, then present it on a map.
    if (place.geometry.viewport) {
      map.fitBounds(place.geometry.viewport);
    } else {
      map.setCenter(place.geometry.location);
      map.setZoom(17);
    }

    marker.setPosition(place.geometry.location);
    marker.setVisible(true);
    infowindowContent.children["place-name"].textContent = place.name;
    infowindowContent.children["place-address"].textContent =
      place.formatted_address;
    infowindow.open(map, marker);
  });

  // Sets a listener on a radio button to change the filter type on Places
  // Autocomplete.
  function setupClickListener(id, types) {
    const radioButton = document.getElementById(id);

    radioButton.addEventListener("click", () => {
      autocomplete.setTypes(types);
      input.value = "";
    });
  }

  setupClickListener("changetype-all", []);
  setupClickListener("changetype-address", ["address"]);
  setupClickListener("changetype-establishment", ["establishment"]);
  setupClickListener("changetype-geocode", ["geocode"]);
  setupClickListener("changetype-cities", ["(cities)"]);
  setupClickListener("changetype-regions", ["(regions)"]);
  biasInputElement.addEventListener("change", () => {
    if (biasInputElement.checked) {
      autocomplete.bindTo("bounds", map);
    } else {
      // User wants to turn off location bias, so three things need to happen:
      // 1. Unbind from map
      // 2. Reset the bounds to whole world
      // 3. Uncheck the strict bounds checkbox UI (which also disables strict bounds)
      autocomplete.unbind("bounds");
      autocomplete.setBounds({ east: 180, west: -180, north: 90, south: -90 });
      strictBoundsInputElement.checked = biasInputElement.checked;
    }

    input.value = "";
  });
  strictBoundsInputElement.addEventListener("change", () => {
    autocomplete.setOptions({
      strictBounds: strictBoundsInputElement.checked,
    });
    if (strictBoundsInputElement.checked) {
      biasInputElement.checked = strictBoundsInputElement.checked;
      autocomplete.bindTo("bounds", map);
    }

    input.value = "";
  });
}
  • 하지만 Autocomplete의 경우 가장 큰 단점은 enter키 입력 시에 대응하기가 어렵다는 점이다.
  • 실제로 검색어를 입력 후 enter키를 입력 시에 아래와 같이 나타나게 된다
  • 수정을 위해 여러가지 에러처리 등을 해보았지만, 결국은 searchBox를 이용하게 되었다

Search Box를 이용하여 검색기능 구현하기

https://developers.google.com/maps/documentation/javascript/examples/places-searchbox?hl=ko

위 링크가 Search Box를 이용하는 예제인데, autocomplete와 크게 다르지 않다.

  • 하지만 위 예제의 경우 enter 클릭 시 자동완성이 되는 모든 리스트가 지도상에 마커로 나타나게 된다

  • 이러한 기능은 필요가 없기 때문에 필요한 부분만 가져와 사용하였다

  1. 먼저 searchbox를 연결해야한다
const searchBox = new google.maps.places.SearchBox(input);
  1. places가 변경이 되면 해당 places 중 첫번째 값을 가져와 지도의 위치를 이동시킨다
    (enter 클릭 시 places가 변경되어, 해당 이벤트가 발생하게 된다)
searchBox.addListener("places_changed", () => {
  //이벤트 발생 시 getPlaces()를 통해 place객체 배열을 가져온다
  const places = searchBox.getPlaces();
  //검색 결과가 없는 경우이다
  if (places.length == 0) {
    return;
  }
  //첫 번째 값을 가져와 사용한다
  const place = places[0];
  //input에 해당 장소의 이름을 출력해준다
  input.value = place.name;
  //해당 장소가 위치 정보가 없는 경우이다
  if (!place.geometry || !place.geometry.location) {
    console.log("Returned place contains no geometry");
    return;
  }
  //검색한 장소로 지도를 이동시킨다
  if (place.geometry.viewport) {
    map.fitBounds(place.geometry.viewport);
  } else {
    map.setCenter(place.geometry.location);
    map.setZoom(17);
  }
});
  1. 위 코드에 여러가지를 추가하여 사용하면 된다. 필자는 info window를 사용하여 검색을 하면 해당 장소의 정보가 뜨도록 하였다.
const infowindow = new google.maps.InfoWindow();
const infowindowContent = document.getElementById("infowindow-content");

infowindow.setContent(infowindowContent);
const marker = new google.maps.Marker({
  map,
  anchorPoint: new google.maps.Point(0, -29),
});

searchBox.addListener("places_changed", () => {
  //위 코드 생략
  
  marker.setPosition(place.geometry.location);
  marker.setVisible(false);
  map.setZoom(15);
  infowindowContent.children["place-name"].textContent = place.name;
  infowindowContent.children["place-address"].textContent = place.formatted_address;
  infowindow.open(map, marker);
});

최종 결과물

  • 검색 시에 해당 위치로 지도를 이동시키고 info-window를 띄웠다
  • 위에 올린 코드는 핵심만 올린 것이고, 나머지 리스팅과 같은 코드는 올리지 않음
profile
꿈이 너무나 큰 평범한 컴공 대딩에서 취업 성공!

0개의 댓글