본문 바로가기

Programming/D3.js

[01. D3.js] 004. D3-Selection

728x90

D3.js의 d3-selection 모듈은 DOM 요소를 선택하고 조작하는 기능을 제공한다. D3.js는 데이터를 바인딩하고, SVG 및 HTML 요소를 동적으로 생성하는 데 강력한 도구이며, d3-selection은 그 기초가 되는 핵심 개념이다.

 

1. 단일 요소 선택 (select)

<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
<div>
  <h1>1</h1>
  <h1>2</h1>
  <h1>3</h1>
</div>
<script>
  d3.select("h1") // 첫 번째 <h1> 요소 선택
    .style("color", "red") // 스타일 변경
    .text("Hello, D3!");
</script>

 

d3.select()는 첫 번째로 매칭되는 요소만 선택한다.

 

[그림 1.7] select의 실행화면

 

3개의 <h1>요소들 중에서 첫 번째만 데이터를 바꾼다.

 

2. 여러 요소 선택 (selectAll)

<script>
  d3.selectAll("h1") // 모든 <h1> 요소 선택
    .style("color", "blue") // 스타일 변경
    .text("D3 is awesome!");
</script>

 

 

[그림 1.8] selectAll의 실행화면

3. 속성 및 스타일 변경

d3.select("svg")
  .attr("width", 500)
.attr("height", 300);

 

위와 같이 attr를 통해 속성을 변경할 수 있다.

 

그리고 아래와 같이 style 또한 변경이 가능하다.

d3.select("h1").style("font-size", "24px").style("color", "purple");

 

4. 요소 추가 및 삭제 (append(), remove())

요소를 아래와 같이 추가 또는 삭제를 할 수 있다.

d3.select("body").append("p").text("새로운 문단 추가!");
d3.select("h1").remove();

 

5. 데이터바인딩

기존에는 데이터를 바인딩할 때 enter(), update(), exit()를 각각 호출해야 했지만, join()을 사용하면 한 줄로 정리할 수 있다.

 

- 기존 방식 (enter, update, exit 사용)

const data = [10, 20, 30];
const selection = d3.select("svg")
  .selectAll("circle")
  .data(data);

// Enter (새로운 데이터에 대한 요소 추가)
selection.enter()
  .append("circle")
  .attr("r", d => d)
  .attr("cx", (d, i) => i * 50 + 30)
  .attr("cy", 50)
  .style("fill", "blue");

// Update (기존 요소 업데이트)
selection
  .attr("r", d => d)
  .style("fill", "green");

// Exit (더 이상 필요 없는 요소 제거)
selection.exit().remove();

 

기존 방식은 data를 각 요소에 추가하기 위해 enter, 업데이트하기 위해 update, 삭제하기 위해 exit를 사용했다. 하지만 join을 사용하면 다음과 같이 직관적이고 간결해진다.

 

- join()을 사용한 간결한 방식

d3.select("svg")
  .selectAll("circle")
  .data(data)
  .join(
    enter => enter.append("circle")
      .attr("r", d => d)
      .attr("cx", (d, i) => i * 50 + 30)
      .attr("cy", 50)
      .style("fill", "blue"),
    update => update.style("fill", "green"),
    exit => exit.remove()
  );

 

더욱 줄여서 join만 사용한다면 다음과 같이 간편해진다.

const selection = d3.select("svg")
  .selectAll("circle")
  .data([10, 20, 30])
  .join("circle") // 자동으로 enter() + update 처리
  .attr("r", d => d)
  .attr("cx", (d, i) => i * 50 + 30)
  .attr("cy", 50)
  .style("fill", "purple");

// exit() 호출하여 필요 없는 요소 삭제
selection.exit().remove();

 

join("태그")를 사용하면 exit는 자동으로 처리되지 않으므로, 필요할 경우 exit().remove()를 추가해야 한다.

 

6. 이벤트핸들링

- 클릭 이벤트 추가(버튼 클릭 시 배경색을 변경하는 이벤트 처리)

d3.select("button")
  .on("click", function() {
    d3.select("body").style("background-color", "lightblue");
});

 

- 마우스 오버 이벤트(마우스를 올리면 빨간색, 떼면 파란색으로 변경)

d3.select("circle")
  .on("mouseover", function() {
    d3.select(this).style("fill", "red");
  })
  .on("mouseout", function() {
    d3.select(this).style("fill", "blue");
});

 

- 키보드 이벤트(사용자가 키를 누를 때마다 콘솔에 키 값 출력)

d3.select("body")
  .on("keydown", function(event) {
    console.log(`Key pressed: ${event.key}`);
});

 

- this를 활용한 요소 변경(사각형(rect)을 클릭하면 해당 요소만 색상 변경)

d3.selectAll("rect")
  .on("click", function() {
    d3.select(this).style("fill", "orange");
  });

 

7. Custom Control Flow

조금 더 고급 스킬을 사용하고 싶다면 다음을 익혀두면 좋다.

 

- each()를 사용한 커스텀 루프

d3.selectAll("p")
  .data(["Apple", "Banana", "Cherry"])
  .each(function(d, i) {
    d3.select(this).text(`Fruit ${i + 1}: ${d}`);
});

 

each()를 활용하여 각 요소에 개별적인 작업을 수행하며 d는 데이터, i는 인덱스, this는 현재 요소를 뜻한다.

 

- 부모-자식 데이터 접근 (each() 활용)

d3.selectAll(".parent")
  .each(function(parentData) {
    d3.select(this)
      .selectAll(".child")
      .text(d => `child ${d.name} of ${parentData.name}`);
});

 

부모 요소의 데이터를 활용하여 자식 요소를 업데이트할 때 유용하다.

 

- call()을 이용한 함수 체이닝

function setStyle(selection) {
  selection.style("color", "red").style("font-size", "20px");
}
d3.selectAll("p").call(setStyle);

 

call()을 사용하면 공통 스타일 설정을 손쉽게 적용 가능하다.

728x90

'Programming > D3.js' 카테고리의 다른 글

[01. D3.js] 003. D3-Axis  (0) 2024.10.02
[01. D3.js] 002. D3-Scale  (0) 2024.07.17
[01. D3.js] 001. D3.js란  (0) 2024.07.14