Dev/JavaScript

[JavaScript] 네이버 지도 API로 지도 구현하기

taeyeoxn 2024. 8. 31. 23:29

이번 프로젝트에서  프론트엔드 개발 중 가장 구현 난이도가 높았던 것 중 하나는 바로 지도 기능이었다.

팀원들에게 내가 맡아서 구현하겠다고 큰소리를 쳤지만, 솔직히 자바스크립트를 이번 프로젝트에서 처음 다뤄본 나로서는 구글링과 GPT의 많은 도움을 받았던 것 같다.

따라서 복습 차원에서 정리해보려고 하니 참고해주길 바란다!

1. 지도 생성하기

 

NAVER CLOUD PLATFORM

cloud computing services for corporations, IaaS, PaaS, SaaS, with Global region and Security Technology Certification

www.ncloud.com

 
우선 우리팀은 네이버 지도 API를 사용하기로 결정했기 때문에, 먼저 위의 링크에서 클라이언트 ID를 발급받았다. 이 클라이언트 ID를 사용하려면 스크립트를 로딩해주어야 한다.

<script src="https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId={클라이언트 ID}&submodules=geocoder"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

 
다음으로 지도를 생성하고 옵션을 설정해주었다.

function initMap(lat, lng) {
    currentLocation = { lat, lng };
    map = new naver.maps.Map("map", {
        center: new naver.maps.LatLng(lat, lng),
        zoom: 15,
        zoomControl: false,
        mapTypeControl: false, 
        scaleControl: false,
        mapDataControl: false,
    });

 

2. 사용자의 현재 위치 불러오기
 

setCurrentLocation() 함수를 사용해 사용자의 현재 위치를 불러올 수 있다.
만약 불러오는데 실패했을 경우 미리 지정된 위치(서울 시청)로 표시된다.

function setCurrentLocation() {
    return new Promise((resolve, reject) => {
        function success(position) {
            const lat = position.coords.latitude;
            const lng = position.coords.longitude;
            currentLocation = { lat, lng };
            resolve({ lat, lng });
        } // 위치 불러오기 성공

        function error() {
            const lat = 37.5666103;
            const lng = 126.9783882;
            currentLocation = { lat, lng };
            resolve({ lat, lng });
        } // 위치 불러오기 실패

 
사용자의 현재 위치가 마커로 표시될때, 마커를 아래와 같이 커스터마이징 할 수 있다.

    var currentLocationIcon = {
        content: '<img src="' + staticUrl + 'image/now-marker.svg" alt="Current Location" style="width: 14px; height: 14px;">',
        size: new naver.maps.Size(14, 14),
        anchor: new naver.maps.Point(7, 7)
    };

    currentLocationMarker = new naver.maps.Marker({
        position: new naver.maps.LatLng(lat, lng),
        map: map,
        icon: currentLocationIcon
    });

 

3. 다중 마커 표시하기
 

우리 서비스는 여행 계획을 네 가지 장소 카테고리(PLAY, EAT, STAY, OTHERS)로 분류하여 DB에 저장하는 방식인데, 이 저장된 장소의 위치와 정보를 불러와 각 카테고리에 맞는 마커로 지도에 표시해야 했다.

function addTravelPlanMarkers() {
    // travel_plans 목록에서 각 여행 계획에 대해 반복문 실행
    {% for plan in travel_plans %}
        // 여행 계획에 주소가 있는 경우에 마커 추가
        {% if plan.address %}
            // 주소를 이용해 좌표를 얻기 위해 네이버 지도 API의 지오코딩 서비스 호출
            naver.maps.Service.geocode({
                query: '{{ plan.address }}' // 여행 계획의 주소를 쿼리로 사용
            }, function(status, response) {
                // 지오코딩이 성공적으로 완료된 경우
                if (status === naver.maps.Service.Status.OK) {
                    // 첫번째 주소의 좌표 가져오기
                    var result = response.v2.addresses[0];
                    var lat = result.y; 
                    var lng = result.x; 

                    // 마커 옵션 설정
                    var markerOptions = {
                        position: new naver.maps.LatLng(lat, lng), // 마커 위치를 위도와 경도로 설정
                        map: map, // 마커를 표시할 지도 설정
                        icon: getMarkerIcon('{{ plan.category }}') // 여행 계획의 카테고리에 따라 마커 아이콘 설정
                    };

                    // 마커를 생성하고 지도에 추가
                    var marker = new naver.maps.Marker(markerOptions);
                    markers.push(marker); // 마커를 markers 배열에 저장

 

다음으로 앞서 현재 위치를 표시할 때 마커를 커스터마이징했던 방식과 유사하게 카테고리별로 다른 마커 이미지를 불러오도록 설정했다.

function getMarkerIcon(category) {
    const iconPaths = {
        'play': staticUrl + 'image/play-marker.svg',    
        'eat': staticUrl + 'image/eat-marker.svg',     
        'stay': staticUrl + 'image/stay-marker.svg',    
        'others': staticUrl + 'image/others-marker.svg'
    };

    // 주어진 카테고리가 iconPaths 객체에 존재하는 경우
    if (category in iconPaths) {
        return {
            content: `<img src="${iconPaths[category]}" alt="${category} marker" style="width: 35px; height: 35px;">`,
            size: new naver.maps.Size(35, 35),
            anchor: new naver.maps.Point(17.5, 35)
        };
    }

    // 카테고리가 iconPaths에 없는 경우(기본 아이콘 반환)
    return {
        content: `<img src="${staticUrl}image/default-marker.svg" alt="default marker" style="width: 35px; height: 35px;">`,
        size: new naver.maps.Size(35, 35),
        anchor: new naver.maps.Point(17.5, 35)
    };
}

 
차이점이 있다면,  getMarkerIcon 함수는 다양한 카테고리에 대해 동적으로 마커 아이콘을 설정할 수 있어 재사용성이 높은 반면, 현재 위치를 표시하는 방식은 특정 마커에 대해 고정된 아이콘을 설정하므로 재사용성이 낮다는 것이다.
 
추가적으로 마커를 클릭했을 때 이벤트 함수를 추가하여 정보창이 표시되도록 했다.

짜잔! 내가 최종적으로 구현한 화면이다.