d3.js を使用して、外側にラベルが付いたドーナツ グラフを作成しています。円の各スライスの重心に基づく三角法を使用して、ラベルを配置します。
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+"%"; });
私が最終的に達成しようとしているのは、円グラフの端の外側にあるラベルを再配置して、重複を防ぐことです。
私がこの問題を解決しようとした方法の 1 つは、ラベルを配置できるセットの「アンカー ポイント」を定義することです。問題は、セントロイドをアンカーにマッピングし、スライスとラベルの間の視覚的な対応関係を維持することです (スライスがスリムな場合は特に困難です)。
上の画像は、アンカーの可能な位置を示しています (表示されているスライスの重心)。これらの位置では、オーバーラップすることはできません。
問題を複雑にしているのは、ラベル (水平) が円グラフの上部または下部に近い場合、円グラフの右側または左側にある場合よりも簡単に重なり合うという事実です。
この問題にアプローチする方法についてのアイデアはありますか?
[編集] meetamit の提案に従って、以下を実装しました。
.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";
})
それは少し役立ち、ラベルにいくらかの余地を与えますが、それでもすべてのケースをカバーするソリューションを探しています...