반응형

예전에 포스팅한 amchart에서 svg로 표현된 svg파일을 가져와서 svg코드를 수정거나 CSS 변경으로 적용했던 부분을 많이 보러 오시는걸 보고 한국지도를 찾는분들이 많이 계시는걸 알게 되었습니다.

 

이번에는 d3 라이브러리와 맵정보가 담긴 geoJson파일을 읽고 파싱하여 지도의 형태의 도형을 그려 넣을 것입니다. 그려 넣은 지도에 클릭 이벤트, 줌 이벤트 등을 추가할 수 있으며 이를 만들어보겠습니다.

추가적으로 이번엔 웹서버가 필요합니다.

was서버로 유명한 tomcat을 쓰셔도 좋고 간단하게 웹서버를 올릴 수 있는 http-server를 쓰셔도 됩니다. 

 

데이터 시각화를 지원하는 수많은 라이브러리 중에 d3라는 강력한 라이브러리가 있습니다.

데이터를 차트화도 시켜주고 이미지화 지도 등등 다양하게 표현이 가능합니다.

 

특히, 우리가 일반적으로 사용하는 차트형태가 아닌 topology차트와 같은 기하학적인 형태(트리형 표현, 노드 구성도 등)의 차트도 표현이 가능합니다.

 

이렇게 좋은 기능을 제공하는 d3이지만 개인적으로 안좋은 점(?), 힘든점으로 첫 번째 버전업에 따른 변경되는 메소드명, 파라미터등입니다.

버전이 올라감에 따라 과거버전에서 사용된 메소드가 사라지거나 이름이 바뀌는데... 버전 별로 어떤 기능을 쓸 때, 사용해야 하는 메소드명이라던지... 파라미터를 매번 다시 찾아봐야하는 점이 힘듭니다.

두번째는 기능이 많다보니 공식 API문서도 따로 공부를 해야할 정도로 양도 방대하고 영문으로 되어있습니다...(영어를 잘하는분들이 부럽습니다ㅜ.ㅜ) 엄청 깊게 사용해야할게 아니면 따로 공부보단 그때마다 사용해야할 메소드를 찾아서 적용하는편이 나을 것 같습니다.

 

개인적으로 느낀 d3에 대한 설명은 이정도로 하고 진행해보겠습니다.

 

 


d3를 활용한 한국 지도 만들기

 

한국 지도 gif...

만들어볼 한국지도의 UI 형태입니다.

카카오맵이나 구글지도, 오픈레이어스와 같은 형태가 아니니 참고바랍니다.

 

아래는 준비물입니다.

- d3(3.1.7 ver)

- was서버(http-server, node, tomcat등)

- 한국 지도의 데이터가 담긴 geoJSON파일

d3는 3.1.7버전으로 개발을 했었네요... 현재 최신 버전의 d3를 다운받아서 사용하시면 아마 메소드가 충돌나거나 에러가 발생하여 정상적으로 동작하지 않을겁니다.

 

geoJSON파일은 구글링을 하시면 많이 찾으실수 있는데 통계청을 통해 사용하셔도 되고, 아래 URL

https://github.com/vuski/admdongkor

 

vuski/admdongkor

대한민국 행정동 경계 파일. Contribute to vuski/admdongkor development by creating an account on GitHub.

github.com

이분의 github에서 받은 데이터를 QGIC3 툴을 활용하여 잘라서 사용하셔도 됩니다.

실제로 이번포스팅에는 없지만 지역별로 나눠야 하는 작업이 있어서 한국지도를 QGIC3툴로 잘라서 사용했습니다.

 

아래 2개 파일은 과거 d3버전이나, json파일 받는게 어려운 분들을 위해 따로 첨부합니다.

d3.js
0.29MB
korea.json
1.31MB

 


korea.html

<!DOCTYPE html>
<html lang="en" dir="ltr">
    <head>
        <meta charset="utf-8" />
        <title>koreaMap</title>
        <link rel="stylesheet" href="css/korea.css" />
    </head>
    <script type="text/javascript" src="js/d3.js"></script>
    <script type="text/javascript" src="js/korea.js"></script>
    <body>
        <div id="container"></div>
    </body>
</html>

html은 간단합니다. container라는곳에 데이터를 파싱하여 한국 지도를 넣을겁니다.

css는 korea.css라는 파일에서 간단하게 정의할겁니다. hover와 같은 이벤트들~

 

이제 동작을 위해 d3라이브러리를 추가해야겠죠? 소스를 동작시킬 korea.js도 연결하였습니다.

 

korea.css, korea.js를 만들어보겠습니다.

 

korea.css

@charset "UTF-8";

#container {
	width: 700px;
	min-height: 700px;
	float: left;
	margin: 15px 35px;
}
#states path {
	fill: #585858;
	stroke: #000000;
	stroke-width: 1.5px;
}

#states path:hover {
	fill: #009300;
}

#states .active {
	fill: #00B700;
}

