본문 바로가기

3.구현/HTML5&Javascript

[javascript] Map Service 사용

들어가기

웹 기반 지도 서비스 제공되는 플랫폼을 비교 분석해보았다. 대표적인 웹기반 지도 서비스를 제공하는 Google, Naver, Kakao 서비스들을 비교분석해보았다. 모바일 기반 맵을 다루지 않았고 일반적인 웹 기반 맵을 다루었다. 그외 다양한 맵 서비스와 라이브러리가 있지만 가장 전통적인 방식의 Javascript 라이브리러를 활용했다. 여기 작성된 내용은 2024/01/23 기준으로 확인했다.

작성자: ospace114@empal.com, http://ospace.tistory.com/

사전작업

맵 서비스 사용하기 전에 사전에 해야할 작업이 있다. 키를 발급 받는 작업이 필요하다.

Google

Google Map을 사용하기 위해서는 API 키가 필요하다. Google Maps Platform에 등록하고 API를 발급받아야 한다. 발급 받는 방법은 조금 까다롭지만 크게 어렵지는 않다. 가입할 때에 결재카드번호가 필요하다.

Maps JavaScript API를 사용했다. 로컬 파일도 로딩 가능하다.(한 개 맵만 사용)

Naver

애플리케이션 등록하여 클라이언트 아이디 발급받아야 한다. 가입할 때에 결재카드번호가 필요하다.

https://navermaps.github.io/maps.js.ncp/docs/tutorial-1-Getting-Client-ID.html

사용할 서비스는 Web Dynamic Map을 선택했다. 로컬 파일도 테스트 가능하다.

Kakao

개발자 등록하고 애플리케이션 등록하여 키를 발급해야 한다. 결재카드 번호는 필요 없다.

https://apis.map.kakao.com/web/guide/

사이드 도메인에 플랫폼 등록(localhost)하여야 테스트 가능하다. 웹 서버를 별도 실행되어야 하고 앞에 등록된 사이트 도메인에서만 접속이 가능하다.

기본 맵

먼저 가장 기본이 되는 맵부터 살펴보자. 단지 특정 위치에서 맵을 표시한다.

Google

구글 맵을 작성해보자. 사용할 API는 “https://maps.googleapis.com/maps/api/js”를 사용한다.

<!DOCTYPE html>
<html>
  <head>
    <title>Google Map</title>
    <meta charset="utf-8" />
    <style>
      #map {
        height: 100%;
      }
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      var map;
      function initMap() {
        map = new google.maps.Map(document.getElementById("map"), {
          center: { lat: 33.368, lng: 126.567 },
          zoom: 11,
        });
      }
    </script>
    <script src="https://maps.googleapis.com/maps/api/js?key={API_KEY}&callback=initMap"></script>
  </body>
</html>

callback에 로딩이 완료되면 호출할 콜백함수를 지정하면 된다. key에 {API_KEY} 대신에 발급 받은 API 키를 입력해야 한다. 로딩이 정상적으로 완료되면 initMap 콜백 함수 호출되고 맵이 화면에 아래와 같이 출력된다.

가장 기본 화면이고, 다른 서비스에 비해 좀더 많은 지리정보가 표시된다.

Naver

네이버 맵을 작성해보자. 사용할 API는 “https://oapi.map.naver.com/openapi/v3/maps.js”이다. 이전에는 “https://openapi.map.naver.com”에서 변경되었고, clientId에서 ncpClientId으로 변경되었다.

<!DOCTYPE html>
<html>
  <head>
    <title>Naver Map</title>
    <meta charset="utf-8" />
    <style>
      #map {
        height: 100%;
      }
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script
      type="text/javascript"
      src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpClientId={API_KEY}&callback=initMap"
    ></script>
    <script>
      var map;
      function initMap() {
        var mapOptions = {
          center: new naver.maps.LatLng(33.368, 126.567),
          zoom: 11,
        };
        map = new naver.maps.Map("map", mapOptions);
      }
    </script>
  </body>
</html>

API 호출 스크립트가 먼저 위치해야 한다. 그리고 ncpClient에 {API_KEY} 대신에 발급받은 API 키를 입력해야 한다. 그리고 callback에 로딩이 완료되면 호출할 함수를 지정한다. 로딩이 정상적으로 완료되면 initMap()이 호출되고 아래와 같이 맵이 출력된다. 구글 맵보다 지리정보가 적지만 카카오 맵보다는 조금 많이 표시된다.

Kakao

카카오 맵을 작성해보자. 사용할 API는 “http://dapi.kakao.com/v2/maps/sdk.js”이다.

