2014-12-11 4 views
0

D3.js가 포함 된 onclick 핸들러에서 SVG 요소를 클래스별로 선택할 때 예기치 않은 동작을 관찰하고 있습니다. 간단한 예제를 제시하고 두 가지 JS 피들을 사용하여 문제를 설명합니다.이벤트 핸들러에서 d3 선택 : select vs selectAll

이 예제에는 두 개의 <rect>이 들어 있습니다. 그들은 라디오 버튼처럼 행동해야합니다 : 클릭하면 사각형이 독점적으로 선택됩니다. 다른 사각형이 이미 활성화되어 있으면 비활성화됩니다. 모든 활성 직사각형은 변수 currently_active에 저장됩니다.

testdata = [ 
    { 
    unique_id: "3-2-1", 
    y: 10 
    }, 
    { 
    unique_id: "2-3-1", 
    y: 40 
    } 
]; 

var svg = d3.select("body").append("svg"); 
var rects = svg.selectAll(".node").data(testdata); 

var currently_active = null; 

rects.enter().append("rect") 
.attr("x",10) 
.attr("y", function(d){return d.y;}) 
.attr("width", 60) 
.attr("height", 20) 
.attr("class", function(d){return "node node-"+d.unique_id;}) 
.on("click", function(d){ 
    var node_id = d.unique_id; 
    console.log(node_id); 
    if (currently_active == node_id) return; 
    if (currently_active) { 
     var thenode = svg.select(".node-"+currently_active); 
     thenode.style("fill", null); 
     currently_active = null; 
    } 
    var thenode = svg.select(".node-"+node_id); 
    thenode.style("fill", "#d11"); 

    currently_active = node_id; 
});  

이 간단한 버전은 의도 한대로 작동합니다. 참고 : 클릭 된 node_id은 JS 콘솔에 로그인됩니다.

  1. 의도 한대로 작동하지 : http://jsfiddle.net/bdy8z7dh/1/ 여기
    • 내가 최소한의 "재사용 가능한 차트"기능에 코드를 이동했다.
    • 이 버전은 의도 한대로 작동하지 않습니다. 첫 번째 클릭 이벤트에서 작동하지만 node_id는 다음 이벤트에서 정의되지 않습니다 (JS 콘솔 참조).
    • 이벤트 콜백에서 글로벌 d3.select을 사용하지 않기 때문에 "parent"요소를 변수에 저장했음을 유의하십시오. http://jsfiddle.net/bdy8z7dh/2/ 다음
      • 는 단순히 parent.selectAllparent.select을 변경하고 다시 의도 한대로 이제 예를 작동 :
    • 다시 구성 작업을한다.

또 다른 수정 대신 parent.select의 글로벌 d3.select 사용하는 것입니다. 그러나 내가 이해하지 못했던 것이 있습니다 : 왜 두 번째 바이올린이 작동하지 않습니까? 내가 뭘 놓치고 있니? 첫 번째 예제가 효과적이기 때문에 JS의 스코프와 관련이있을 수 있습니다.

추신. 나의 의도는 3 개의 코드 스 니펫을 모두 바이올린에 넣는 것이었지만 내 담당자는 여러 링크를 게시하기에는 너무 낮습니다. 재사용 가능한 차트에 대한 Mike Bostock의 기사에 링크하고 싶지만, 지금은 "재사용 가능한 차트쪽으로"검색하여 찾을 수 있습니다.

+1

이 부분을 자세히 살펴 보지 않았지만 'parent.select (...)'가 부모에서 자식으로 데이터를 상속한다고 생각됩니다. 즉,'parent'가 데이터를 변경하고'.select()'를하면, 선택된 엘리먼트는 새로운 데이터를 가지게됩니다. 이것은 * d3.select()와'.selectAll()'에서 발생하지 않습니다. –

+0

리드와 같지만 첫 번째 클릭에는 작동하지만 두 번째 클릭에는 작동하지 않는다고 설명합니까? 데이터는 한 번만 바인딩되며 .enter() 만 사용됩니다. 누군가가 차이점에 대해 자세히 설명해 주면 (또는 URL), LarsKotthoff에 대한 언급은 감사 할 것입니다. – jeinarsson

답변

0

@LarsKotthoff는 그의 코멘트에서 정확히 맞았습니다.

올바른 데이터로 요소를 초기화하므로 첫 번째 스위치가 잘 작동합니다. 그러나 첫 번째로 선택된 버튼에서 벗어나면 parent.select 호출은 선택한 버튼의 데이터를 처음에는 부모에서만 있었던 전체 데이터 배열로 변경합니다. 그러나 parent.selectAll은 상위 데이터를 전달하지 않으므로이 경우에는 문제가되지 않습니다.

관련 문서 섹션 여기 https://github.com/mbostock/d3/wiki/Selections#select입니다

는이를 확인하려면, 당신의 예에서 라인 (19)에 대한 또 다른 콘솔 출력을 추가 라고 말하면 약 selection.select()

현재 요소에 연관된 데이터가있는 경우이 데이터는 에 의해 반환 된 하위 선택에 상속되며 새로 선택된 선택된 요소에 자동으로 바인딩됩니다.

selection.selectAll()

현재 선택에서 데이터를 상속하지 않는 하위 선택; 그러나 데이터 값이 함수로 지정된 경우이 함수 은 조상 노드의 데이터 d와 그룹 색인 i와 함께 호출되어 하위 선택에 대한 데이터 바인딩을 결정합니다.

편집 :

당신은 아래에 코멘트에 올바른 다음과 같습니다 svg 요소가 전파 할 데이터가없는, 그래서 당신은 rect 요소에 직접 데이터를 할당하기 때문에 첫 번째 예는 작동합니다. selection.select()은 상위 항목에 데이터가있는 경우에만 하위 선택 항목의 데이터를 덮어 씁니다.

+0

감사합니다. 내 질문에 인라인 된 첫 번째 간단한 예제가 작동하는 이유는 svg에 전파 할 데이터가 없기 때문입니까? – jeinarsson

관련 문제