D3.js
를 사용하기 위한 예제를 작성하면서 아무래도 selection
의 기본적인 개념을 정리해보는게 좋을 것 같다는 생각이 들었다. D3.js는 기본적으로 함수형 프로그래밍 기반으로 만들어졌으며, 이러한 특징들은 selection
을 통해서도 나타나는 것을 확인할 수 있다.
d3.select('body')
.append('div')
.html('Hello world!');
앞선 게시글에서 해당 코드를 통해 body
태그에 div
태그를 추가할 수 있었다. 각 함수들의 인터페이스를 살펴보면 현재 내가 하고자 하는 일에만 집중할 수 있는 것을 알 수 있다. select
함수 내부에서 어떤 일이 벌어지든 사용자는 선택하고자 하는 body
만 명시하면 된다. 이러한 점은 함수형 프로그래밍의 특징으로 볼 수 있다.
D3.js
는 선택을 통해 시각화 작업을 시작할 수 있다. 표준 W3C CSS 선택자나 jQuery
에 익숙하다면 D3.js
의 선택을 이용하는데 큰 불편함은 없을 것이다. 표준 W3C CSS 선택자 API는 선택이 아닌 선택자를 제공하기 때문에 다중 요소를 처리함에 있어서 번거로움이 있을 수 있다. 그러나 D3.js
에서는 선택 API를 제공하기 때문에 다중 요소에 대한 처리도 간단하게 처리할 수 있다.
// 표준 W3C CSS 선택자
const i = document.querySelectorAll('p').iterator();
let e;
while(e = i.next()) {
// 선택된 각 요소 처리를 한다.
console.log(e);
}
// D3.js
d3.selectAll('p')
.each(function (d, i) {
// 선택된 각 요소 처리를 한다.
console.log(this)
});
아래 코드는 CSS 선택자를 통해 단일 요소를 선택하고 'hello world'를 출력한다.
<p id="target"></p>
d3.select('p#target')
.text('hello world');
위 코드 처럼 select
함수는 D3.js
에서 단일 요소를 선택하기 위해 사용된다. 해당 함수는 HTML을 조작하는 수정자 함수를 연결할 수 있는 D3 선택 객체를 반환한다.
📝 D3 선택 객체는 몇가지 수정자 함수를 제공하는데 기본적인 것들을 살펴보자
- selection.attr: 주어진 속성을 조작할 수 있게 하는 함수
- selection.classed: CSS 클래스 요소를 조작할 수 있는 함수
- seection.style: CSS 스타일을 조작할 수 있는 함수
- selection.text: 텍스트 내용을 조작할 수 있는 함수
- selection.html: 내부 HTML을 조작할 수 있는 함수
이러한 수정자 함수들은 단일 선택 요소, 다중 선택 요소 모두 적용 가능하다.
여러 요소를 처리 하기 위해서는 단일 요소 선택만으로는 부족할 때가 있다. D3.js
는 다중 요소를 처리하기 위한 함수도 제공한다.
<div>1</div>
<div>2</div>
<div>3</div>
d3.selectAll('div')
.attr('class', 'red box');
selectAll
함수를 사용하여 위와 같이 간단하게 다중 요소에 class를 적용할 수 있다.
선택한 다중 요소들을 순회하면서 필요한 요소들을 처리해야 하는 상황들이 종종 있다. D3.js
는 선택 반복 API를 제공하여 개별 요소를 처리할 수 있게 해준다.
d3.selectAll('div')
.attr('class', 'red box');
.each(function(d, i) {
// select 함수는 단일 선택 요소를 반환한다.
d3.select(this).append('h1');
});
작업을 처리할 때 전체 범위를 처리하기 보다 특정 범위를 지정하여 선택하는 것이 편할 때가 있다. CSS 선택자를 사용한 부분 선택과 D3.js
의 select
함수를 사용한 부분 선택을 확인해보자.
// CSS 선택자 사용
d3.select('#section1 > div')
.attr('class', 'blue box');
// select 함수의 이중 사용
d3.select('#section1')
.select('div')
.attr('class', 'blue box');
위 두 가지 코드 모두 동일하게 동작한다. 차이점은 select
함수를 이중으로 사용하게 되면 선택 요소에 좀 더 유연한 처리를 할 수 있다. 아래 코드는 #section1
요소에 class를 적용한 코드이다.
// select 함수의 이중 사용
d3.select('#section1')
.attr('class', 'red border')
.select('div')
.attr('class', 'blue box');
CSS 선택자를 사용하면 중간 요소의 처리가 어렵지만, select
함수를 사용하면 중간 요소의 처리도 쉽게 할 수 있는 것을 확인할 수 있다.
개발 과정에서 D3 선택 요소를 제외한 원시 DOM 요소에 접근할 일이 생길 때가 있다. 아래 코드를 통해서 원시 DOM 요소에 접근하기 위한 방법을 확인 할 수 있다.
const rows = d3.selectAll('tr');
const headerElement = rows[0][0];
d3.select(headerElement).attr('class', 'table-header');
d3.select(rows[0][1]).attr('class', 'table-row-odd');
d3.select(rows[0][2]).attr('class', 'table-row-even');
d3.select(rows[0][3]).attr('class', 'table-row-odd');
위 코드는 효율적이지 못하지만 원시 DOM 요소에 접근하기 위한 예제로 작성되었다. 해당 코드는 each
함수로 작성되는 것이 더 효율적이다. D3.js
를 사용하면서 원시 DOM 요소를 접근할 일이 거의 없지만 필요한 경우에는 이런 식으로 접근이 가능하다.
D3.js
를 사용하여 시각화 작업을 처리하기 위한 첫번째 단계로 selection
이 사용되는데, 해당 내용을 통해 기본적인 selection
의 내용을 정리해 보았다.
📝 해당 게시글의 내용은 다양한 레시피로 보는 D3.js 쿡북 책을 참조하여 정리했습니다. 보다 디테일하고 정확한 내용을 참조하고 싶다면 해당 책을 읽어보시기 바랍니다.