안녕하세요!

카카오 지도 API로 자기 위치에서 마커 위치까지 길찾기 기능 만들기 어렵지 않아요!(스프링부트 thymeleaf) 본문

개발일지2

카카오 지도 API로 자기 위치에서 마커 위치까지 길찾기 기능 만들기 어렵지 않아요!(스프링부트 thymeleaf)

shinyfood 2023. 11. 5. 22:59
728x90
반응형

이번에 간단한 프로젝트를 진행하며 카카오map API를 이용하여 전국 전기차 충전소의 위치를 database에 넣고 스프링부트의 thymeleaf를 이용하여 마커로 표시해봤습니다.

 

카카오지도 API를 이용하기위해선 카카오개발자의 회원가입부터 진행하셔야합니다.

 

https://developers.kakao.com/

해당 링크로 이동하셔서 회원가입을 진행하시면 됩니다. 

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

애플리케이션은 10개까지 이용 가능하니 부담없이 많이 만드세요!

해당 사진에 나와있듯, JavaScript key를 사용할 예정이니 해당 부분이 필요합니다. 나머지 키들도 들어가시면나와있어요!

 

script key를 사용할 url을 설정해주기위해 좌측에 나와있는 플랫폼으로 이동하셔서 등록해주시면됩니다!

 

카카오개발자에서 수정(또는 등록)버튼을 누르시면 어떻게 해야하는지 나와있으니 참고해주세요!

 

자 이제 appkey를 받으셨으면 궁금해하실 코드들을 입력하셔서 사용하시면 됩니다.

본인 위치가 기존에 주어지며, 라디오버튼에따라 교통 및 지형정보 변경가능. 지역 선택시 정보가 나오고, 길찾기 버튼 클릭시 카카오 길찾기로 이동됨.

<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!--jquery 가져다 씀-->
<script type="text/javascript"
    src="//dapi.kakao.com/v2/maps/sdk.js?appkey=본인의 script앱키를 넣으시면 됩니다.&libraries=services"></script>
<script type="text/javascript"
    src="//dapi.kakao.com/v2/maps/sdk.js?appkey=본인의 script앱키를 넣으시면 됩니다.&libraries=services"></script>
<div class="map-info">
    <div id="map" style="width: 870px; height:590px;"></div>
    <!-- 기존에 사용하던 반경 조절 슬라이더 -->

    <!-- 교통정보 라디오버튼 선택 -->
    <label><input type="radio" name="traffic" value="on" id="교통정보on" onchange="trafficInfo(true)">교통정보on</label>
    <label><input type="radio" name="traffic" value="off" id="교통정보off" onchange="trafficInfo(false)">교통정보off</label>
    <label><input type="radio" name="terrain" value="on" id="지형정보on" onchange="terrainInfo(true)">지형정보on</label>
    <label><input type="radio" name="terrain" value="off" id="지형정보off" onchange="terrainInfo(false)">지형정보off</label>

    <!--지역 선택 value에 필요값 넣어서 선택-->
    <select name="jiyuk" size="1" id="regionselect">
        <option value="선택">지역선택</option>
        <option value="">전체</option>
        <option value="서울">서울</option>
        <option value="경기도">경기</option>
        <option value="부산광역시">부산</option>
        <option value="대전광역시">대전</option>
        <option value="대구광역시">대구</option>
        <option value="광주광역시">광주</option>
        <option value="인천광역시">인천</option>
        <option value="울산">울산</option>
        <option value="세종특별">세종</option>
        <option value="강원">강원</option>
        <option value="충청북도">충청북도</option>
        <option value="충청남도">충청남도</option>
        <option value="경상북도">경상북도</option>
        <option value="경상남도">경상남도</option>
        <option value="전라북도">전라북도</option>
        <option value="전라남도">전라남도</option>
        <option value="제주">제주</option>
    </select>
    <button id="userLocation">내위치</button>
</div>
<!-- 각 충전소 정보가 담긴 div 요소들. 실제로는 화면에 보이지 않습니다 -->
<div id="mapData">
    <div th:each="map : ${maps}" th:data-id="${map.id}" th:data-location="${map.location}"
        th:data-address="${map.address}" th:data-latitude="${map.latitude}" th:data-longitude="${map.longitude}"
        th:data-fast="${map.fast}" th:data-normal="${map.normal}">
    </div>
</div>

