Explanation
오늘은 D3를 사용해서 우리나라 지도를 그리는 걸 해보려고 합니다.
사실 이미 굉장히 좋은 글들이 많이 있었는데요, 뭔가 막상 직접 해보니 헷갈리는 부분들이 있어서 정리도 할 겸 제가 해본 내용을 살짝 적어보려 합니다.
1. 지도 데이터 받기
저는 많은 블로그의 글들에서 봤던 것처럼 아래의 링크에서 지도 데이터 파일을 다운로드했습니다!
(저는 '시도'를 받았습니다.)
http://www.gisdeveloper.co.kr/?p=2332
2. geoJSON 파일 만들기
우선! 역시 마찬가지로.. 다른 분들의 글을 참고해서 QGIS을 다운로드했습니다.
https://qgis.org/en/site/forusers/download.html
이쯤에서 QGIS 프로그램에 대해서 이야기를 해야 하는데, 사실.. 아직 잘 몰...

대략 프로그램을 실행하면 위와 같은데요.

'레이어' > '레이어 추가' > '벡터 레이어 추가...' 버튼을 선택합니다.

'원본'란에 아까 다운로드 받은 shp 파일을 넣어주시고, 위에 인코딩은 'EUC-KR'로 선택하신 후에 추가 버튼을 선택합니다.

그러면 위와 같이 지도가 짜잔하고 뜨는 걸 확인하실 수 있는데요, 여기에서 왼쪽 아래에 레이어란에서 마우스 우클릭 후 '속성 테이블 열기' 버튼을 눌러보시면 데이터가 잘 나와야 하는데,

혹시라도 저와 같이 한글이 깨져서 나온다면?!

레이어에서 우클릭 하셔서 '속성'을 선택하신 후 '원본'에서 '데이터 원본 인코딩'을 'EUC-KR'로 변경하고 'OK'버튼을 선택해주세요.

그리고 다시 '속성 테이블 열기'를 확인해 보시면 한글이 정상적으로 나오는 것을 알 수 있습니다. 짜잔!

하... 간단한 내용인데... 캡처가 일입니다...
거의 다 왔습니다...

다시 레이어에서 우클릭 후 'Export' > '객체를 다른 이름으로 저장' 버튼을 선택합니다.

포맷을 'geoJSON'으로 하고 '파일 이름'은 ... 을 선택하셔서 저장할 위치와 파일 이름을 설정하시고요 '좌표계'는 '- WGS 84'로 설정하고 'OK' 버튼을 누르면, 드디어 geoJSON 파일을 만드는 거 끝!!
3. topoJSON 파일 만들기
다음으로 geoJSON 파일의 지도를 조금 단순화 하고 topoJSON 파일로 변경합니다!

https://mapshaper.org/ 여기 사이트로 가셔서 아까 만든 geoJSON 파일을 넣어줍니다.

다음으로 지도를 조금 단순화 해볼게요, 상단에 'Simplify' 메뉴를 선택한 후 'Apply' 버튼을 선택하고 원하시는 퍼센테이지를 입력합니다.

상단에 'Export' 메뉴를 선택한 후 'TopoJSON' 을 선택한 후 Export 버튼을 눌러 topoJSON 파일을 만들어 주면 topoJSON 만들기 끝!

4. D3로 SVG 차트 그리기
전체적인 코드는 아래의 링크를 통해 깃허브에서 확인하실 수 있습니다!
기본 스택은 저에게 가장 간단하고 익숙한 js, webpack, react를 사용하였습니다.
https://github.com/falsy/blog-post-example/tree/master/korea-map-charts
//KoreaMap.js
import * as React from 'react'
import { useEffect, useRef } from 'react'
import * as d3 from 'd3'
import { feature } from 'topojson-client'
import korea from '../mapData/korea-topo.json'
const featureData = feature(korea, korea.objects['korea-topo'])
// topojson-client는 topoJSON 파일을 D3에서 사용할 수 있게 바꿔주는 라이브러리라고 하네요??
// 그리고 저는 위에 'korea-topo' 라는 이름으로 접근했는데
// 만드신 topoJSON 파일을 열어서 'objects'라고 검색하셔서 객체로 안에 프로퍼티 이름을 적어주시면 된답니다.
const KoreaMap = () => {
// svg를 그릴 엘리먼트 설정을 위한 ref
const chart = useRef(null)
const printD3 = () => {
// 지도 svg의 너비와 높이
const width = 500
const height = 500
// 메르카토르 투영법 설정
// 우리가 가장 많이 쓰는 도법으로 구형인 지구를 평면으로 표현하는 하나의 방법이라고 하네요??
const projection = d3.geoMercator().scale(1).translate([0, 0])
const path = d3.geoPath().projection(projection)
const bounds = path.bounds(featureData)
// svg의 크기에 따른 지도의 크기와 위치값을 설정합니다.
const dx = bounds[1][0] - bounds[0][0]
const dy = bounds[1][1] - bounds[0][1]
const x = (bounds[0][0] + bounds[1][0]) / 2
const y = (bounds[0][1] + bounds[1][1]) / 2
const scale = 0.9 / Math.max(dx / width, dy / height)
const translate = [width / 2 - scale * x, height / 2 - scale * y]
projection.scale(scale).translate(translate)
// svg를 만들고
const svg = d3
.select(chart.current)
.append('svg')
.attr('width', width)
.attr('height', height)
const mapLayer = svg.append('g')
// topoJSON의 데이터를 그려줍니다.
mapLayer
.selectAll('path')
.data(featureData.features)
.enter().append('path')
.attr('d', path)
.style('fill', '#666')
}
useEffect(() => {
printD3()
}, [])
return (
<div ref={chart}></div>
)
}
export default KoreaMap
뭔가 캡처만 많았지 제대로 된 설명이 부족한 거 같네요. 절대로 아직 잘 몰라서 대충 적고 넘긴 거, 맞습니다...
(다음에 조금 더 공부해서.. 정리하도록 하겠습니다.)
끝
참고.
https://junghan92.medium.com/d3-geo-topojson-canvas%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%A7%B5-%EC%B0%A8%ED%8A%B8-%EA%B7%B8%EB%A6%AC%EA%B8%B0-ffab54ec23bf
https://parandol.tistory.com/38
https://gist.github.com/e9t/55699e9fa8c3eb7fe40c#file-thumbnail-png
https://threadbuilder.wordpress.com/2019/03/15/echart-%ED%95%9C%EA%B5%ADkorea%EC%A7%80%EB%8F%84-%EB%9D%84%EC%9A%B0%EA%B8%B0/
https://medium.com/@masoolsa7/%ED%96%89%EC%A0%95%EA%B5%AC%EC%97%AD-%EA%B2%BD%EA%B3%84-topojson-%ED%8C%8C%EC%9D%BC-%EB%A7%8C%EB%93%A4%EA%B8%B0-392800d0bc0b
https://stackoverflow.com/questions/25310390/how-does-path-bounds-work



