CSR로 D3.js map chart 만들기

LateMarch·2023년 10월 21일
0

D3.js를 이용해 맵차트를 구현하면 d3의 여러 기능들을 이용해 인터렉티브한 차트를 구현할 수 있다. d3.js가 무엇인지, 그리고 성능적인 이슈들은 다음 포스팅으로 미루고 이 글에서는 Next.js app router에서 d3를 이용해 map chart를 구현하는 로직에 대해 소개해볼까 한다.

시작하기

맵 차트는 svg부터 모두 client component에서 만들 예정이다. 성능적으로는 불필요하고 오히려 더 복잡한 작업이 될 수 있을지 모르지만 이 코드로 기타 csr 라이브러리등에서도 작동하기를 기대하기 때문이다.(ssr 로드는 나중에 다룰 예정임)

도화지 장만하기

d3.js는 dom 조작 라이브러리로 svg나 canvas를 정의하고 그 위에 요소들을 올려놓으면서 데이터를 시각화한다. 그러니 먼저 그림(요소들)을 그릴 도화지부터 정의해줘야 한다.

export default function D3Map() {
  const ref = useRef<HTMLDivElement | null>(null);
  useEffect(() => {
    if (!ref.current) return;

    //Remove any existing SVG
    d3.select(ref.current).selectAll("svg").remove();
    
    const svg = d3.select(ref.current).append("svg");
    svg //
      .attr("viewBox", `0 0 ${width} ${height}`)
      .style("border", "1px solid steelblue");
	
      ... 중략 ...
      
 return <div ref={ref}/>

viewBox 대신 width, height를 지정해줘도 되지만 viewBox를 사용하면 svg를 반응형으로 만들 수 있으며 전체화면을 설정할 때에도 도움이 된다. svg가 잘 정의되었는지 확인하기 위해 border를 svg에 둘러 이후 요소들이 표시될 구역을 확인하는 것이 좋다. 그리고 개발 환경에서는 변경사항을 적용할때마다 브라우저에 svg가 복사가 되는 경우가 있으므로 이미 존재하던 svg를 지워줄 필요가 있으며 배포 환경에서는 삭제해도 무방하다.

SVG에 지도 올리기

지도 데이터인 geojson 파일이나 topojson파일을 가지고 있다면, 이를 svg에 올리는 일은 생각보다 간단하다. 이미 polygon에 대한 정보들을 맵 데이터에 다 가지고 있기 때문에 위도경도를 내가 가진 svg파일 스케일로 바꿔줄 함수 하나를 만들어서 그대로 svg에 append 해주면 그만이다.하지만 라이브러리가 언제나 그렇든 이 작업을 하기 위한 "적당한" 명령어를 찾는 일이 언제나 일이다. (하지만 내가 처음부터 하는 거에 비해서 말도 안되게 편한 것은 사실이니 불평은 할 수 없다.)

//useEffect
const projection = d3.geoMercator().fitExtent(
      [
        [0, 30],
        [width, height - 200],
      ],
      mapData
    );

const geoGenerator = d3.geoPath().projection(projection);

const map = svg
      .selectAll("path")
      .data(mapData.features)
      .enter()
      .append("path")
      .attr("d", geoGenerator)
      .attr("fill", "#0e0e0e")
      .attr("stroke", "#545454")

이게 끝이다. 가장 위에 projection 이라는 함수를 만드는데 이 함수가 svg상의 좌표와 맵 데이터상의 좌표간 관계를 정의한다. d3이하에 붙은 goeMercator()함수는 좌표를 평면에 투영하기 위한 방법을 정의하고, firExtent()함수에 svg 를 입력해 맵 데이터가 어느 범위에 속해야 할지 정의한다.

어떻게 투영(projection)할지 정했다면 이 투영 함수를 이용하는 path 생성 함수를 만드는데 이게 위의 geoGenerator()이다. 이 함수는 맵 데이터를 받아 적용된 투영 방법을 따라 svg상의 좌표를 반환하게 된다. 그럼 아래는 일반적인 path를 그리는 d3 로직이다. 이로써 svg상에 지도가 성공적으로 로드 됐다.

profile
latemarch

0개의 댓글

관련 채용 정보