<!DOCTYPE html>
<html>
  <head>
    <title>Daum Map</title>
    <meta charset="utf-8" />
    <style>
      #map {
        height: 100%;
      }
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script
      type="text/javascript"
      src="http://dapi.kakao.com/v2/maps/sdk.js?appkey={API_KEY}"
    ></script>
    <script>
      var mapOptions = {
        center: new kakao.maps.LatLng(33.368, 126.567),
        level: 9,
      };
      var map = new kakao.maps.Map(document.getElementById("map"), mapOptions);
    </script>
  </body>
</html>

API 스크립트 호출이 먼저 나와야 한다. 그리고 appkey의 {API_KEY}을 발급받은 키로 바꿔야 한다. 카카오맵은 콜백 함수를 사용하는 방식은 아니고 바로 사용할 수 있다. 성공적으로 실행이 되면 아래와 같은 지도가 화면에 표시된다. 다른 곳보다 표시되는 지리정보는 가장 적다.

Info Window 비교

지도에 정보 표시하는 윈도우를 출력하는 예제이다. 특정 위치에 풍선말 처럼 입력한 텍스트가 출력되는 기능이다. 아래 코드에서 사용하는 createInfoWinContent()은 단순 문자열 리턴되는 함수이다. 각 플랫폼 별로 객체에서 정보를 추출해서 포멧팅해서 리턴하는 함수이다.

Google

구글맵의 Info Window 출력하는 코드를 보자.

var map;
function initMap() {
    var cheju = new google.maps.LatLng(33.368, 126.567);
    map = new google.maps.Map(document.getElementById('map'), {
        center: cheju,
        zoom: 12
    });
    var infoWin = new google.maps.InfoWindow();
    infoWin.setContent(createInfoWinContent(cheju, map.getZoom()));
    infoWin.setPosition(cheju);
    infoWin.open(map);
}

InfoWindow 객체를 만들고 setContent()을 통해서 화면에 출력할 문자열을 입력받는다. HTML 태그도 사용 가능하다. 그리고 setPosition()으로 맵에 출력할 위치를 지정한다. 그리고 open()을 통해 아래 이미지 처럼 맵에 출력된다.

Naver

네이버 맵의 Info Window 출력하는 코드를 보자.

var map;
function initMap() {
    var cheju = new naver.maps.LatLng(33.368, 126.567);
    var mapOptions = {
        center: cheju,
        zoom: 7
    };
    map = new naver.maps.Map('map', mapOptions);
    var infoWin = new naver.maps.InfoWindow();
    infoWin.setContent(createInfoWinContent(cheju, map.getZoom()));
    infoWin.setPosition(cheju);
    infoWin.open(map);
}

구글과 비슷하게 InfoWindow 객체를 만들고 setContent()와 setPositon()으로 출력할 내용과 출력할 맵 위치를 입력받는다. 그리고 open()으로 아래와 같은 화면이 맵에 출력된다. 구글 방식과 거의 동일하다. 단지 화면 UI가 조금 다르다.

Kakao

카카오의 Info Window 출력하는 코드를 보자.

var cheju = new daum.maps.LatLng(33.368, 126.567);
var mapOptions = { 
    center: cheju,
    level: 8
};
var map = new daum.maps.Map(document.getElementById('map'), mapOptions); 
var infoWin = new daum.maps.InfoWindow({
    map: map,
    position: cheju,
    content: createInfoWinContent(cheju, map.getLevel()),
    removable: false
});

InfoWindow 객체를 만들면서 사용할 맵 객체, 위치, 표시할 내용을 입력한다. removable을 true로 하면 풍선말에 닫힘버튼이 생긴다. 추가 호출 작업 필요 없이 아래와 처럼 맵에 출력된다.

위치 서비스

위치 서비스는 현재 접속한 사용자의 위치를 확인해서 맵에 표시하는 기능이다. 이는 브라우저에서 위지정보 접근허용을 한 경우에만 정상적으로 작동한다.

Google

구글 맵에서 위시 서비스에 대한 코드를 살펴보자.

function initMap() {
    var map = new google.maps.Map(document.getElementById('map'), {
      center: {lat: 33.368, lng: 126.567},
      zoom: 11
    });
    var infoWin = new google.maps.InfoWindow;
    var geo = navigator.geolocation;
    if(geo) {
        geo.getCurrentPosition(function(pos) {
            var p = {lat: pos.coords.latitude, lng:pos.coords.longitude};
            infoWin.setPosition(p);
            infoWin.setContent('Location found.');
            infoWin.open(map);
            map.setCenter(p);

        });
    }
}

