一个很好的例子是Nadieh Bremer用 D3.js 在弧上放置文本。一个包含许多图像的冗长博客,以下是其中的摘录:
翻转下半部分的文本
你可能已经觉得它已经完成了这个外观。但我发现下半部分的标签是颠倒的,很难阅读。如果这些标签被翻转,我会更喜欢它,这样我就可以再次从左到右阅读它们。
为此,我们需要沿下半部分切换当前弧路径的起点和终点坐标,以便从左到右绘制它们。此外,扫描标志必须设置为 0 才能获得从左到右以逆时针方式运行的弧
所以对于最后一幕,让我们在 .each() 语句中再添加几行代码
//Create the new invisible arcs and flip the direction for those labels on the bottom half
.each(function(d,i) {
//Search pattern for everything between the start and the first capital L
var firstArcSection = /(^.+?)L/;
//Grab everything up to the first Line statement
var newArc = firstArcSection.exec( d3.select(this).attr("d") )[1];
//Replace all the commas so that IE can handle it
newArc = newArc.replace(/,/g , " ");
//If the end angle lies beyond a quarter of a circle (90 degrees or pi/2)
//flip the end and start position
if (d.endAngle > 90 * Math.PI/180) {
var startLoc = /M(.*?)A/, //Everything between the capital M and first capital A
middleLoc = /A(.*?)0 0 1/, //Everything between the capital A and 0 0 1
endLoc = /0 0 1 (.*?)$/; //Everything between the 0 0 1 and the end of the string (denoted by $)
//Flip the direction of the arc by switching the start and end point (and sweep flag)
var newStart = endLoc.exec( newArc )[1];
var newEnd = startLoc.exec( newArc )[1];
var middleSec = middleLoc.exec( newArc )[1];
//Build up the new arc notation, set the sweep-flag to 0
newArc = "M" + newStart + "A" + middleSec + "0 0 0 " + newEnd;
}//if
//Create a new invisible arc that the text can flow along
svg.append("path")
.attr("class", "hiddenDonutArcs")
.attr("id", "donutArc"+i)
.attr("d", newArc)
.style("fill", "none");
});
与上一节相比,唯一改变的是添加了 if 语句。要翻转开始和结束位置,我们可以使用更多的正则表达式。当前起始 x 和 y 位置由大写字母 M 和大写字母 A 之间的所有内容给出。当前半径由大写字母 A 和 x 轴旋转的 0 0 1 之间的所有内容表示,大圆弧标志和扫旗。最后,结束位置由 0 0 1 和字符串结尾之间的 all 给出(在正则表达式中用 $ 表示)。
因此,我们将所有片段保存在不同的变量中,并使用 if 语句中的最后一行切换了开始和结束位置来构建/替换 newArc。
textPath 部分需要稍作改动。对于下半圆弧,dy 属性不应将标签抬高到圆弧路径上方,而应将标签降低到圆弧路径下方。所以我们需要一个小的 if 语句,它会产生两个不同的 dy 值。(为了能够在 if 语句中使用 d.endAngle,我在 .data() 步骤中将 donutData 替换为 pie(donutData)。您仍然可以使用 d.data 而不是仅使用 d 来引用数据本身可以在 .text() 代码行中看到。)
//Append the label names on the outside
svg.selectAll(".donutText")
.data(pie(donutData))
.enter().append("text")
.attr("class", "donutText")
//Move the labels below the arcs for those slices with an end angle greater than 90 degrees
.attr("dy", function(d,i) { return (d.endAngle > 90 * Math.PI/180 ? 18 : -11); })
.append("textPath")
.attr("startOffset","50%")
.style("text-anchor","middle")
.attr("xlink:href",function(d,i){return "#donutArc"+i;})
.text(function(d){return d.data.name;});