Google Maps API 활용

Jiwon·2021년 3월 24일
0

API

목록 보기
2/2

저번에 sdk까지 설치하고 프로젝트까지 권한을 주었다.
이번에는 직접 Google Maps API를 이용하여 지도를 띄우고, 장소 검색까지 해보겠다.

내가 필요한 기능은 '동물병원' 찾기

Maps API 중 place 기능을 이용했다.

먼저 jsp 안에 script 문으로 구글 맵과 place 기능을 불러온다.

<script src="https://maps.googleapis.com/maps/api/js?key=[api_key]&callback=initMap&libraries=places&v=weekly&radius=5000"></script>

여기서 [api_key] 부분에 자신의 api key 를 넣어주면 된다.

google에서 제공해주는 샘플 코드를 이용해서 작성했는데 첫 위치를 한국으로 잡고 싶어서 kr을 추가했다.

<script>
      // This example uses the autocomplete feature of the Google Places API.
      // It allows the user to find all hotels in a given place, within a given
      // country. It then displays markers for all the hotels returned,
      // with on-click details for each hotel.
      // 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">
      let map;
      let places;
      let infoWindow;
      let markers = [];
      let autocomplete;
      const countryRestrict = { country: "kr" };
      const MARKER_PATH =
        "https://developers.google.com/maps/documentation/javascript/images/marker_green";
      const hostnameRegexp = new RegExp("^https?://.+?/");
      const countries = {
        
        
        //(코드 생략)
     
        
        kr: {
          center : { lat: 37.5642135 ,lng: 127.0016985 },
          zoom: 16,
        },
        
      };

initMap 함수에서도 kr로 위치를 잡아준다.

function initMap() {
        map = new google.maps.Map(document.getElementById("map"), {
          zoom: countries["kr"].zoom,
          center: countries["kr"].center,
          mapTypeControl: true,
          panControl: true,
          zoomControl: true,
          streetViewControl: true,
        });
        infoWindow = new google.maps.InfoWindow({
          content: document.getElementById("info-content"),
        });
        // Create the autocomplete object and associate it with the UI input control.
        // Restrict the search to the default country, and to place type "cities".
        autocomplete = new google.maps.places.Autocomplete(
          document.getElementById("autocomplete"),
          {
            types: ["(cities)"],
            componentRestrictions: countryRestrict,
          }
        );
        places = new google.maps.places.PlacesService(map);
        autocomplete.addListener("place_changed", onPlaceChanged);
        // Add a DOM event listener to react when the user selects a country.
        document
          .getElementById("country")
          .addEventListener("change", setAutocompleteCountry);
      }

그리고 내가 도시를 입력했을 때,
자동으로 '동물병원'이 검색되도록 google에서 제공해주는 type을 지정한다.

// Search for hotels in the selected city, within the viewport of the map.
      function search() {
        const search = {
          bounds: map.getBounds(),
          types: ["veterinary_care"],
        };
        places.nearbySearch(search, (results, status, pagination) => {
          if (status === google.maps.places.PlacesServiceStatus.OK && results) {
            clearResults();
            clearMarkers();

            // Create a marker for each hotel found, and
            // assign a letter of the alphabetic to each marker icon.
            for (let i = 0; i < results.length; i++) {
              const markerLetter = String.fromCharCode(
                "A".charCodeAt(0) + (i % 26)
              );
              const markerIcon = MARKER_PATH + markerLetter + ".png";
              // Use marker animation to drop the icons incrementally on the map.
              markers[i] = new google.maps.Marker({
                position: results[i].geometry.location,
                animation: google.maps.Animation.DROP,
                icon: markerIcon,
              });
              // If the user clicks a hotel marker, show the details of that hotel
              // in an info window.
              markers[i].placeResult = results[i];
              google.maps.event.addListener(
                markers[i],
                "click",
                showInfoWindow
              );
              setTimeout(dropMarker(i), i * 100);
              addResult(results[i], i);
            }
          }
        });
      }

const search = {
bounds: map.getBounds(),
types: ["veterinary_care"],
};

이 부분이 핵심이다.
자신이 원하는 type을 정해주면 되는데
google에서 제공해주는 타입만 검색 가능하므로 미리 조사해두면 나중에 고생을 덜 한다.
나는 그걸 몰랐어서 구글에 직접 메일을 보내고 답변을 통해 알게 되었다.

https://developers.google.com/maps/documentation/places/web-service/supported_types?hl=fi

나머지 샘플코드는 고치지 않아도 되므로
body 부분 안에