navigator.geolocation로 접근을 한다. 브라우저에서 위치정보를 획득에 성공했다면 현재 위치 정보를 가져오고 좌표값을 추출해서 앞에서 사용했던 InfoWindow을 사용해 해당 위치를 화면에 표시한다. 그리고 마지막으로 setCenter()로 접속 위치를 맵의 가운데에 표시한다.

Naver

네이버 맵에서 위시 서비스에 대한 코드를 살펴보자.

function initMap() {
    var map = new naver.maps.Map('map', {
      center: new naver.maps.LatLng(33.368, 126.567),
      zoom: 11
    });

    var infoWin = new naver.maps.InfoWindow();
    var geo = navigator.geolocation;
    if(geo) {
        geo.getCurrentPosition(function(pos) {
            var p = {lat: pos.coords.latitude, lng:pos.coords.longitude};
            infoWin.setPosition(p);
            infoWin.setContent('Location found.');
            infoWin.open(map);
            map.setCenter(p);

        });
    }
}

navigator.geolocation으로 접근해서 현재 접속한 위치 정보를 가져오는 부분은 동일하다. 그리고 InfoWindow도 동일한 방식이므로 앞의 구글맵 코드와 유사하다. 그리고 setCenter() 호출도 동일하다. google을 naver로만 바꾸기만 해도 동작할 듯 하다. 물론 세세한 부분이 조금 틀리다.

Kakao

카카오 맵에서 위시 서비스에 대한 코드를 살펴보자.

var mapOptions = { 
    center: new daum.maps.LatLng(33.368, 126.567),
    level: 7
};
var map = new daum.maps.Map(document.getElementById('map'), mapOptions); 
var infoWin = new daum.maps.InfoWindow();
var geo = navigator.geolocation;
if(geo) {
    geo.getCurrentPosition(function(pos) {
        var p = new daum.maps.LatLng(pos.coords.latitude, pos.coords.longitude);
        infoWin.setPosition(p);
        infoWin.setContent('Location found.');
        infoWin.setMap(map);
        map.setCenter(p);
    });
}

navigator.geolocation으로 현재 접속한 위치 정보를 가져오는 방식은 동일하다. 그리고 LatLng 객체로 위치정보를 갖는 객체를 생성해서 InfoWindow에 넘긴다. 카카오 맵도 접속 위치를 화면 가운데로 표시하기위해 setCenter()을 호출한다.

컨트롤러 제어

컨트롤러는 맵을 제어하기 위한 툴박스로 줌, 스케일, 스트릿뷰, 전체화면 등의 기능을 실행할 수 있다. 이런 컨트롤러를 화면표시를 제어할 수 있는 기능이다.

Google

function initMap() {
    var map = new google.maps.Map(document.getElementById('map'), {
      center: {lat: 33.368, lng: 126.567},
      zoom: 11,
      disableDefaultUI: true
      zoomControl: true,
      scaleControl: false
    });
}

화면 오른쪽 하단에 줌 컨트롤이 표시된다. 그외에 컨트롤도 표시여부를 선택할 수 있다.

Naver

function initMap() {
    var map = new naver.maps.Map('map', {
      center: {lat: 33.368, lng: 126.567},
      zoom: 11,
      zoomControl: true,
      sacleControl: false
    });
}

왼쪽 상단에 줌 컨트롤이 표시된다. 구글과 동일하게 설정된다. 줌 컨트롤이 좀더 세밀하게 조절할 수 있다.

Daum

var map = new daum.maps.Map(document.getElementById('map'), {
  center: new daum.maps.LatLng(33.368, 126.567),
  level: 9
}); 
var zoomControl = new daum.maps.ZoomControl();
map.addControl(zoomControl, daum.maps.ControlPosition.RIGHT);

오른쪽 상단에 줌 컨트롤이 표시된다. ZoomControl 개체를 생성해서 addControl()로 추가한다. 그리고 추가 위치도 지정할 수 있다.

마커 비교

마커는 특정 위치를 표시하는 아이콘이다. 보통 핀모양의 이미지를 사용하고 필요하면 해당 마커를 클릭할 수 있는 도구이다.

Google

var contStr = '<div id="content">Hello</div>';
function initMap() {
    var cheju = {lat: 33.368, lng: 126.567};
    var map = new google.maps.Map(document.getElementById('map'), {
      center: cheju,
      zoom: 11
    });

    var infoWin = new google.maps.InfoWindow({content:contStr});

    var marker = new google.maps.Marker({position:cheju, map:map, title: 'Cheju'});
    marker.addListener('click', function(){ infoWin.open(map, marker)});
}

