olrlobt

[Java] 카카오 지도 / 시도 시군구 행정구역 폴리곤으로 구분하기 본문

Spring/Maps

[Java] 카카오 지도 / 시도 시군구 행정구역 폴리곤으로 구분하기

olrlobt 2023. 9. 14. 16:51

 시도 시군구 행정구역 폴리곤으로 구분하기

 

카카오 맵 API에서는 지도 위에 원, 선, 다각형 등을 표시하고 이벤트를 넣을 수 있는데,

이를 활용하여 우리나라의 시도/시군구/행정구역을 폴리곤(다각형)으로 표시할 수 있다.

 


카오 지도 API 다각형 그리기

카카오 지도 API에서는 아래와 같은 방법으로 다각형을 그릴 수 있다. 

 

카카오 지도 API 공식 홈페이지 - 다각형 그리기 :

https://apis.map.kakao.com/web/sample/drawShape/

 

// 다각형을 구성하는 좌표 배열입니다. 이 좌표들을 이어서 다각형을 표시합니다
var polygonPath = [
    new kakao.maps.LatLng(33.45133510810506, 126.57159381623066),
    new kakao.maps.LatLng(33.44955812811862, 126.5713551811832),
    new kakao.maps.LatLng(33.449986291544086, 126.57263296172184),
    new kakao.maps.LatLng(33.450682513554554, 126.57321034054742),
    new kakao.maps.LatLng(33.451346760004206, 126.57235740081413) 
];

// 지도에 표시할 다각형을 생성합니다
var polygon = new kakao.maps.Polygon({
    path:polygonPath, // 그려질 다각형의 좌표 배열입니다
    strokeWeight: 3, // 선의 두께입니다
    strokeColor: '#39DE2A', // 선의 색깔입니다
    strokeOpacity: 0.8, // 선의 불투명도 입니다 1에서 0 사이의 값이며 0에 가까울수록 투명합니다
    strokeStyle: 'longdash', // 선의 스타일입니다
    fillColor: '#A2FF99', // 채우기 색깔입니다
    fillOpacity: 0.7 // 채우기 불투명도 입니다
});

// 지도에 다각형을 표시합니다
polygon.setMap(map);

 

이 방법을 이용해서, 아래와 같이 행정 구역을 다각형으로 나누어 줄 것이다.

 

 

 

 


 

대한민국 행정구역 다운로드

http://www.gisdeveloper.co.kr/?p=2332 

 

대한민국 최신 행정구역(SHP) 다운로드 – GIS Developer

 

www.gisdeveloper.co.kr

 

먼저 위 링크에서 행정구역을 나누기 위한 모델링 파일을 다운로드한다.

여기서 다운로드한 파일들은. shp 등의 파일로, 사용하기 위해서는 Json 변환이 필요하다.

 

아니면, 아래과정을 일부 생략하고, 내가 사용했던 아래파일을 받아도 무방하다.

 

 

시/도 :

sido.json
0.39MB

 

시/군/구 :

sig.json
1.34MB

 

 

 

 

 

원하는 구현 정도에 따라, 알맞은 파일을 받아서 사용하면 되고,

나의 경우에는 줌인, 줌 아웃에 따라 보이는 정도를 달라지게 할 것이기 때문에,

시, 도 / 시, 군, 구 /  두 파일을 사용했다.

 

 


폴리곤 간소화와 JSON 변경

 

https://mapshaper.org/

 

mapshaper

Drop or paste files here or select from a folder Shapefile, GeoJSON, TopoJSON, KML and CSV files are supported Files can be gzipped or in a zip archive Quick import Drop or paste files here to import with default settings

mapshaper.org

 

대한민국 행정구역의 경계는 일직선이 아니기 때문에 매우 복잡한 다각형으로 되어 있다.

이에 따라 용량도 꽤나 크고, 다각형의 각의 개수도 많기 때문에 카카오 맵 API에서 폴리곤을 Load 할 때까지의 시간이 오래 걸리게 된다.

 

따라서, 이 로딩 시간을 줄이기 위하여, 폴리곤을 간소화하는 방법을 사용했다.

 

위 사이트를 이용하여 폴리곤을 간소화하고 Json으로 추출해 보자.

 

위 사이트에 접속하면 아래와 같은 화면이 나온다.

 

 

 

 

 

 

여기에 앞선 홈페이지에서 다운로드한. shp 파일을 로드한다. 

 

 

 

Import를 해 주면, 

 

 

 

위처럼, 폴리곤의 형태를 미리 보기로 볼 수 있다.

 

여기서 폴리곤을 간소화하기 위해, 우측 상단의 Simplify를 누른다.

 

 

그럼 위와 같은 설정 창이 하나 뜬다.

Prevent shape removal : 폴리곤을 간소화하면서, 완전히 삭제되지는 않게 하는 설정이다.

 

Method : 폴리곤을 간소화하는 알고리즘을 선택한다.

 

여기서 나는, 아무것도 건들지 않고 기본 설정으로 넘어갔다.

 

그러면 상단에, 간소화 정도를 설정할 수 있는 드래그바가 생성이 되고 이를 조절하여 폴리곤을 간소화할 수 있다.

 

 