#states .activeDetail {
	fill: #00B700;
}

#states path {
	cursor: pointer;
}

#states text {
	cursor: pointer;
	font-size: 12px;
	fill: #fff;
}

지역별 색상과 hover 이벤트 글씨 색상등을 처리했습니다. 이번에도 svg로 그려지기때문에 fill, stroke등의 속성이 사용되었습니다.

 

korea.js

window.onload = function() {
    drawMap('#container');
};

//지도 그리기
function drawMap(target) {
    var width = 700; //지도의 넓이
    var height = 700; //지도의 높이
    var initialScale = 5500; //확대시킬 값
    var initialX = -11900; //초기 위치값 X
    var initialY = 4050; //초기 위치값 Y
    var labels;

    var projection = d3.geo
        .mercator()
        .scale(initialScale)
        .translate([initialX, initialY]);
    var path = d3.geo.path().projection(projection);
    var zoom = d3.behavior
        .zoom()
        .translate(projection.translate())
        .scale(projection.scale())
        .scaleExtent([height, 800 * height])
        .on('zoom', zoom);

    var svg = d3
        .select(target)
        .append('svg')
        .attr('width', width + 'px')
        .attr('height', height + 'px')
        .attr('id', 'map')
        .attr('class', 'map');

    var states = svg
        .append('g')
        .attr('id', 'states')
        .call(zoom);

    states
        .append('rect')
        .attr('class', 'background')
        .attr('width', width + 'px')
        .attr('height', height + 'px');

    //geoJson데이터를 파싱하여 지도그리기
    d3.json('json/korea.json', function(json) {
        states
            .selectAll('path') //지역 설정
            .data(json.features)
            .enter()
            .append('path')
            .attr('d', path)
            .attr('id', function(d) {
                return 'path-' + d.properties.name_eng;
            });

        labels = states
            .selectAll('text')
            .data(json.features) //라벨표시
            .enter()
            .append('text')
            .attr('transform', translateTolabel)
            .attr('id', function(d) {
                return 'label-' + d.properties.name_eng;
            })
            .attr('text-anchor', 'middle')
            .attr('dy', '.35em')
            .text(function(d) {
                return d.properties.name;
            });
    });

    //텍스트 위치 조절 - 하드코딩으로 위치 조절을 했습니다.
    function translateTolabel(d) {
        var arr = path.centroid(d);
        if (d.properties.code == 31) {
            //서울 경기도 이름 겹쳐서 경기도 내리기
            arr[1] +=
                d3.event && d3.event.scale
                    ? d3.event.scale / height + 20
                    : initialScale / height + 20;
        } else if (d.properties.code == 34) {
            //충남은 조금 더 내리기
            arr[1] +=
                d3.event && d3.event.scale
                    ? d3.event.scale / height + 10
                    : initialScale / height + 10;
        }
        return 'translate(' + arr + ')';
    }

    function zoom() {
        projection.translate(d3.event.translate).scale(d3.event.scale);
        states.selectAll('path').attr('d', path);
        labels.attr('transform', translateTolabel);
    }
}

d3사용으로 인해 여러 메소드들이 사용되었습니다.

d3의 메소드들을 다 설명하기엔 너무 길어지므로 공식 홈페이지의 API들이나 다른 예제들을 참조하여 추가해보시면 좋을것 같습니다.

 

지역명을 입력하는 label부분에서 서로 중간지점이 겹쳐서 글자를 제대로 알아보지 못하는 현상이 발생해서 

공통으로 사용하는 trnslateTolabel이라는 함수에서 약간의 커스텀이 처리되었습니다.

 

소스 작성이 완료되었으면 이제 실행을 해봐야겠죠?

웹 서버가 필요합니다!

톰캣같은 was로 개발하고 계신분들은 확인시 문제가 없겠지만 서버없이 html을 실행하게 되면 이런 에러가 발생할겁니다. 처음에 시작할 때 서버가 필요하다고 했었죠?

 

저는 http-server를 활용해서 실행하였습니다.

터미널 창을 열고 프로젝트 디렉토리로 이동해서 http-server를 입력합니다.

터미널에 http-server 입력!

 

enter입력! 서버가 실행되었습니다.

웹서버 실행

별다른 옵션없이 실행하여 기본포트인 8080으로 실행되었습니다.

 

이제 localhost:8080/korea.html을 입력해서 실행해보겠습니다. (127.0.0.1:8080/korea.html)

정상적으로 실행된 모습

 

http-server 설치법 및 사용법은 매우 간단하므로 구글링을 통해 보시고 사용하는것도 추천드립니다.

(추후에 포스팅하게 되면 연결해놓겠습니다.)

 

 

아래 URL의 github를 가시면 지금까지 작성한 소스를 받아보실수 있습니다.

https://github.com/myhappyman/d3_koreaMap

 

myhappyman/d3_koreaMap

Contribute to myhappyman/d3_koreaMap development by creating an account on GitHub.

github.com

반응형