2013-04-22 3 views
6

외부에 레이블이있는 도넛 형 차트를 만들 때 d3.js를 사용하고 있습니다. 원형의 각 조각의 중심에 기반한 삼각법을 사용하여 레이블을 배치합니다.d3js 원형 차트 주위에 레이블 재배포

g.append("g") 
     .attr("class", "percentage") 
     .append("text") 
      .attr("transform", function(d) 
       { 
        var c = arc.centroid(d); 
        var x = c[0]; 
        var y = c[1]; 
        var h = Math.sqrt(x*x + y*y); 
        return "translate(" + (x/h * obj.labelRadius) + ',' + (y/h * obj.labelRadius) + ")"; 
       } 
      ) 
      .attr("dy", ".4em") 
      .attr("text-anchor", function(d) 
       { 
        return (d.endAngle + d.startAngle)/2 > Math.PI ? "end" : "start"; 
       } 
      ) 
      .text(function(d) { return d.data.percentage+"%"; }); 

궁극적으로 달성하려는 것은 원형 차트의 가장자리 바깥에있는 레이블을 재정렬하여 중복을 방지하는 것입니다.

enter image description here 나는이 문제를 해결하기 위해 시도하는 방법 중

은 보장 레이블이 배치 될 수있다 "앵커 포인트"로 설정 정의하는 것입니다 그들이이 더 겹쳐도. 문제는 도심을 앵커에 매핑하고 조각과 레이블 간의 시각적 인 일치감을 유지하는 것입니다 (조각이 얇을 때 특히 어려움).

enter image description here

이미지는 상기 앵커의 가능한 위치를 도시한다 (조각의 무게 중심이 도시 됨). 이러한 위치에서는 겹치는 것이 불가능합니다.

레이블이 수평 인 경우 원형의 상단이나 하단에 가까울수록 원형의 오른쪽이나 왼쪽에있을 때보 다 쉽게 겹치게됩니다 .

이 문제에 접근하는 방법에 대한 아이디어가 있습니까?

.attr("dy", function(d) 
{ 
    var c = arc.centroid(d); 
     var x = c[0]; 
     var y = c[1]; 
     var h = Math.sqrt(x*x + y*y); 
     var dy = y/h * obj.labelRadius; 
    dy=dy*fontSizeParam*.14/heightParam); 
    return (dy)+"em"; 
}) 

그것은 약간의 도움, 그리고 라벨에 약간의 공간을 제공, 여전히하지만 모든 경우를 포함하는 솔루션을 찾고 :

[편집] meetamit의 제안에 따라, 나는 다음과 같은 구현했습니다. ..

+0

jsfiddle에서 지금까지 가지고있는 것의 예를 들어 주시겠습니까? – Jonah

+0

명확성을 위해 이미지를 추가했습니다. 코드에서 "앵커"솔루션을 구현하지 않았습니다. 여러 가지 경우에 실패 할 수있는 여러 가지 사례를 연구했습니다. – Cenobyte321

+0

나는 본다. 사실, 당신은 어려운 문제가 있습니다. 그리고 d3 그 자체와는 거의 관계가없는 것 : 그래프에 레이블을 배치하기위한 일반적인 알고리즘을 찾고 있습니다. 어떤 가정을 할 수 있습니까? 예를 들어 모든 조각이 초록색과 황색 조각만큼 작 으면 모든 레이블을 넣는 좋은 방법이 없을 것입니다. 특정 크기보다 작은 조각에 대해서만 마우스를 올리면 레이블을 표시하는 것은 어떻습니까? – Jonah

답변

0

두 개의 호를 만들 수 없습니까? 하나는 차트 용이고 다른 하나는 레이블 용입니까?

// first arc used for drawing the pie chart 
var arc = d3.svg.arc() 
    .outerRadius(radius - 10) 
    .innerRadius(0); 

// label attached to first arc 
g.append("text") 
    .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; }) 
    .attr("dy", ".35em") 
    .style("text-anchor", "middle") 
    .text(function(d) { return d.data.age; }); 

// second arc for labels 
var arc2 = d3.svg.arc() 
    .outerRadius(radius + 20) 
    .innerRadius(radius + 20); 

// label attached to second arc 
g.append("text") 
    .attr("transform", function(d) { return "translate(" + arc2.centroid(d) + ")"; }) 
    .attr("dy", ".35em") 
    .style("text-anchor", "middle") 
    .text(function(d) { return d.data.age; }); 
1

존 윌리엄스가 여기에 제시된 프로그래머 좋은, 실용적인 d3.js 기반 솔루션이있다 :

https://www.safaribooksonline.com/blog/2014/03/11/solving-d3-label-placement-constraint-relaxing/

그것은 합리적 제한, 예를 들어,와 경우에 잘 작동한다은 위에서 설명한대로 최대 12 개의 레이블. 더욱 진보 된 알고리즘에 대한 기사의 포인터도 있지만,이 간단한 접근법은 충분한 레이블 내용 제약 조건을 사용하면 다른 방법보다 더 질서 정연한 시각적 모양을 갖는 결과를 제공 할 수 있습니다.

관련 문제