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()는 첫 번째로 매칭되는 요소만 선택한다.

3개의 <h1>요소들 중에서 첫 번째만 데이터를 바꾼다.
2. 여러 요소 선택 (selectAll)
<script>
d3.selectAll("h1") // 모든 <h1> 요소 선택
.style("color", "blue") // 스타일 변경
.text("D3 is awesome!");
</script>

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()을 사용하면 공통 스타일 설정을 손쉽게 적용 가능하다.
'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 |