D3.js pack 사용법

예제 프로그램

코드 확인

예제 코드

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>D3 hierarchy pack</title>
  <script src="https://d3js.org/d3.v7.min.js"></script>
</head>

<body>
  <svg width="800" height="600"></svg>

  <script>
    // 1. 데이터 준비
    var width = document.querySelector("svg").clientWidth;
    var height = document.querySelector("svg").clientHeight;
    var data = {
      "name": "A",
      "children": [
        { "name": "B", "value": 25 },
        {
          "name": "C",
          "children": [
            { "name": "D", "value": 10 },
            { "name": "E", "value": 15 },
            { "name": "F", "value": 10 }
          ]
        },
        { "name": "G", "value": 15 },
        {
          "name": "H",
          "children": [
            { "name": "I", "value": 20 },
            { "name": "J", "value": 10 }
          ]
        },
        { "name": "K", "value": 10 }
      ]
    };

    // 2. 그리려는 데이터 변환
    root = d3.hierarchy(data);
    root.sum(function (d) { return d.value; });

    var pack = d3.pack()
      .size([width, height])
      .padding(0);

    pack(root);

    // 3. SVG 요소 설정
    var node = d3.select("svg").selectAll(".node")
      .data(root.descendants())
      .enter()
      .append("g")
      .attr("transform", function (d) { return "translate(" + d.x + "," + (d.y) + ")"; });

    var color = ["Orange", "Khaki", "Ivory"];
    node.append("circle")
      .attr("r", function (d) { return d.r; })
      .attr("stroke", "black")
      .attr("fill", function (d) { return color[d.depth]; });

    node.append("text")
      .style("text-anchor", function (d) { return d.children ? "end" : "middle"; })
      .attr("font-size", "150%")
      .text(function (d) { return d.children ? "" : d.data.name; });
  </script>
</body>

</html>

예제 코드 설명

1. 데이터 준비

  var data = {
    "name": "A",
    "children": [
      { "name": "B", "value": 25 },
      {
        "name": "C",
        "children": [
          {"name": "D", "value": 10 },
          { "name": "E", "value": 15 },
          { "name": "F", "value": 10 }
        ]
      },
      { "name": "G", "value": 15 },
      {
        "name": "H",
        "children": [
          { "name": "I", "value": 20 },
          { "name": "J", "value": 10 }
        ]
      },
      { "name": "K", "value": 10 }
    ]
  };

그리려는 데이터를 준비한다. 데이터 구조에 대한 자세한 내용은 여기를 참조한다. 그리고, 모든 마지막 노드에 풍선 크기를 표시하는 value 값을 설정한다. 부모 노드의 크기는 자식, 손자 노드의 value 값의 합계 값을 다음 데이터 변환 시에 설정한다.

2. 그리려는 데이터 변환

root = d3.hierarchy(data);
root.sum(function(d) { return d.value; });

var pack = d3.pack()
  .size([width, height])
  .padding(0);

pack(root);

준비된 데이터를 그리려는 데이터 구조로 변경한다. 준비한 데이터 → hierarchy용 데이터 → 그리기 종류별(여기는 pack) 데이터와 2단계 변환이 필요하다.

root = d3.hierarchy(data);
root.sum(function(d) { return d.value; });

위의 함수에 data를 hierarchy용의 데이터 구조 root로 변경한 후(데이터 구조 상세는 이쪽을 참조), value 값을 설정하지 않은 노드에 자손 노드의 합계 value 값을 계산한다.

그런 다음에 pack용 데이터로 변경하는 함수를 호출한다.

  var pack = d3.pack()
    .size([width, height])
    .padding(0);

  pack(root);

d3.pack()에서 호출한 함수에 root를 인수로 설정하면 다음과 같은 데이터가 루트에 부여된다.

변수 설명
x 서클의 중심 x 좌표
y 서클의 중심 y 좌표
r 서클 반경

또, d3.pack()에는 이하의 설정이 가능한다.

pack.radius() 서클의 반경을 인수로 function(d) { return d.value; } 등으로 한 함수로 지정한다.
기본값은 null이다.
pack.size() pack 레이아웃 전체의 사이즈를 [폭, 높이]의 2가지 요소 배열로 설정한다.
인수가 설정되어 있지 않은 경우는 현재의 사이즈를 반환한다.
기본값은 [1, 1]이다.
pack.padding() 서클의 접선 사이의 거리를 지정한다.
기본값은 0입니다.

3. svg 요소 설정

// 3. svg 요소 설정
var node = d3.select("svg").selectAll(".node")
  .data(root.descendants())
  .enter()
  .append("g")
  .attr("transform", function(d) { return "translate(" + d.x + "," + (d.y) + ")"; });

var color = ["orange", "Khaki", "Ivory"];
node.append("circle")
  .attr("r", function(d) { return d.r; })
  .attr("stroke", "black")
  .attr("fill", function(d) { return color[d.depth]; });

node.append("text")
  .style("text-anchor", function(d) { return d.children ? "end" : "middle"; })
  .attr("font-size", "150%")
  .text(function(d) { return d.children ? "" : d.data.name; });

서클에 대한 svg 요소를 설정힌다. 시작하기 전에 "g" 요소를 설정하고 그 안에 "circle""text"를 설정한다.

데이터 할당 부분에서 아래와 같은 함수를 사용하고 있는데,

root.descendants()

이 함수는 중첩된 노드를 배열로 정렬해주는 함수이다.

"circle"에서는 처음에 색상 배열을 설정하고, "fill"의 속성으로 깊이 방향의 위치에 따른 색상을 설정하고 있다. 또한 "text"에서 설정한 "text-anchor"text의 위치를 설정하는 스타일이다.




최종 수정 : 2024-01-18