2013-03-08 4 views
3

HTML 페이지에 일부 svg 있습니다. 일부 데이터를 바인딩하고 해당 데이터를 기반으로 장식 요소를 추가하고 싶습니다. 내가해야 할 일은 다음과 같습니다.d3.js : 기존 svg에 데이터 바인딩. 어떤 selector.each합니까?

// pseudo-code 
selection = select all existing svg piece i want to decorate 

var datas = selection.each(function(d,i) { // each is right? maybe selection.datum() is better? 
    var data = this.(do something with the svg piece) 
    return data; 
}); 

// add elements with the "default" chain selection.data(datas).enter().append() 

내가 알아챈 것은 selection.each가 반환 된 데이터를 찾을 수있는 곳을 반환하지 않는다는 것입니다. 나는 이것이 방법이라고 생각하지만 바인딩 된 데이터를보기 위해 내가해야 할 일을 생각할 수 없다.

var datas = []; 
selection.each(function(d,i) { // each is right? maybe selection.datum() is better? 
    var data = this.(do something with the svg piece) 
    datas.push(data); 
}); 

이유 :

그래서 나는 같은 일부 더러운 해결을 할 필요가? 어떻게 수동으로 데이터를 배열로 밀어 넣고 기존의 svg 요소 내부에 데이터를 바인딩하지 않고도 비슷한 작업을 수행 할 수 있습니까?

여기에 jsFiddle example입니다.

또는, 당신은 코드를 선호하는 경우 :

HTML :

<div id="container"> 
    <svg> 
     <rect id="0" x="0" y="50" width="30" height="30"/> 
     <rect id="1" x="50" y="50" width="30" height="30"/> 
     <rect id="2" x="100" y="50" width="30" height="30"/> 
     <rect id="3" x="150" y="50" width="30" height="30"/> 
     <rect id="4" x="200" y="50" width="30" height="30"/> 
     <rect id="5" x="250" y="50" width="30" height="30"/> 
    </svg> 
</div> 

JS :

var svg = d3.select("#container svg"); 
var districts = svg.selectAll("rect"); 

var district_data = []; 
var _c = districts.each(function(d, i) { 
    var bbox = this.getBBox(); 
    var centroid = [ 
     bbox.x + bbox.width/2, 
     bbox.y + bbox.height/2 
    ]; 
    var ret = {centroid:centroid, position:bbox.x}; 
    district_data.push(ret); 
    return ret; 
}); 

// now, i'm expecting that _c should be something 
// similar to district_data 
console.log(_c); 

svg 
    .selectAll("circle") 
    .data(district_data) // i think i should use `_c` instead of manually created `district_data` but does not work 
    .enter() 
    .append("circle") 
    .attr("class", "district_circle") 
    .attr("cx", function(d){ return d.centroid[0]}) 
    .attr("cy", function(d){ return d.centroid[1]}) 
    .attr("r", 10) 
    .attr("fill", function(d){ return "rgb("+d.position+",0,0)"}); 

답변

2

첫째, 그것은 데이터의 배열을 반환하는 each() 방법을 기대하는 것은 잘못이다 . 선택을 반복하는 방법 일뿐입니다. 그것이 반환하는 것 (_c에 할당되는 것은 d3 선택 객체입니다 - each()을 호출하는 동일한 선택 객체입니다. 나는. _c == districts이 true로 평가됩니다. AFAIK, d3 선택 개체는 사용자가 원하는 방식으로 값을 수집하는 데 사용할 수있는 것을 제공하지 않습니다. 다시, districts는 D3 선택이 아닌 평면이기 때문에

일반적으로, 당신은 그 값을 수집하고 _c에 할당하지만, 불행히도 여기에 가능하지 않는 것하는 .map() 기능을 사용할 것 정렬. 그리고 map()을 호출하려고 시도하면 선택 영역의 각 요소를 실제로 반복하지 않을 것이며 this 객체가 SVG 요소에 할당되지 않기 때문에 js 오류가 발생합니다. getBBox()으로 전화해야합니다.

결론은 올바른 방법이라고 생각합니다. each()으로 반복하고 배열을 밀어 넣습니다.


좀 더 간결하게이 작업을 수행하는 하나의 다른 방법을 제안 할 수 있지만, 기존 SVG의 구조를 수정 필요 :

을 대신 rects가 형제 자매, 둥지 g 내부의 각각의 하나가 될 수있는의의. 같은 JS (안된)에이어서

<div id="container"> 
<svg> 
    <g> 
    <rect id="0" x="0" y="50" width="30" height="30"/> 
    </g> 
    <g> 
    <rect id="1" x="50" y="50" width="30" height="30"/> 
    </g> 
    ... 

: 위치 결정이 각 원과 RECT인가되므로

svg.selectAll('g') 
    .each(function(d, i) { // Note, d is actually undefined, bc no data-binding was done 
    var rect = d3.select(this).select('rect'); 
    var bbox = this.getBBox(); 
    var centroid = [ 
     bbox.x + bbox.width/2, 
     bbox.y + bbox.height/2 
    ]; 

    // Now create the circle, appending it to the group, 
    // as a sibling of its corresponding rect 
    var circle = d3.select(this).append('circle') 
    .attr("class", "district_circle") 
    .attr("cx", centroid[0]) 
    .attr("cy", centroid[1]) 
    .attr("r", 10) 
    .attr("fill", "rgb("+bbox.x+",0,0)"); 
    }); 

이는 반면, 이상적 위치는 것, 여전히 완전히 좋은 형태 아니다 그룹 수준에서 적용되며 달성하기가 그리 어렵지 않습니다. 하지만 이제 우리는 까다 롭다.

+0

좋은 아이디어!그것은 편리 할 수 ​​있었다! (정말로, 원형 차트로 원을 대체해야하고 selection.each() 콜백 내부에 중첩시켜야합니다.) .. 그룹에 있어야하는 이유는 무엇입니까? 'd3.select (this);만이 아니었을 까? – nkint

+0

@nkit, 예, 그룹화가 필요하지 않을 수도 있습니다. 당신은'd3.selectAll ('rect')'(평평한 계층 구조로 작업하고있는 것처럼)을 수행 한 다음, 필자가 나타낸 것처럼'each()'를 반복하여 그 원을 같은 부모에게 추가 할 수 있습니다. rects (즉, SVG 자체). 스타일을 사용하면 그룹을 사용하는 것이 더 깔끔하고 유연 해집니다. 이 기능을 사용하면 길 아래의 어느 지점에서나 모든 그룹을 선택하고 그 그룹에서 하나씩 차례로 반복하여 그 안에있는 "관련"직사각형 및 원에 액세스 할 수 있습니다. – meetamit