(좌) 100% / (우) 1.3%

 

너무 높은 수치를 사용하면, 용량과 점의 개수가 많아 로딩 시간이 오래 걸리게 되고,

너무 낮은 수치를 사용하면, 생략되어 사라져 버리는 지점이 있기 때문에 적당한 지점을 찾아서 설정해 주자.

 

개인적으로 15% ~ 5%가 사라지는 지점 없이 적당하다고 생각된다.

 

 

 

 

간소화를 마쳤다면, Export를 눌러 Json 형식으로 추출해 주자.

 

 

json으로 변환된 모델링 파일

 


코드 구현

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

    let map = new kakao.maps.Map(mapContainer, mapOption),
        customOverlay = new kakao.maps.CustomOverlay({})

    let detailMode = false; // level에 따라 다른 json 파일 사용
    let level = '';
    let polygons = [];

    init("json/sido.json") // 초기 시작

    kakao.maps.event.addListener(map, 'zoom_changed', function () {
        level = map.getLevel()
        if (!detailMode && level <= 10) { // level 에 따라 다른 json 파일을 사용한다.
            detailMode = true;
            removePolygon();
            init("json/sig.json")
        } else if (detailMode && level > 10) { // level 에 따라 다른 json 파일을 사용한다.
            detailMode = false;
            removePolygon();
            init("json/sido.json")
        }
    });

  	// 모든 폴리곤을 지우는 함수
    function removePolygon() { 
        for (let i = 0; i < polygons.length; i++) {
            polygons[i].setMap(null);
        }
        areas = [];
        polygons = [];
    }

	// 폴리곤 생성
    function init(path) {

		//path 경로의 json 파일 파싱
        $.getJSON(path, function (geojson) {
            var units = geojson.features; // json key값이 "features"인 것의 value를 통으로 가져온다.

            $.each(units, function (index, unit) { // 1개 지역씩 꺼내서 사용. val은 그 1개 지역에 대한 정보를 담는다
                var coordinates = []; //좌표 저장할 배열
                var name = ''; // 지역 이름
                var cd_location = '';
                coordinates = unit.geometry.coordinates; // 1개 지역의 영역을 구성하는 다각형의 모든 좌표 배열
                name = unit.properties.SIG_KOR_NM; // 1개 지역의 이름
                cd_location = unit.properties.SIG_CD;


                var ob = new Object();
                ob.name = name;
                ob.path = [];
                ob.location = cd_location;
                $.each(coordinates[0], function (index, coordinate) { 
                    ob.path
                        .push(new kakao.maps.LatLng(coordinate[1],
                            coordinate[0]));
                });

                areas[index] = ob;
            });//each
        });//getJSON

		// 지도에 영역데이터를 폴리곤으로 표시
        for (var i = 0, len = areas.length; i < len; i++) {
            displayArea(areas[i]);
        }

        function displayArea(area) {

            var polygon = new kakao.maps.Polygon({
                map: map,
                path: area.path,
                strokeWeight: 2,
                strokeColor: '#004c80',
                strokeOpacity: 0.8,
                fillColor: '#fff',
                fillOpacity: 0.7
            });
            polygons.push(polygon);

            kakao.maps.event.addListener(polygon, 'mouseover', function (mouseEvent) {
                polygon.setOptions({fillColor: '#09f'});
                customOverlay.setContent('<div class="area">' + area.name + '</div>');
                customOverlay.setPosition(mouseEvent.latLng);
                customOverlay.setMap(map);
            });

            kakao.maps.event.addListener(polygon, 'mousemove', function (mouseEvent) {

                customOverlay.setPosition(mouseEvent.latLng);
            });

            kakao.maps.event.addListener(polygon, 'mouseout', function () {
                polygon.setOptions({fillColor: '#fff'});
                customOverlay.setMap(null);
            });

            kakao.maps.event.addListener(polygon, 'click', function (mouseEvent) {
                if (!detailMode) {
                    map.setLevel(10); // level에 따라 이벤트 변경
                    var latlng = mouseEvent.latLng;

                    // 지도의 중심을 부드럽게 클릭한 위치로 이동시킵니다.
                    map.panTo(latlng);
                } else {
					// 클릭 이벤트 함수
                    // callFunctionWithRegionCode(area.location);
                }
            });
        }
    }

 

코드는 주석으로 설명이 되어 있고,

카카오 공식 홈페이지를 참고하며 이해하면 큰 문제없이 해결할 수 있을 것이라 생각되어, 

자세한 설명은 생략하려 한다.

 

 


결과

 

 

시작하게 되면, 시/도로 이루어진 폴리곤이 보이고,

레벨에 따라, 시/도 폴리곤과 시/군/구 폴리곤이 알맞게 나오게 설정하였다.

 

또한,

시/도에서 클릭하게 되면, 시/군/구로 이루어진 폴리곤이 나오게 확대되고,

시/군/구 에서 클릭하게 되면, 내가 원하는 데이터의 좌표에 마커가 찍히게끔 구현하였다.

 

 

 

 

Comments