Marker 객체를 생성하고 생성할 때 위치와 표시할 지도를 설정한다. 그리고 addListener()로 필요한 이벤트 핸들러를 등록 한다. click 이벤트를 마커를 크릭할때 발생되는 이벤트이다. 정상적으로 실행되면 아래 화면처럼 표시된다.

Naver

var contStr = '<div id="content">Hello</div>';
function initMap() {
    var cheju = {lat: 33.368, lng: 126.567};
    var map = new naver.maps.Map('map', {
      center: cheju,
      zoom: 6
    });
    var infoWin = new naver.maps.InfoWindow({content:contStr});
    var marker = new naver.maps.Marker({position:cheju, map:map, title: 'Cheju'});
    marker.addListener('click', function(){
        if(infoWin.getMap()) {
           infoWin.close(); 
        } else {
            infoWin.open(map, marker);
        }
    });
}

네이버 맵도 구글과 동일하게 Maker 객체를 생성하고 생성할 때 위치와 표시할 지도를 설정한다. 그리고 addListener()로 마커에서 발생하는 이벤트 처리할 핸들러를 추가한다. 네이버 맵은 InfoWindow가 닫기 버튼이 없기 때문에 마크 클릭 핸들러에서 닫기처리를 해줘야 한다. 실행에 문제가 없으면 아래와 같은 화면이 표시된다.

Kakao

var cheju = new daum.maps.LatLng(33.368, 126.567);
var mapOptions = { 
    center: cheju, // 지도의 중심좌표
    level: 9 // 지도의 확대 레벨
};
var map = new daum.maps.Map(document.getElementById('map'), mapOptions);

var contStr = '<div id="content">Hello</div>';
var infoWin = new daum.maps.InfoWindow({
    content:contStr,
    removable: true
});

var marker = new daum.maps.Marker({position:cheju, map:map, title: 'Cheju'});
marker.addListener('click', function(){ infoWin.open(map, marker)});

카카오 맵도 구글과 네이버와 유사하다. Marker 객체를 생성하고 생성할 때에 설정 정보를 입력한다. 또한 addListener()로 이벤트 핸들러를 등록한다. 문제가 없다면 아래와 같은 하면이 출력된다.

성능

각 맵 서비스에 대한 간단하게 비교해보았다. 기본 맵을 로딩하는 경우에 대해 측정했다.

Provider Loading Time(sec) Transfered(kB) Resources(kB) Request Count(ea)
Google 2.01 439 1173 68
Naver 0.686 235 455 33
Kakao 0.777 229 298 29

구글 맵이 가져오는 데이터가 많아서인지, 또한 표시되는 정보가 많아서 처리되는 시간이 걸리기 때문인지 로딩 시간이 오래 걸렸다. 네이버 맵과 카카오 맵이 대동소이한 로딩 시간을 보였다. 데이터 크기도 거의 비슷했다. 물론 사용하는 기능이나 최적화를 하면 성능도 달라질 수 있으니 단순 참고용으로만 활용하시길 바란다.

Prices

마지막으로 비용을 확인해보자. 여기서 비용은 기본적인 웹 지도을 사용하는 경우만 확인했다.

google

구글 맵은 8가지 맵을 구분하고 있다. 건단 비용을 청구하고 있다. Google Map Platform에 매달 약 200달러만 무료 크래딧로 제공되면 자동으로 적용된다(태평양 표준시 기준으로 매월 1일 자정에 재설정).

| | $200 Monthly credit | Monthly Volume Range
(Price per thousand calls) | | |
| --- | --- | --- | --- | --- |
| | | 0-100,000 | 100,001-500,000 | 500,001+ |
| Dynamic Maps | Up to 28,000 loads | $7.00 | $5.60 | contact |

Naver

Web Dynamic Map은 10,000,000/일 까지 무료로 제공되며, 그 이상은 건당 0.1원이 부과된다. 그외 모바일과 스태틱 등 다른 맵 서비스는 과금 기준이 다르기 때문에 요금 안내를 참조하시기 바란다.

https://www.ncloud.com/product/applicationService/maps

Kakao

무료로 제공되고 있다. 300,000회/일 까지 무료로 제공된다.

참고

[1] Google Maps Platform, https://developers.google.com/maps/documentation/javascript/tutorial

[2] Naver Maps JavaScript API v3, https://navermaps.github.io/maps.js.ncp/

[3] Hello, WEB API, http://apis.map.daum.net/web/

[4] Pricing that scales to fit your needs, https://cloud.google.com/maps-platform/pricing/sheet/

반응형