<div class="hospital-search">
      <div id="findhospital">Find hospital in:</div>

      <div id="locationField">
        <input id="autocomplete" placeholder="Enter a city" type="text" />
      </div>

      <div id="controls">
        <select id="country">
          <!--코드 생략-->
          <option value="kr" selected>Korea</option>
        </select>
      </div>
    </div>

    <div id="map" style="height: 480px; position: relative; overflow: hidden;"></div>

나머지 list 부분은 수정하지 않았다.

화면을 구동하면 구글 맵이 뜰거고 검색창에 seoul 이라고 입력하면 밑에 자동으로 대한민국 서울이라고 뜰거다.
누르게 되면

오른쪽에 동물병원 리스트가 뜬 것을 볼 수 있고, 리스트 항목을 눌렀을 때 정보를 볼 수 있다.

하지만 나는 도시보다는 현재 위치에서 동물병원을 검색하고 싶었으며, 리스트 항목이 적어 이 방법을 포기하고 다른 방법으로 접근하였다.
다음 글로 작성할 예정,,

// 총 코드 (부트스트랩 제거)
// map.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Map </title>
    
    
 
 <!-- test2 -->
 
     <style type="text/css">
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      }

      /* Optional: Makes the sample page fill the window. */
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }

      body {
        padding: 0 !important;
      }

      table {
        font-size: 12px;
      }

      .hospital-search {
        -webkit-box-align: center;
        -ms-flex-align: center;
        align-items: center;
        background: #fff;
        display: -webkit-box;
        display: -ms-flexbox;
        display: flex;
        left: 0;
        position: absolute;
        top: 0;
        width: 880px;
        z-index: 1;
      }

      #map {
        margin-top: 40px;
        width: 880px;
      }

      #listing {
        position: absolute;
        width: 200px;
        height: 490px;
        overflow: auto;
        left: 630px;
        top: 0px;
        cursor: pointer;
        overflow-x: hidden;
      }

      #findhospitals {
        font-size: 14px;
      }

      #locationField {
        -webkit-box-flex: 1 1 190px;
        -ms-flex: 1 1 190px;
        flex: 1 1 190px;
        margin: 0 8px;
      }

      #controls {
        -webkit-box-flex: 1 1 140px;
        -ms-flex: 1 1 140px;
        flex: 1 1 140px;
      }

      #autocomplete {
        width: 100%;
      }

      #country {
        width: 100%;
      }

      .placeIcon {
        width: 20px;
        height: 34px;
        margin: 4px;
      }

      .hospitalIcon {
        width: 24px;
        height: 24px;
      }

      #resultsTable {
        border-collapse: collapse;
        width: 240px;
      }

      #rating {
        font-size: 13px;
        font-family: Arial Unicode MS;
      }

      .iw_table_row {
        height: 18px;
      }

      .iw_attribute_name {
        font-weight: bold;
        text-align: right;
      }

      .iw_table_icon {
        text-align: right;
      }
    </style>
    <script>
      // This example uses the autocomplete feature of the Google Places API.
      // It allows the user to find all hospitals in a given place, within a given
      // country. It then displays markers for all the hospitals returned,
      // with on-click details for each hospital.
      // 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">
      let map;
      let places;
      let infoWindow;
      let markers = [];
      let autocomplete;
      const countryRestrict = { country: "kr" };
      const MARKER_PATH =
        "https://developers.google.com/maps/documentation/javascript/images/marker_green";
      const hostnameRegexp = new RegExp("^https?://.+?/");
      const countries = {
        au: {
          center: { lat: -25.3, lng: 133.8 },
          zoom: 4,
        },
        br: {
          center: { lat: -14.2, lng: -51.9 },
          zoom: 3,
        },
        ca: {
          center: { lat: 62, lng: -110.0 },
          zoom: 3,
        },
        fr: {
          center: { lat: 46.2, lng: 2.2 },
          zoom: 5,
        },
        de: {
          center: { lat: 51.2, lng: 10.4 },
          zoom: 5,
        },
        mx: {
          center: { lat: 23.6, lng: -102.5 },
          zoom: 4,
        },
        nz: {
          center: { lat: -40.9, lng: 174.9 },
          zoom: 5,
        },
        it: {
          center: { lat: 41.9, lng: 12.6 },
          zoom: 5,
        },
        za: {
          center: { lat: -30.6, lng: 22.9 },
          zoom: 5,
        },
        es: {
          center: { lat: 40.5, lng: -3.7 },
          zoom: 5,
        },
        pt: {
          center: { lat: 39.4, lng: -8.2 },
          zoom: 6,
        },
        us: {
          center: { lat: 37.1, lng: -95.7 },
          zoom: 3,
        },
        uk: {
          center: { lat: 54.8, lng: -4.6 },
          zoom: 5,
        },
        
        kr: {
          center : { lat: 37.5642135 ,lng: 127.0016985 },
          zoom: 16,
        },
        
      };

      function initMap() {
        map = new google.maps.Map(document.getElementById("map"), {
          zoom: countries["kr"].zoom,
          center: countries["kr"].center,
          mapTypeControl: true,
          panControl: true,
          zoomControl: true,
          streetViewControl: true,
        });
        infoWindow = new google.maps.InfoWindow({
          content: document.getElementById("info-content"),
        });
        // Create the autocomplete object and associate it with the UI input control.
        // Restrict the search to the default country, and to place type "cities".
        autocomplete = new google.maps.places.Autocomplete(
          document.getElementById("autocomplete"),
          {
            types: ["(cities)"],
            componentRestrictions: countryRestrict,
          }
        );
        places = new google.maps.places.PlacesService(map);
        autocomplete.addListener("place_changed", onPlaceChanged);
        // Add a DOM event listener to react when the user selects a country.
        document
          .getElementById("country")
          .addEventListener("change", setAutocompleteCountry);
      }

      // When the user selects a city, get the place details for the city and
      // zoom the map in on the city.
      function onPlaceChanged() {
        const place = autocomplete.getPlace();

        if (place.geometry && place.geometry.location) {
          map.panTo(place.geometry.location);
          map.setZoom(15);
          search();
        } else {
          document.getElementById("autocomplete").placeholder = "Enter a city";
        }
      }

      // Search for hospitals in the selected city, within the viewport of the map.
      function search() {
        const search = {
          bounds: map.getBounds(),
          types: ["veterinary_care"],
        };
        places.nearbySearch(search, (results, status, pagination) => {
          if (status === google.maps.places.PlacesServiceStatus.OK && results) {
            clearResults();
            clearMarkers();

            // Create a marker for each hospital found, and
            // assign a letter of the alphabetic to each marker icon.
            for (let i = 0; i < results.length; i++) {
              const markerLetter = String.fromCharCode(
                "A".charCodeAt(0) + (i % 26)
              );
              const markerIcon = MARKER_PATH + markerLetter + ".png";
              // Use marker animation to drop the icons incrementally on the map.
              markers[i] = new google.maps.Marker({
                position: results[i].geometry.location,
                animation: google.maps.Animation.DROP,
                icon: markerIcon,
              });
              // If the user clicks a hospital marker, show the details of that hospital
              // in an info window.
              markers[i].placeResult = results[i];
              google.maps.event.addListener(
                markers[i],
                "click",
                showInfoWindow
              );
              setTimeout(dropMarker(i), i * 100);
              addResult(results[i], i);
            }
          }
        });
      }

      function clearMarkers() {
        for (let i = 0; i < markers.length; i++) {
          if (markers[i]) {
            markers[i].setMap(null);
          }
        }
        markers = [];
      }

      // Set the country restriction based on user input.
      // Also center and zoom the map on the given country.
      function setAutocompleteCountry() {
        const country = document.getElementById("country").value;

        if (country == "all") {
          autocomplete.setComponentRestrictions({ country: [] });
          map.setCenter({ lat: 15, lng: 0 });
          map.setZoom(2);
        } else {
          autocomplete.setComponentRestrictions({ country: country });
          map.setCenter(countries[country].center);
          map.setZoom(countries[country].zoom);
        }
        clearResults();
        clearMarkers();
      }

      function dropMarker(i) {
        return function () {
          markers[i].setMap(map);
        };
      }

      function addResult(result, i) {
        const results = document.getElementById("results");
        const markerLetter = String.fromCharCode("A".charCodeAt(0) + (i % 26));
        const markerIcon = MARKER_PATH + markerLetter + ".png";
        const tr = document.createElement("tr");
        tr.style.backgroundColor = i % 2 === 0 ? "#F0F0F0" : "#FFFFFF";

        tr.onclick = function () {
          google.maps.event.trigger(markers[i], "click");
        };
        const iconTd = document.createElement("td");
        const nameTd = document.createElement("td");
        const icon = document.createElement("img");
        icon.src = markerIcon;
        icon.setAttribute("class", "placeIcon");
        icon.setAttribute("className", "placeIcon");
        const name = document.createTextNode(result.name);
        iconTd.appendChild(icon);
        nameTd.appendChild(name);
        tr.appendChild(iconTd);
        tr.appendChild(nameTd);
        results.appendChild(tr);
      }

      function clearResults() {
        const results = document.getElementById("results");

        while (results.childNodes[0]) {
          results.removeChild(results.childNodes[0]);
        }
      }

      // Get the place details for a hospital. Show the information in an info window,
      // anchored on the marker for the hospital that the user selected.
      function showInfoWindow() {
        const marker = this;
        places.getDetails(
          { placeId: marker.placeResult.place_id },
          (place, status) => {
            if (status !== google.maps.places.PlacesServiceStatus.OK) {
              return;
            }
            infoWindow.open(map, marker);
            buildIWContent(place);
          }
        );
      }

      // Load the place information into the HTML elements used by the info window.
      function buildIWContent(place) {
        document.getElementById("iw-icon").innerHTML =
          '<img class="hospitalIcon" ' + 'src="' + place.icon + '"/>';
        document.getElementById("iw-url").innerHTML =
          '<b><a href="' + place.url + '">' + place.name + "</a></b>";
        document.getElementById("iw-address").textContent = place.vicinity;

        if (place.formatted_phone_number) {
          document.getElementById("iw-phone-row").style.display = "";
          document.getElementById("iw-phone").textContent =
            place.formatted_phone_number;
        } else {
          document.getElementById("iw-phone-row").style.display = "none";
        }

        // Assign a five-star rating to the hospital, using a black star ('&#10029;')
        // to indicate the rating the hospital has earned, and a white star ('&#10025;')
        // for the rating points not achieved.
        if (place.rating) {
          let ratingHtml = "";

          for (let i = 0; i < 5; i++) {
            if (place.rating < i + 0.5) {
              ratingHtml += "&#10025;";
            } else {
              ratingHtml += "&#10029;";
            }
            document.getElementById("iw-rating-row").style.display = "";
            document.getElementById("iw-rating").innerHTML = ratingHtml;
          }
        } else {
          document.getElementById("iw-rating-row").style.display = "none";
        }

        // The regexp isolates the first part of the URL (domain plus subdomain)
        // to give a short URL for displaying in the info window.
        if (place.website) {
          let fullUrl = place.website;
          let website = String(hostnameRegexp.exec(place.website));

          if (!website) {
            website = "http://" + place.website + "/";
            fullUrl = website;
          }
          document.getElementById("iw-website-row").style.display = "";
          document.getElementById("iw-website").textContent = website;
        } else {
          document.getElementById("iw-website-row").style.display = "none";
        }
      }
    </script>


      
 
 