<script>


    let mapContainer = document.getElementById('map'), // 지도를 표시할 div 
        mapOption = {
            center: new kakao.maps.LatLng(35.1649, 126.8), // 지도의 중심좌표
            level: 8 // 지도의 확대 레벨
        };


    let map = new kakao.maps.Map(mapContainer, mapOption); // 지도를 생성합니다

    // 일반 지도와 스카이뷰로 지도 타입을 전환할 수 있는 지도타입 컨트롤을 생성합니다
    let mapTypeControl = new kakao.maps.MapTypeControl();


    // 지도에 컨트롤을 추가해야 지도위에 표시됩니다
    // kakao.maps.ControlPosition은 컨트롤이 표시될 위치를 정의하는데 TOPRIGHT는 오른쪽 위를 의미합니다
    map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);


    // 지도 확대 축소를 제어할 수 있는  줌 컨트롤을 생성합니다
    let zoomControl = new kakao.maps.ZoomControl();
    map.addControl(zoomControl, kakao.maps.ControlPosition.RIGHT);

    //radio버튼과결합
    function trafficInfo(isOn) {
        if (isOn) {
            // 지도에 교통정보를 표시하도록 지도타입을 추가합니다
            map.addOverlayMapTypeId(kakao.maps.MapTypeId.TRAFFIC);
        } else {
            // 아래 코드는 위에서 추가한 교통정보 지도타입을 제거합니다
            map.removeOverlayMapTypeId(kakao.maps.MapTypeId.TRAFFIC);
        }
    }

    function terrainInfo(isOn) {
        if (isOn) {
            // 지도에 교통정보를 표시하도록 지도타입을 추가합니다
            map.addOverlayMapTypeId(kakao.maps.MapTypeId.TERRAIN);
        } else {
            // 아래 코드는 위에서 추가한 교통정보 지도타입을 제거합니다
            map.removeOverlayMapTypeId(kakao.maps.MapTypeId.TERRAIN);
        }
    }
    //radio버튼과결합 완

    let imageSrc = '/images/Marker.png', // 마커이미지의 주소입니다    
        imageSize = new kakao.maps.Size(64, 69), // 마커이미지의 크기입니다
        imageOption = { offset: new kakao.maps.Point(27, 69) }; // 마커이미지의 옵션입니다. 마커의 좌표와 일치시킬 이미지 안에서의 좌표를 설정합니다.

    let imageSrc2 = "/images/LMarker4.png", // 마커이미지의 주소입니다    
        imageSize2 = new kakao.maps.Size(25, 35), // 마커이미지의 크기입니다
        imageOption2 = { offset: new kakao.maps.Point(11, 30) }; // 마커이미지의 옵션입니다. 마커의 좌표와 일치시킬 이미지 안에서의 좌표를 설정합니다.


    let markerImage2 = new kakao.maps.MarkerImage(imageSrc2, imageSize2, imageOption2);

    // 현재 화면에 표시된 모든 마커들
    let markers = [];

    function getMarkers(region) {
        $.ajax({
            url: '/getMarkers',
            type: 'GET',
            data: { region: region },
            success: function (data) {
                console.log(data);
                // 성공적으로 데이터를 받아왔을 때,
                // 먼저 기존에 화면에 표시된 모든 마커들을 제거.
                for (let i = 0; i < markers.length; i++) {
                    markers[i].setMap(null);
                }
                markers = [];

                // 그리고 새로운 데이터로 마커들을 생성.
                for (let i = 0; i < data.length; i++) {
                    let mapData = data[i];
                    let markerPosition2 = new kakao.maps.LatLng(mapData.latitude, mapData.longitude);
                    // 데이터생성시 표현해줄것들 추가하기 가능
                    createMarker(markerPosition2, map, markerImage2,
                        mapData.location, mapData.address,
                        mapData.fast,
                        mapData.normal
                    );
                }
            },
            error: function (request, status, error) {
                console.error("실패:", error);
            }
        });
    }

    // 각 옵션에 대응하는 위도와 경도
    const regionCoords = {
        "전체": { lat: 36.5, lng: 127.5 },
        "서울": { lat: 37.5665, lng: 126.9780 },
        "경기도": { lat: 37.2749, lng: 127.0094 },
        "부산광역시": { lat: 35.1854, lng: 129.0734 },
        "대전광역시": { lat: 36.3519, lng: 127.3843 },
        "대구광역시": { lat: 35.8723, lng: 128.6022 },
        "광주광역시": { lat: 35.1622, lng: 126.8514 },
        "인천광역시": { lat: 37.4620, lng: 126.7038 },
        "울산": { lat: 35.5444, lng: 129.3433 },
        "세종특별": { lat: 36.4822, lng: 127.2810 },
        "강원": { lat: 37.6323, lng: 128.4417 },
        "충청북도": { lat: 36.8752, lng: 127.7584 },
        "충청남도": { lat: 36.6826, lng: 126.8400 },
        "경상북도": { lat: 36.4275, lng: 128.9087 },
        "경상남도": { lat: 35.2302, lng: 128.4078 },
        "전라북도": { lat: 35.6514, lng: 126.9480 },
        "전라남도": { lat: 34.9107, lng: 126.9710 },
        "제주": { lat: 33.3867, lng: 126.5395 }
    };
    //select id를 받아옴
    $('#regionselect').change(function () {
        let selectedRegion = $(this).val();

        if (selectedRegion in regionCoords) {
            let coords = regionCoords[selectedRegion];
            map.setCenter(new kakao.maps.LatLng(coords.lat, coords.lng));
        }

        getMarkers(selectedRegion);
    });
    // 시작시 전부 의 마커를 받아옴
    window.onload = (function () {
        getMarkers("전체");
    });


    let locPosition;
    // HTML5의 geolocation으로 사용할 수 있는지 확인합니다 
    if (navigator.geolocation) {
        // GeoLocation을 이용해서 접속 위치를 얻어옵니다
        navigator.geolocation.getCurrentPosition(function (position) {
            console.log("위치를 받아옵니다:", position);
            let lat = position.coords.latitude, // 위도
                lon = position.coords.longitude; // 경도

            locPosition = new kakao.maps.LatLng(lat, lon);

            let markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption);

            let marker = new kakao.maps.Marker({
                position: locPosition,
                image: markerImage,
                clickable: true
            });

            marker.setMap(map);

        }, function (error) {
            console.error("좌표 받아오기에 실패했습니다:", error)
        });

    } else {
        console.error("표현할수없습니다.");
    }

    // 현재 화면에 표시된 모든 인포윈도우들
    let infoWindows = [];

    function coord2Address(lat, lon, callback) {
        var geocoder = new kakao.maps.services.Geocoder();

        var coord = new kakao.maps.LatLng(lat, lon);

        geocoder.coord2Address(coord.getLng(), coord.getLat(), function (result, status) {
            if (status === kakao.maps.services.Status.OK) {
                callback(result[0].address.address_name);
            }
        });
    }


    // 현재 위치를 얻는 코드입니다.
    let currentAddress = '';
    navigator.geolocation.getCurrentPosition(function (position) {
        let lat = position.coords.latitude, // 위도
            lon = position.coords.longitude; // 경도
        coord2Address(lat, lon, function (address) {
            currentAddress = address;
            // alert(address)
        });
    });

    //마커 생성하기
    function createMarker(position, map, image, name1, name2, name3, name4) {
        const content = '<div style="padding:5px;">이름:' + name1 + '<br>주소:' + name2 + '<br>급속:' + name3 + '완속:' + name4 + '<br><br><a class="rlf" href="https://map.kakao.com/?sName=' + currentAddress + '&eName=' + name2 + '" target="_blank">길찾기</a>' + '<div><br></div>' + '</div>',

            overRemoveable = true;
        const infoWindow = new window.kakao.maps.InfoWindow({
            content: content
            , removable: true
        });
        infoWindows.push(infoWindow);

        const myMarker = new window.kakao.maps.Marker({ position, map, image });
        let isClicked = false;  //클릭 여부 확인

        // 마커를 markers 배열에 추가합니다.
        markers.push(myMarker);

        // 마우스 클릭시 인포윈도우 표현
        window.kakao.maps.event.addListener(myMarker, 'click', function () {
            closeAllInfoWindows();  // 다른 인포윈도우가 열려있다면 닫습니다.
            infoWindow.open(map, myMarker);
            map.setCenter(position);  // 클릭한 마커의 위치를 지도의 중심으로 설정합니다.
            isClicked = true;
        });
        // 모든 인포윈도우를 닫는 함수입니다.
        function closeAllInfoWindows() {
            for (let i = 0; i < infoWindows.length; i++) {
                infoWindows[i].close();
            }
        }

        let timeoutId;

        // 마우스 오버시의 인포윈도우 표현
        let overContent = '<div style="padding:5px;">이름:' + name1 + '<br>급속:' + name3 + '<br>완속:' + name4 + '<br><br><br></div>';

        let overInfowindow = new kakao.maps.InfoWindow({
            content: overContent
        });

        window.kakao.maps.event.addListener(myMarker, 'mouseover', function () {  //마커가 클릭되지 않았을 때만 마우스 오버 이벤트 처리
            if (timeoutId) clearTimeout(timeoutId);
            if (!isClicked) {
                overInfowindow.open(map, myMarker);
            }
        });

        window.kakao.maps.event.addListener(myMarker, 'mouseout', function () {
            timeoutId = setTimeout(function () {
                overInfowindow.close();
            }, 10);

        });
        window.kakao.maps.event.addListener(myMarker, 'click', function () {
            overInfowindow.close(); // 클릭 시 마우스 오버 인포윈도우를 닫습니다.
            isClicked = false; // 마커 클릭 상태를 초기화합니다.
        });
    }
    //내위치button을 눌렀을때 사용자의 위치로 전환.
    document.getElementById('userLocation').addEventListener('click', function () {
        // GeoLocation을 이용해서 접속 위치를 얻어옵니다
        navigator.geolocation.getCurrentPosition(function (position) {
            let lat = position.coords.latitude; // 위도
            let lon = position.coords.longitude; // 경도

            locPosition = new kakao.maps.LatLng(lat, lon);
            map.setCenter(locPosition);  // 사용자의 위치를 지도의 중심으로 설정합니다.
        });
    });

    $(window).resize(function () {
        let mapContainer = document.getElementById('map');
        map.relayout();  // 화면 크기 변화에 따른 지도 재렌더링
    });
</script>
</body>

여러 부분이 있지만, 해당하는 주석을 다 달아놓았으니 궁금한점은 댓글로 부탁드립니다! 

 

감사합니다!

728x90
반응형