-
Notifications
You must be signed in to change notification settings - Fork 47
Selections
Wiki ▸ API Reference ▸ Core ▸ Selections
선택물(selection) 은 현재 문서에서 가져온 문서요소의 집합이다. D3는 문서요소 선택에 CSS3를 사용한다. 예를 들어서, 태그("div"), CSS클래스(".awesome"), ID("#foo"), Html 속성("[color=red]"), 컨테이너("parent child")로 선택할 수 있다. 선택자는 AND(".this.that")나 OR(".this .that")로 결합할 수도 있으며, 선택자를 지원하지 않는 브라우저를 위해서 D3이전에 Sizzle을 추가할 수 있다.
문서요소를 선택한 후에는 작업을 하기위해서 연산자(operator) 를 적용할 수 있다. 연산자는 컨텐츠의 속성(attributes), 스타일(styles), 프로퍼티(properties), HTML, 텍스트(text)를 가져오고(get) 지정(set)할 수 있다. Attribute등의 이런 값들에는 상수나 함수가 지정되고 선택한 각 요소별로 적용된다. 선택물은 데이터(data)와 연결할 수도 있다. 여기서 데이터는 데이터 중심의 변환을 위해 조작할 수 있다. 그리고 데이터 연결을 하면 하위 선택물로 들어가기(enter)과 나오기(exit)가 일어난다. 그래서 여러분은 데이터 변경으로 결과 문서요소를 추가(add)하거나 제거(remove)할 수 있다.
D3에서는 문서 수정을 위해서 for
를 이용한 루프문이나 재귀함수를 사용할 필요가 없다. 그 이유는 개별 문서요소를 순환하는 대신에 연산자를 이용해서 모든 선택물에 한번에 적용하기 때문이다. 하지만 여전히 개발자가 원하면 임의의 함수를 호출하는 each연산자를 이용해서 수동으로 문서요소를 루프 돌릴 수 있다. 그리고 선택물은 배열이라서 문서요소를 바로 접근할 수 있다( selection[0][0]
). D3는 메서드 채이닝을 지원한다. 이를 이용해서 여러 연산자를 적용할 때 표현을 간결하게 할 수 있다. 이 때 연산자의 반환값은 그 선택물이다.
D3는 문서요소를 선택하기 위해서 최상위 레벨의 메서드 두개를 제공한다. select과 selectAll이다. 이들은 셀렉터 문자열을 인자로 받는다. 전자는 일치하는 문서요소중 첫번째 문서요소만 선택하고, 후자는 문서상의 순서대로 일치하는 모든 문서요소를 선택한다. 인자는 셀렉터 문자열 뿐이 아니라 DOM 노드(node)를 받을 수도 있다. 그래서 jQuery나 개발툴($0
) 같은 서트파티 라이브러리와 통합이 용의하다.
# d3.select(selector)
인자로 지정한 셀렉터 문자열과 일치하는 첫번째 문서요소를 선택한다. 단일 문서요소를 선택해서 반환한다. 지정한 셀렉터 문자열과 일치하는 문서요소가 현재 문서에 없다면 빈 선택물을 반환한다. 셀렉터와 일치하는 문서요소가 여러개면 문서순서상 첫번째로 일치하는 문서요소를 선택한다.
# d3.select(node)
인자로 지정한 노드( node )를 선택한다. 이벤트 리스너에서 d3.select(this)
같이 선택한 노드나 document.body
같이 선택한 전역 노드에 대한 참조값을 이미 가지고 있을 때 유용하다.
# d3.selectAll(selector)
인자로 지정한 선택자( selector )와 일치하는 모든 문서요소를 선택한다. 문서요소는 문서상의 순서대로(위에서 아래로) 선택된다. 현재 문서에 선택자와 일치하는 문서요소가 없다면 빈 선택물을 반환한다.
# d3.selectAll(nodes)
인자로 지정한 문서요소의 배열을 선택한다. 이벤트 리스너에서 d3.selectAll(this.childNodes)
같이 선택한 노드나 document.links
같이 선택한 전역 노드에 대한 참조값을 이미 가지고 있을 때 유용하다. 인자 nodes 는 명확하게 배열은 아니다. 배열로 변경 가능한 유사배열이 동작한다.(NodeList
나 arguments
)
선택물은 말그대로 문서요소의 배열이다. 그리고 D3는 배열에 확장 메서드를 바인드한다. 그래서 선택한 모든 문서요소에 속성을 추가하는 것같은 선택된 문서요소에 연산자를 적용할 수 있다. 그 선택물은 일차원 배열이 아닌 선택물이 문서요소 배열의 배열인 그룹 이다. 이는 하위선택물의 계층구조를 유지한다. 지금은 이런 세부사항을 무시할 수도 있지만 이것이 선택물이 [node]
이 아니라 [[node]]
로 보이는 이유다. 중첩 선택물에 대한 상세내용은 Nested Selections를 보라.
선택물이 동작하는 방법을 배우기를 원한다면, 문서요소 선택을 여러분의 브라우저 개발 콘솔에서 살펴보라. 문서요소가 선택된 위치를 보고 그룹핑된 방법을 보기위해서 반환된 배열을 뒤저볼 수 있고 선택된 문서요소에 연산자를 적용해서 페이지 컨텐츠가 어떻게 바뀌는지 볼 수도 있다.
D3에는 문서 내용에 영향을 주는 연산자들이 있다. 그중 대부분은 데이터를 출력하는데 사용한다. 문서 내용을 지정하기 위해서 사용할 때 연산자는 현재 선택물을 반환한다. 그래서 간단한 구문으로 여러 연산자를 연결할 수 있다.
# selection.attr(name[, value])
value 인자를 지정하면 선택한 모든 문서요소에서 지정한 속성명의 값으로 지정한다. value 가 상수이면 모든 문서요소가 같은 속성값이 주어지지만 value 가 함수이면 각 선택된 문서요소별로 순서대로 적용된다. 이 함수는 전달인자로 datum d
와 인덱스 i
가 넘어오고 this
는 현재 DOM 문서요소다. 함수 만환 값이 각 문서요소의 속성 값지정에 사용된다. null 값은 지정한 속성을 제거한다.
value 인자를 지정하지 않으면 선택물에서 null이 아닌 첫번째 문서요소의 지정 속성 값을 반환한다. 이는 선택물이 확실하게 문서요소를 하나만 담고 있다는 사실을 개발자가 알고 있을 때만 유용하다.
XLink 네임스페이스에서 "href" 속성을 지정하기위해서 xlink:href
라고 하듯, name 인자에 네임스페이스 접두사가 있을 수 있다. 기본적으로 D3는 svg, xhtml, xlink, xml, xmlns 네임스페이스를 지원한다. 별도의 네임스페이스는 d3.ns.prefix를 사용해서 등록할 수 있다.
name 인자에는 name과 value 속성을 가진 객채도 올 수 있다.
# selection.classed(name[, value])
이 연산자는 "class"속성이 공백으로 구분된 토큰 세트라는걸 인식하는 "class" 속성을 지정하기 위한 편한 수단이다. 이런 전제하에 CSS 클래스를 편리하게 추가, 제거, 토글하기위해서 가능하면 classList 를 사용한다.
value 인자를 지정하면 선택 문서요소와 연관된 지정한 클래스를 지정한다. value 가 상수이면서 true에 해당하는 값인 경우, 아직 클래스가 할당되지 않았다면, 지정한 클래스를 모든 문서요소에 할당한다. false에 해당하는 값이면서 할당되었다면 그 클래스는 모든 선택 문서요소에서 제거된다. value 가 함수인 경우 그 함수는선택물의 각 문서요소별로 순서대로 동작한다. 전달인자는 데이텀 d
와 인덱스 i
이고 this
는 현재 DOM 문서요소이다. 함수의 반환값은 각 문서요소에 클래스를 적용하거나 제거하기 위해서 사용한다.
value 인자를 지정하지 않으면 선택물에서 null이 아닌 첫번째 문서요소가 지정한 클래스를 가지고 있는 경우에만 true를 반환한다. 그래서 보통은 선택물이 명확하게 하나의 요소만 가지고 있다는 것을 아는 경우에만 쓸모가 있다.
# selection.style(name[, value[, priority]])
value 인자를 넘기면 이 값을 선택한 모든 문서요소에서 지정한 이름의 CSS 스타일 프로퍼티에 지정한다. value 가 상수이면 모든 문서요소는 동일 스타일 값이 주어지지만 value 가 함수이면 그 함수는 선택된 각 문서요소별로 순서대로 동작한다. 함수에 전달되는 인자는 데이텀 d
와 인덱스 i
이고 this
는 현재 DOM 문서요소이다. 함수의 반환 값은 각 문서요소의 스타일 프로퍼티를 지정하는데 사용된다. null 값은 지정한 이름의 스타일 프로퍼티를 제거한다. 그리고 null이나 "important"로 priority 인자를 지정 수도 있다.
value 인자를 넘기지 않으면 선택물에서 null이 아닌 첫번째 문서요소의 지정 스타일 프로퍼티의 계산된 현재값을 반환한다. 이는 선택물이 명확하게 하나의 문서요소만 담고 있다는 사실을 알고 있을 때만 쓸모가 있다. 계산된 값은 이전에 지정했던 값과 다를 수 있다.특히 스타일 프로퍼티가 축약형 프로퍼티를 사용해서 지정했다면 말이다. (예를 들면 "font-size", "font-face"의 축약형은 "font"이다. )
# selection.property(name[, value])
몇가지 HTML 문서요소는 표준 속성이나 스타일 사용을 고려하지 않은 별란 프로퍼티를 가지고 있다. 예를 들어, 폼의 텍스트 필드는 value
라는 문자열 프로퍼티가 있고 체크박스는 checked
라는 블리언 프로퍼티가 있다. 여러분은 이런 프로퍼티 값을 가져오거나 값을 지정하기 위해서 property
연산자를 사용할 수 있다. 아니면 className
같이 기반 문서요소에서 다르게 다룰수 있는 필드를 사용할 수 있다.
value 인자를 넘기면 이 값을 선택한 모든 문서요소에서 지정한 이름의 프로퍼티에 지정한다. value 가 상수이면 모든 문서요소는 동일한 프로퍼티 값이 주어지지만, value 가 함수면 그 함수는 선택한 각 문서요소에서 순서대로 동작한다. 함수에 전달되는 인자는 데이텀 d
와 인덱스 i
이고 this
는 현재 DOM 문서요소이다. 함수의 반환값은 각 문서요소의 프로퍼티 값을 지정하는데 사용된다. null은 지정한 속성을 제거한다.
value 인자를 넘기지 않으면 선택물에서 null이 아닌 첫번째 문서요소의 지정 프로퍼티 값을 반환한다. 이는 선택물이 명확하게 하나의 문서요소만 담고 있다는 사실을 알고 있을 때만 쓸모가 있다.
# selection.text([value])
text
연산자는 textContent 프로퍼티에 기초한다. 그래서 텍스트 컨텐츠를 지정하면 존재하는 하위 문서요소는 모두 텍스트 컨텐츠로 교체된다.
value 인자를 넘기면 그 값을 선택한 모든 문서요소에서 텍스트 컨텐츠로 지정한다. value 가 상수이면 무든 문서요소는 같은 텍스트 내용이 되지만, value 가 함수이면 그 함수는 선택한 각 문서요소에서 순서대로 동작한다. 함수에 전달되는 인자는 데이텀 d
와 인덱스 i
이고 this
는 현재 DOM 문서요소이다. 함수의 반환값은 각 문서요소의 프로퍼티 값을 지정하는데 사용된다. null은 지정한 속성을 제거한다.
value 인자를 넘기지 않으면 선택물에서 null이 아닌 첫번째 문서요소의 지정 프로퍼티 값을 반환한다. 이는 선택물이 명확하게 하나의 문서요소만 담고 있다는 사실을 알고 있을 때만 쓸모가 있다.
# selection.html([value])
html
연산자는 innerHTML 프로퍼티에 기초한다. 그래서 inner HTML 컨텐츠를 지정하면 존재하는 하위 문서요소는 모두 지정한 HTML로 교체된다. 아니면, 데이터 중심적인 방법으로 HTML 컨텐츠를 생성하기위해서는 append
나 insert
연산자 사용을 선호할 수도 있다. 이 연산자는 비교적 적은 HTML을 원할 때를 위해서 고안되었다. 리치 포메팅이라 한다.
value 인자를 넘기면 그 값으로 선택한 모든 문서요소에서 inner HTML 컨텐츠를 지정한다. value 가 상수이면 모든 문서요소는 같은 inner HTML 컨텐츠가 되지만, value 가 함수이면 그 함수는 선택한 각 문서요소에서 순서대로 동작한다. 함수에 전달되는 인자는 데이텀 d
와 인덱스 i
이고 this
는 현재 DOM 문서요소이다. 함수의 반환값은 각 문서요소의 프로퍼티 값을 지정하는데 사용된다. null은 지정한 속성을 제거한다.
value 인자를 넘기지 않으면 선택물에서 null이 아닌 첫번째 문서요소의 지정 프로퍼티 값을 반환한다. 이는 선택물이 명확하게 하나의 문서요소만 담고 있다는 사실을 알고 있을 때만 쓸모가 있다.
# selection.append(name)
현재 선택물에서 각 문서요소의 마지막 자식으로 지정한 name 의 신규 문서요소를 추가한다. 그리고 추가한 문서요소를 포함한 새로운 선택물을 반환한다. 각각의 새로운 문서요소는 부모 문서요소의 데이터를 상속한다. 만약 있으면 하위 선택물에 대한 select도 같은 방식으로 동작한다. 전달인자 name 은 상수로 전달해야만 한다. 차후에 인자로 존재하는 문서요소나 동적으로 이름 생성을 위한 함수 사용을 지원할 계획이다.
문서요소의 태그 명(name)
에는 SVG 네임스페이스에 "text" 문서요소를 생성하기위한 "svg:text"같은 네임스페이스 접두사가 있을 수 있다. 기본적으로 D3는 svg, xhtml, xlink, xml, xmlns 네임스페이스를 지원한다. d3.ns.prefix를 사용해서 추가 네임스페이스를 등록할 수 있다.
# selection.insert(name, before)
현재 선택물의 각 문서요소에서 before 셀렉터와 일치하는 문서요소 앞에 name 으로 명명한 새로운 문서요소를 삽입한다. 그리고 삽입한 문서요소를 추가한 새로운 선택물을 반환한다. before 셀렉터와 일치하는 문서요소가 없으면 추가할 새 문서요소는 append처럼 맨 끝의 자식요소가 된다. 각각의 새로 추가되는 문서요소는 선택물의 각 문서요소의 데이터를 상속한다. 하위 선택물의 select에서도 같은 방식으로 동작한다. 두 전달인자는 반드시 상수여야 한다. 차후에 존재하는 문서요소나 동적으로 name 이나 before 셀렉터를 생성하는 함수 사용을 지원할 계획이다.
예를 들어, insert("div", ":first-child")
는 현재 선택물에 div 자식 노드를 앞에 추가한다.
문서요소의 태그 명(name)
에는 SVG 네임스페이스에 "text" 문서요소를 생성하기위한 "svg:text"같은 네임스페이스 접두사가 있을 수 있다. 기본적으로 D3는 svg, xhtml, xlink, xml, xmlns 네임스페이스를 지원한다. d3.ns.prefix를 사용해서 추가 네임스페이스를 등록할 수 있다.
# selection.remove()
현재 문서의 현재 선택물에서 문서요소를 제거한다. 문서에 다시 다시 추가하는 방법이 없기 때문에 일반적으로 문서요소를 제거한 후에는 그 선택물 사용을 멈춰야 한다. ( 추가는 바로 앞에서 설명한 append와 insert 참고)
# selection.data([values[, key]])
현제 선택물에 데이터 배열을 연결한다. 인자 values 는 숫자나 객체 배열 같은 데이터 값들의 배열이거나 그런 배열을 반환하는 함수다. key 함수를 넘기지 않으면, 전달한 배열의 첫번째 데이텀(datum)을 현재 선택물의 첫번째 문서요소에 할당하고, 두번째 데이텀은 두번째 문서요소에... 이런식으로 할당한다. 데이터가 문서요소에 할당되면, 그 값은 __data__
프로퍼티에 저장된다. 그래서 선택물을 재 선택 했을 때 데이터 사용이 가능하도록 데이터가 문서요소에 짝 달라붙게 만든다.
values 배열은 선택물 안의 각 그룹에 대해서 데이터를 지정한다. 그러므로 선택물이 여러개의 그룹(d3.selectAll를 이서서 selection.selectAll를 사용하는 경우처럼) 이면, data 는 배열을 반환하는 함수로 지정해야 한다(각 그룹별로 다른 데이터를 살당하려 한다고 가정할 때). 예를 들어, 최초 선택물에 2차원 배열을 연결했다 치자. 그러면 각 하위 선택물에는 안쪽 배열이 연결된다. 이런 경우의 values 함수는 항등 함수(identity function)이고, 이 함수는 자식 문서요소들을 가진 각 그룹에서 호출되고 부모 문서요소에 연결된 데이터를 전달받아서 이 데이터 배열을 반환한다.
var matrix = [
[11975, 5871, 8916, 2868],
[ 1951, 10048, 2060, 6171],
[ 8010, 16145, 8090, 8045],
[ 1013, 990, 940, 6907]
];
var tr = d3.select("body").append("table").selectAll("tr")
.data(matrix)
.enter().append("tr");
var td = tr.selectAll("td")
.data(function(d) { return d; })
.enter().append("td")
.text(function(d) { return d; });
문서요소에 데이터를 가공해서 연결하고 싶을 때는 인자 key 에 key 함수를 지정한다. 이 함수는 순차적인 동작에서는 기본 동작 방식이 달라진다. key 함수는 신규 데이터 배열의 각 원소별로 호출된 후, 선택물에서 존재하는 문서요소별로 다시 실행된다. 이 두가지 경우에 key 함수는 인자로 데이텀 d
와 인덱스 i
를 전달받는다. key 함수가 데이터의 원별로 싱행될 떄, 함수 내에서 this
는 데이터 배열이고, key 함수가 존재하는 선택물에서 실행될 때는 this
가 관련 DOM 문서요소다. key 함수의 반환 값은 사전에 연결한 데이터 기반으로 해당하는 문서요소의 데이텀을 연동하기 위한 문자열이다. 예를 들어서, 각 데이텀에 name
이라는 유일한 필드가 있다면, 다음 처럼 연결할 수 있다.
.data(data, function(d) { return d.name; })
key 함수와 데이터를 연결하는 더 자세한 예제는 A Bar Chart, Part 2 예제를 참고하자.
data
연산자를 실행한 결과는 갱신 된 선택물(전부가 아닌)로서, 선택한 DOM 문서요소에 인자로 넘긴 데이터의 원소를 할당해서 반환한다. 갱신 된 선택물에는 부족한(enter) 선택물과 남는(exit) 선택물로의 참조도 있다. 이를 통해서 데이터 기반으로 HTML 노드를 추가하거나 제거할 수 있다. 예를 들어, key 인자를 사용하지 않는 기본값을 사용하고 존재하는 선택물이 지정한 데이터 보다 문서요소가 적다면, 부족한 선택물은 새로운 데이터를 위한 플레이스 홀더로 채운다. 만약 데이터 보다 선택물에 문서요소가 더 많다면, 남는 선택물은 남는 문서요소로 채운다. 그리고 선택한 문서요소가 데이터와 개수가 같으면, 갱신된 선택물에 모든 노드가 있고 부족한 선택물과 남는 선택물은 비어있게 된다. 자세한 내용은 튜토리얼 Thinking With Joins 를 참고하라.
key 함수 인자를 사용하면 data
연산자로 노드 순서의 색인(index)도 바꿀 수 있다. 이 색인은은 모든 연산 함수값을 위해서 함수의 두번째 전달인자 i
로 전달된다. 하지만, 이 함수가 문서에 존재하는 DOM 문서요소를 자동으로 재배열하는건 아니다. 문서내 문서요소의 순서를 바꿀 때는 sort나 order를 써야한다.
values 인자를 넘기지 않으면 이 메서드는 선택물의 첫번째 그룹을 위한 데이터 배열을 반환한다. 반환 배열의 길이는 선택물의 첫번째 그룹의 길이가 되고 반환 배열 각 데이텀의 색인은 부합하는 선택물의 색인과 같게 된다. 이때, 만약 선택물의 문서요소 일부가 null 이거나 선택물이 데이터와 연결되어있지 않다면, 배열안의 해당 색인의 원소는 undefined가 된다.
주의사항: data
메서드를 사전에 연결된 데이터를 클리어 하는 용도로 사용하지 마라. 이때는 selection.datum를 사용한다.
# selection.enter()
이 메서드는 현재 선택물안에서 데이터에 부합하는 만큼 DOM 문서요소가 없으면 그 각 데이터 원소를 위한 플래이스 홀더 역활을 하는 부족한 선택물 을 반환한다. 이 메서드는 data연산자의 반환 선택물에만 정의되어있고, append, insert, select는 그 부족한 선택물에만 정의되어있다. 이 연산자들은 컨텐츠 편집 전에 부족한 노드를 가늠하는 용도로 사용한다. (부족한 선택물이 비었는지를 확인하기위한 empty도 있다.), 주의할 점은 enter 연산자는 부족한 선택물로의 참조만을 반환하므로 추가할 노드는 직접 추가해야 한다는 사실이다.
간단한 예를 들면, 선택은 했는데 선택물이 비여있는 경우를 고려해서 데이터와 매칭되도록 새로운 노드를 생성하기 원하는 경우다.
d3.select("body").selectAll("div")
.data([4, 8, 15, 16, 23, 42])
.enter().append("div")
.text(function(d) { return d; });
문서의 body
가 빈 채로 생성되었다는 가정하에, 위의 코드는 6개의 DIV 문서요소를 새로 생성하고 순서대로 body
에 추가한다. 그런 다음 DIV의 텍스트 컨텐츠를 매핑된 데이터 숫자로 채운다.
<div>4</div>
<div>8</div>
<div>15</div>
<div>16</div>
<div>23</div>
<div>42</div>
enter
메서드의 반환값 플레이스 홀더 노드에 대해 한가지 더 집을 내용은 이 노드들이 부모 노드에 위치한다는 사실이다. 그러나 enter
메서드의 반환 노드는 append와 insert만 지원한다.
append와 insert 메서드는 부족한 선택물 를 갱신된 선택물과 합쳐진다. 이는 부족한 선택물과 갱신된 선택물에 따로따로 연잔자들을 적용하는 것에 비해서 둘 간의 중복 코드를 줄일 수 있다. 부족한 노드의 플래이스 홀더를 가져온 후에 바로 이를 갱신한 선택물에 적용할 수 있지만, 흔한 경우는 아니지만 갱신한 선택물에서만 연산자를 사용하려는 경우에는 부족한 노드를 새로 가져오기 전에 갱신한 선택물에서 필요한 연산자를 사용하면 된다.
# selection.exit()
이 메서드는 데이터 원소의 수보다 현재 선택물의 DOM 문서요소가 많은 경우 그 남는 선택물 을 반환한다. 이 메서드는 data 연산자의 반환 선택물에만 정의되어있다. 일반적으로 remove를 사용하는 경우가 대부분이긴 하지만 남는 선택물 에는 부족한 선택물 과 달리 모든 연산자가 정의되어있다. 다른 연산자들이 있으므로 원하는 순간 전환(transition)을 끝낼 수 있다. 주의할 점은 exit 연산자는 남는 선택물 로의 참조만을 반환하므로 노드 제거는 여러분의 몫이다.
간단한 예를 들어보면, enter 연산자를 위한 앞의 예제에서 생성된 6개의 DIV 문서요소를 갱신하는 문제 대해 생각해보자. 이제 값을 몇개만 바꾼 새로운 데이터 배열을 이 문서요소에 결합한다.
var div = d3.select("body").selectAll("div")
.data([1, 2, 4, 8, 16, 32], function(d) { return d; });
그러면 data 연산자 호출 결과인 변수 div
는 갱신한 선택물 을 참조한다. 예제가 항등함수인 key 함수를 지정했고 새로운 데이터 배열이 이전 데이터 배열에도 있던 [4, 8, 16]을 가지고 있기 때문에 이 갱신한 선택물 은 세개의 DIV 문서요소를 가지고 있다. 이제 이전 데이터에서 남은 원소를 이야기해보자. 부족한 선택물 을 사용해서 [1, 2, 32] 신규 원소를 인스턴드해서 추가할 수 있다.
div.enter().append("div")
.text(function(d) { return d; });
아니면 남은 원소 [15, 23, 42]를 제거할 수있다.
div.exit().remove();
그러면 문서의 body는 다음처럼 보인다.
<div>4</div>
<div>8</div>
<div>16</div>
<div>1</div>
<div>2</div>
<div>32</div>
DOM 문서요소가 순서가 엉망인게 문제인데, 선택물 색인 i
는 (연산자 함수의 두번째 인자) 새 데이터 배열의 색인과 일치한다. 예를 들어, 이를 index 속성으로 할당할 수 있다.
d3.selectAll("div").attr("index", function(d, i) { return i; });
결과는 다음과 같다.
<div index="2">4</div>
<div index="3">8</div>
<div index="4">16</div>
<div index="0">1</div>
<div index="1">2</div>
<div index="5">32</div>
데이터 순서와 일치하는 문서 요수 순서를 원한다면 sort, order를 사용한다.
# selection.filter(selector)
선택물을 필터링한다. 즉, 인자 selector 가 true에 대항하는 문서요소만 담고 있는 선택물을 새로 반환한다. selector 는 함수이거나 ".foo"같은 CSS 셀렉터 문자열이다. 다른 연산자들 처럼, 이 함수는 데이텀 d
와 색인값 i
를 전달인자로 받고, 해당 DOM 문서요소를 컨텍스트 this
로 가진다. 배열의 내장 메서드 filter처럼, 원래 선택물의 색인값을 유지하지 않는다. 그리고 문서요소를 제거한 복사본을 반환한다. 색인값을 유지하고 싶다면 select를 사용한다. 예를 들어 홀수 번째만 모두 선택하려면,
var odds = selection.select(function(d, i) { return i & 1 ? this : null; });
같은 작업을 filter 함수를 사용하면,
var odds = selection.filter(function(d, i) { return i & 1; });
혹은 CSS 셀렉터를 사용하면,
var odds = selection.filter(":nth-child(odd)");
그러므로 문서요소의 부분집합을 적용하기위해서는 select나 filter 모두 사용 가능하다.
# selection.datum([value])
선택된 개별 문서요소와 엮인 데이터를 지정하거나 가져온다. selection.data 메서드와는 다르다. 이 메서드는 데이터 결합 연산을 하지 않는다. (그러므로 모자란 선택물과 남는 선택물 연산도 안한다.) 이 메서드는 selection.property 기반으로 구현되었다.
d3.selection.prototype.datum = function(value) {
return arguments.length < 1
? this.property("__data__")
: this.property("__data__", value);
};
value 인자를 넘기면 그 값으로 모든 선택 문서요소에서 엮인 데이터를 지정한다. value 가 상수이면 모든 문서요소가 같은 값이 주어지지만, value 가 함수면 그 함수는 각 선택 문서요소별로 호출되고, 이전 데이텀 d
와 현재 색인값 i
을 인자로 가지며 해당 DOM 문서요소를 컨텍스트 this
로 가진다. 이 함수는 각 문서요소의 데이터 지정에 사용된다. value 가 null이면 엮인 데이터를 삭제한다. 이 연산자는 색인값에 영향을 주지는 않는다.
value 인자를 넘기지 않으면 선택물에서 null이 아닌 첫번째 문서요소에 엮인 데이터를 반환한다. 선택물이 명확하게 하나의 문서요소만 가지고 있다는 사실을 알때만 유용하다.
주의: 이 메서드의 이전 이름은 "map"이 였다. "map"은 폐기되었다.
datum
메서드는 D3로 HTML5의 custom data 속성에 접근할 때 유용하다. 예를 들어 다음같은 문서요소가 있다.
<ul id="list">
<li data-username="shawnbot">Shawn Allen</li>
<li data-username="mbostock">Mike Bostock</li>
</ul>
여러분은 HTML5 내장 프로퍼티 dataset로 각 문서요소의 데이터를 지정해서 D3로 custom data 속성을 끌어올 수 있다.
selection.datum(function() { return this.dataset; })
예를 들어, username으로 문서요소를 정렬할 때 사용할 수 있다.
# selection.sort(comparator)
인자로 지정한 비교 함수 comparator 에 따라서 현재 선택물을 정렬한다. 비교 함수는 비교할 데이터 원소 a 와 b 를 인자로 갖는다. 반환 값은 양수, 음수, 0 중 하나다. 반환값이 음수면 a 가 b 보다 앞에 온다. 반환 값이 양수면 a 는 b 보다 뒤에 온다. 그렇지않으면 a 과 b 가 같다고 보고 순서는 임의로 정한다. sort는 아직 안정화 버전이 아니지만 이는 브라우저의 배열의 내장 메서드 sort와 동일 동작을 보장한다.
# selection.order()
문서 순서가 선택물 순서와 일치하 도록 문서에 문서요소를 다시 삽입한다. 데이터가 이미 정렬 되어있다면 sort()를 호출하는 것 과 같지만 더 빠르다.
# selection.on(type[, listener[, capture]])
현재 선택물의 각 문서요소에 인자로 지정한 타입(type) 의 이벤트 리스너(listener) 를 추가하거나 제거한다. type 은 "click", "mouseover", "submit" 같은 이벤트 타입의 이름을 의미하는 문자열이다. 인자로 넘긴 listener 는 각각의 DOM 문서요소에서 같은 방식으로 별도의 연산 함수처럼 호출된다. 이 함수는 데이텀 d
와 색인 i
을 인자로 가지며, 해당 DOM 문서요소가 this
가 된다. 리스너에서 현재 이벤트에 접근할 때는 전역 객체인 d3.event를 사용한다. 이벤트 리스너의 반환 값은 무시된다.
선택한 문서요소에 등록하려는 이벤트 타입의 리스너가 이미 등록되어 있다면, 이전 리스너는 신규 리스너가 추가되기 전에 삭제 된다. 동일 타입에 여러 리스너를 등록하려면 "click.foo"나 "click.bar"같은 네임스페이스를 옵션으로 넣어야 한다.
리스너를 제거할 때는 listener 인자에 null를 넘긴다. 어떤 이벤트 타입에서 모든 리스너를 제거하려면 listener에는 null을, type에는 .type
를 넘긴다. 예) selection.on(".foo", null)
W3C의 useCapture 플래그와 해당하는 capture 플래그를 지정할 수 있다. useCapture 플래그 는 계층구조의 하단에 있는 EventTarget으로 이벤트가 전파되기 전에 등록된 EventListener로 먼저 전파된다. 계층구조를 통해서 버블링 되는 이벤트는 capture를 사용해서 지명한 EventListener를 호출하지 않는다.
listener 인자를 넘기지 않으면 지정한 type 을 위해 현재 할당된 이벤트가 있을 경우 이를 반환한다.
# d3.event
만약 현재 발생한 이벤트가 있다면 그 이벤트를 반환한다. 이 전역 객체에는 on 연산자로 등록된 이벤트 리스터 콜백함수가 있다. 이벤트 리스너가 마지막 블럭안에 통보된 후에 해당 이벤트는 초기화된다. 이를 통해 리스너 함수는 다른 연산자 함수에서 같은 형태(데이터 d
과 색인 i
를 인자로 갖는)를 유지할 수 있다.
d3.event
객체는 DOM event로서 preventDefault()
와 stopPropagation()
같은 메서드는 물론이고 timeStampe
와 keyCode
같은 표준 이벤트 필드까지 구현한다. 네이티브 이벤트인 pageX, pageY를 사용할 때, d3.event
는 이벤트 좌표값을 해당 이벤트의 컨테이너 내부 시스템 좌표로 변환에 도움을 준다. 예를 들어 문서안에 SVG가 있다면 SVG 이미지 좌측 상단 기준의 이벤트 좌표가 필요하고, SVG 컨테이너에 변환(transform)이 일어났다면 해당 변환에 반영된 이벤트 좌표도 필요하다. 기본적인 마우스 좌표는 d3.mouse연산자를 사용하고, iOS 멀티터치의 좌표는 d3.touches를 사용하라.
# d3.mouse(container)
인자로 넘긴 container 기준으로 해당 d3.event의 x, y 좌표값을 바꾼다. container 는 svg:g나 svg:svg같은 HTML, SVG 컨테이너 문서요소가 된다. 좌표값으로 원소가 두개인 [ x, y ] 배열을 반환한다.
# d3.touches(container)
인자로 넘긴 container 기준으로 touches 속성 기반의 해당 d3.event의 x, y 좌표값을 바꾼다. container 는 svg:g, svg:svg같은 HTML, SVG 컨테이너 문서요소가 된다. 좌표값으로 원소가 두개인 배열의 배열 [ [ x1 , y1], [ x2 , y2], … ]를 반환한다.
# selection.transition()
해당 선택물를 위한 transition 를 시작한다. 바로 반영되지 않고 부드럽게 시간을 두고 애니메이션을 일으키는 연산자를 제외하고는 변환(Transition)은 대부분 선택물(selection)처럼 동작한다. 이다.
최상위 레벨의 선택 메서드는 모든 문서를 대상으로 조회를 하는 반면에 선택물의 select과 selectAll 연산자는 각 선택된 문서요소의 자손요소에서 조회를 한다. D3는 이를 "하위선택물"이라 부른다. 예를 들어, d3.selectAll("p").select("b")
는 모든 단락("p") 문서요소에서 첫번째 볼드("b") 문서요소를 반환한다. selectAll를 통한 하위선택물 선택은 조상요소에서 문서요소를 그룹짓는다. 그러므로, d3.selectAll("p").selectAll("b")
은 d3.selectAll("p b")
가 반환한 평면적인 선택물을 단락("p")문서요소로 그룹짓는다. select를 통한 하위 선택물 선택도 비슷하지만 그룹은 유지하고 데이터를 전파한다. 그룹은 데이터 연결에서 중요한 규칙을 수행한다. 그리고 함수형 연산자는 그룹안에서 해당 문서요소의 숫자형 색인에 의존한다.
# selection.select(selector)
해당 선택물의 각 문서요소에서 인자로 넘긴 selector 문자열과 부합되는 첫 번째 문서요소를 선택한다. 해당 선택물에 지정한 셀렉터에 해당한는 문서요소가 없다면 반환 선택물에서 해당 색인의 원소는 null이다. D3의 연산자((data는 예외)는 null 원소를 자동으로 무시한다. 이덕분에 존재하는 선택물의 색인이 유지된다.해당 문서요소에 관련 데이터가 있다면 그 데이터는 반환되는 하위선택물에 상속된다. 그리고 새로 선택된 문서요소와 엮인다. 셀렉터에 해당하는 문서요소가 여러개면 문서상에서 첫번째로 일치하는 문서요소만 선택된다.
selector 는 문서요소나 null를 반환하는 함수가 될 수도 있다. null은 일치하는 문서요소가 없을 때 사용한다. 함수 selector 는 전달인자로 해당 데이텀 d
, 색인값 i
를 갖고 this
가 해당 DOM 문서요소로서 다른 연산자 함수와 동일한 형태로 호출된다.
# selection.selectAll(selector)
해당 선택물의 각 문서요소에 대해서 전달인자 selector 문자열에 부합하는 자손 문서요소 모두를 선택한다. 반환 선택물은 해상 선택물의 조상 노드로 그룹화 된다. 만약 해당 선택물에 지정한 셀렉터에 부합하는 문서요소가 없다면 반환 선택물의 해당 색인 그룹은 텅 비게 된다. 그러나 반환 값인 하위선택물은 해당 선택물에서 데이터를 상속하지 않는다. data 값을 함수로 전달했다면 그 함수는 조상 노드의 데이터 d
와 그룹 색인값 i
에 기반해야 한다.
selectAll를 사용한 그룹핑은 추가 입력되는 모자란 플레이스 홀더 노드에도 영향을 준다. 그러므로 모자란 노드를 추가할 때 부모 노드를 지정하기위해서 아래처럼 selectAll를 사용한다.
d3.select("body").selectAll("div")
각 그룹핑 배열의 parentNode
프로퍼티로 각 그룹핑의 부모 노드를 볼 수 있다. selecton[0].parentNode
처럼 사용한다.
전달인자 selector 는 문서요소나 NodeList 배열을 반환하는 함수도 가능하다. 부합하는 문서요소가 없다면 빈 배열를 반환해도 된다. 함수 selector 는 전달인자로 해당 데이텀 d
, 색인값 i
를 갖고 this
가 해당 DOM 문서요소로서 다른 연산자 함수와 동일한 형태로 호출된다.
For advanced usage, D3 has a few additional operators for custom control flow.
D3는 사용편의를 위해서 흐름제어를 위한 몇가지 확장 연산자를 제공한다.
# selection.each(function)
해당 선택물의 각 문서요소 별로 전달인자 function 를 호출한다. 이 함수의 전달인자는 데이텀 d
와 색인값 i
이고 this
는 해당 DOM 문서요소이다. 이 연산자는 거의 모든 연산자 내부에서 사용되고 있으며, 선택된 문서요소별로 임의의 코드를 호출할 때 사용할 수 있다. 콜백 함수에서 d3.select(this)
를 사용하면 각 연산자가 재귀적으로 선택물을 처리하도록 사용할 수 있다.
# selection.call(function[, arguments…])
arguments 를 가진 function 를 해당 선택물에서 호출한다. call 연산자는 function 함수의 반환 값에 관계없이 항상 해당 선택물을 반환한다. call 연산자는 수동으로 함수 호출하는 것과 동일하지만 메서드 체인을 사용하기가 쉽다. 예를 들어, 여러 곳에 같은 방법으로 속성을 지정하기를 원한다고 하자. 그러면 코드를 가져다가 재사용 가능한 함수로 만든다.
function foo(selection) {
selection
.attr("name1", "value1")
.attr("name2", "value2");
}
이제 이 함수를 호출할 수도 있고,
foo(d3.selectAll("div"))
동일하게 이렇게 해도 된다.
d3.selectAll("div").call(foo);
호출된 함수의 this
컨텍스트도 해당 선택물이다. 이 연산자와 첫 번째 전달인자는 불필요한 면이 좀 있어서 차후에 개선될 지도 모른다.
# selection.empty()
해당 선택물이 비어있으면 true를 반환한다. null이 아닌 문서요소를 포함하지 않으면 그 선택물은 비어있다고 본다.
# selection.node()
해당 선택물에서 null이 아닌 첫번째 문서요소를 반환한다. 선택물이 비어있으면 null를 반환한다.
# d3.selection()
최상위(root) 선택물을 반환한다. d3.select(document.documentElement)
와 같다. 객체가 선택물인지(o instanceof d3.selection
)를 확인할 때 이 함수를 사용할 수 있다. 또한 선택물의 prototype으로 신규 메서드를 추가할 때 사용할 수도 있다. 예를들어, 체크박스의 "checked" 프로퍼티를 편하게 설정하기위한 메서드를 추가할 경우 다음처럼 작성할 수 있다.
d3.selection.prototype.checked = function(value) {
return arguments.length < 1
? this.property("checked")
: this.property("checked", value);
};