</head>

<body>
      <h2>Map</h2>
                       
        <!-- Hero Area End -->
        <!-- ================ contact section start ================= -->
        <section class="contact-section">
                <div class="container">
                   <div class="d-none d-sm-block mb-5 pb-4">
                    	<div id="MapID" style="height: 480px; position: relative; overflow: hidden;">
     <div class="hospital-search">
      <div id="findhospital">Find hospital in:</div>

      <div id="locationField">
        <input id="autocomplete" placeholder="Enter a city" type="text" />
      </div>

      <div id="controls">
        <select id="country">
          <!-- 코드생략 -->
          <option value="kr" selected>Korea</option>
        </select>
      </div>
    </div>

    <div id="map" style="height: 480px; position: relative; overflow: hidden;"></div>

    <div id="listing">
      <table id="resultsTable">
        <tbody id="results"></tbody>
      </table>
    </div>

    <div style="display: none">
      <div id="info-content">
        <table>
          <tr id="iw-url-row" class="iw_table_row">
            <td id="iw-icon" class="iw_table_icon"></td>
            <td id="iw-url"></td>
          </tr>
          <tr id="iw-address-row" class="iw_table_row">
            <td class="iw_attribute_name">Address:</td>
            <td id="iw-address"></td>
          </tr>
          <tr id="iw-phone-row" class="iw_table_row">
            <td class="iw_attribute_name">Telephone:</td>
            <td id="iw-phone"></td>
          </tr>
          <tr id="iw-rating-row" class="iw_table_row">
            <td class="iw_attribute_name">Rating:</td>
            <td id="iw-rating"></td>
          </tr>
          <tr id="iw-website-row" class="iw_table_row">
            <td class="iw_attribute_name">Website:</td>
            <td id="iw-website"></td>
          </tr>
        </table>
      </div>
    </div>
  
    </div>
  </div>
                    
    
    
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
	
    <script src="https://maps.googleapis.com/maps/api/js?key=[api_key]&callback=initMap&libraries=places&v=weekly&radius=5000"></script>

    </body>
</html>
profile
과연 나는 ?

0개의 댓글