D3.js data 사용법 - Enter, Update, Exit

D3의 기본, data의 사용법을 소개한다.

기본 사용법

기본 사용법

dataset을 아래 같이 하면, <div> 요소에 데이터가 할당된다.

var dataset = [1, 2, 3, 4, 5, 6];
var div = d3.selectAll("div")
  .data(dataset);

예를 들어, <div> 요소가 없는 상태에서, style, text를 지정하게 되면,

d3.selectAll("div")
  .data(dataset)
  .enter()
  .append("div")
  .style("color", "red")
  .text(
    function (d) {
      return "this data is " + d;
    }
  );

아래와 같이 데이터 수의 <div> 요소가 생성된다.

코드 실행

기존 요소에 추가

아래와 같이 <div> 요소가 이미 2개 있다고 하자.

코드 실행

여기에 아래와 같이 새로운 요소를 추가하게 되면, 새로 생성된 요소가 업데이트된다.

d3.select("#view")
  .selectAll("div")
  .data(dataset)
  .enter()
  .append("div")
  .style("color", "red")
  .text(
    function (d) {
      return "this data is " + d
    }
  );

코드 실행

새로 생성된 부분을 enter 영역, 이미 있는 부분을 update 영역이라고 한다.

update 영역의 데이터 업데이트

이 update 영역의 style 적용하려면, 다음과 같이 하면된다.

d3.selectAll("div")
  .data(dataset)
  .style("color", "blue")
  .text(
    function (d) {
      return "this data is " + d;
    }
  );

코드 실행

update 영역과 enter 영역의 스타일을 동시에 변경

update 영역과 enter 영역의 스타일을 동시에 변경하고 싶은 경우가 많을 거라고 생각되는데, 그러한 경우에는 다음과 같이 하면 일괄로 변경할 수 있다.

var div = d3.selectAll("div")
  .data(dataset);

var divEnter = div.enter()
  .append("div");

var divUpdate = divEnter.merge(div);
divUpdate.style("color", "blue")
  .text(
    function (d) {
      return "this data is " + d
    }
  );

코드 실행

exit를 사용하여 여분의 요소 영역을 지정

반면에 이미 위와 같이 6개의 <div> 요소가 있고, 할당되는 데이터가 적은 경우에는 exit를 사용하여 여분의 요소 영역을 지정할 수 있다.

dataset = ['A', 'B'];
var div = d3.selectAll("div")
  .data(dataset)
  .style("color", "red")
  .text(function(d){return "this data is " + d;});

div.exit()
  .style("color", "green");

코드 실행

exit 영역의 데이터 지우기

exit 영역의 데이터는 지우는 것이 대부분이므로 아래와 같이 지우며 된다.

div.exit().remove();

코드 실행

Enter selection, Exit selection

D3의 가장 중요한 개념인 Update, Enter, Exit에 대해서는 알아보자.

Enter selection

먼저, 다음의 HTML 로 enter selection에 대해 설명하겠다.

<div class="fruitlist">
    <div class="fruit">Apple</div>
    <div class="fruit">Banana</div>
    <div class="fruit">Cherry</div>
</div>

data()data를 할당한 후에, DOM 요소보다 data의 수가 많을 때, data의 수가 많은 부분을 enter selection 이라고 부른다.

enter()로 enter selection에 요소를 추가할 수 있다. append()로 데이터를 추가하려면 selection.selectAll() 메소드를 사용하여 부모 요소로부터 선택해야 한다.

d3.select(".fruitlist")
  .selectAll(".fruit")
  .data([1, 2, 3, 4, 5])
  .enter()
  .append("div")
  .text(d => `Extra fruit number ${d}`)

코드 실행

Exit selection

다음으로 다음 HTML에서 Exit selection에 대해 알아본다.

<div>
    <div class="lunch">Burger</div>
    <div class="lunch">Hotdog</div>
    <div class="lunch">Curry</div>
    <div class="lunch">Pasta</div>
    <div class="lunch">Pizza</div>
</div>

DOM 요소보다 data수가 적을 때 data 수가 적은 부분을 exit selection 이라고 부른다. exit()으로 exit selection을 삭제할 수 있다.

d3.selectAll(".lunch")
  .data([1, 2, 3])
  .exit()
  .remove()

코드 실행

Update, Enter, Exit를 사용하여 필요한 경우에만 DOM을 업데이트

D3 튜토리얼을 보다 보면, 존재하지 않는 요소를 selectAll() 하고 나서, enter()를 실행하고 append()하는 패턴이 갑자기 나와서 당황하게 된다.

존재하지 않는 요소를 selectAll()를 하는 이유는 데이터 갱신시에 전회의 DOM 요소를 다시 이용하기 때문이다. 즉, 처음에는 존재하지 않는 요소를 selectAll() 하게 되지만, 두번째에는 존재하게 되는 것이다. 이 패턴을 사용해 보도록 하자.

이 예제에스는 div 요소가 처음에는 비어 있다.

<style>
 .chart div {
     background-color: powderblue;
     text-align: right;
     margin: 1px;
     transition: width 0.5s ease-in-out;
     animation: fade-in 0.5s ease 0s 1 normal;
 }
 @keyframes fade-in {
     0% { opacity: 0 }
     100% {opacity: 1 }
 }
</style>
<div class="chart"/>

데이터의 갱신을 알기 쉽도록 간단한 애니메이션을 붙이고 있다. 다음 코드로 무작위로 데이터를 업데이트한다.

function barchart(data) {
    const chart = d3.select(".chart")
                    .selectAll("div")
                    .data(data)
                    .style("width", function(d) { return d + "px"; })
                    .text( d => d);

    chart.enter()
                  .append("div")
                  .style("width", function(d) { return d + "px"; })
                  .text( d => d)

    chart.exit().remove();
}

function updatebar() {
    ndata = Math.floor(Math.random() * 5) + 5; // [5, 10)
    data = d3.range(0, ndata).map(() => Math.floor(Math.random() * 300));
    barchart(data);
}

setInterval(updatebar, 1000);



최종 수정 : 2024-01-18