d3.svg.line.radial
函数基于输入的极坐标(半径和角度)构建多个点之间的一系列(而不是弧线)。 (您链接的示例似乎绘制了一个圆形,但这是因为它将圆形分解成许多紧密间隔的点 - 尝试使用5个点代替50个点,您会发现曲线的形状不是一个真正的圆形。)
d3.svg.arc
函数根据innerRadius、outerRadius、startAngle和endAngle的值构造由两个同心圆弧和连接它们的直线组成的形状。
两种方法都以从“12 o'clock”(向上垂直)开始的弧度指定角度。 但是,在将径向线函数与弧数据对象配合使用时存在几个困难。
第一个问题是,线生成器希望传递一个多个点的数组,而不是单个对象。为了解决这个问题,您必须将路径元素的数据设置为重复两次的圆弧组对象的数组,一次用于圆弧的起点,一次用于终点,然后在
中使用函数来确定每个点的角度值应该使用startAngle还是endAngle。
这里是您fiddle的变体,创建这些路径。我没有费心让文本沿着路径运行,我只是用黑色绘制路径:
http://jsfiddle.net/MX7JC/688/
现在看到第二个问题:如果只给出两个点,则线生成器将只在它们之间创建一条直线。
请参见简单的曲线示例:
http://jsfiddle.net/4VnHn/5/
为了使用默认线生成器获得任何类型的曲线,您需要添加其他点以充当控制点,并将
line interpolate 方法更改为“open”选项,以便不绘制端点控制点。 我发现使开始和结束控制点在曲线的开始和结束点(围绕圆)的45度之外创建的曲线与我的简单示例中的弧接受度相似。
请看更好的简单曲线示例:
http://jsfiddle.net/4VnHn/6/
为了可视化,现在需要将数据对象重复四次放入数组中传递给曲线生成器,并且角度访问器现在需要一个 switch 语句来确定不同的点:
http://jsfiddle.net/MX7JC/689/
对于小甜甜圈片段的结果是可以接受的,但对于宽度超过 45 度的部分则不行。在这些情况下,控制点距离圆周太远,完全扰乱了曲线。曲线生成器并不知道任何关于圆的信息,它仅仅是试图平稳地连接点以显示从一个到下一个的趋势。
更好的解决方案是实际绘制一条弧,使用 SVG 路径的
弧记号。弧生成器使用弧符号,但它创建整个二维形状。要使用线生成器创建弧,您需要一个自定义线插值器函数,然后将其传递给线生成器的 interpolate 方法。
线生成器将执行自定义线插值器函数,传递已从极坐标转换为 x、y 坐标的点数组。从那里,您需要定义弧方程。由于弧函数还需要知道圆弧半径,我使用了一个嵌套函数--外部函数接受半径作为参数并返回将接受点数组作为参数的函数:
function arcInterpolator(r) {
return function(points) {
var allCommands = [];
var startAngle;
points.forEach(function(point, i) {
var angle = Math.atan2(point[0], point[1]);
var command;
if (i) command = ["A",
r,
r,
0,
+(Math.abs(angle - startAngle) > Math.PI),
+(angle < startAngle),
point[0],
point[1]
];
else command = point;
startAngle = angle;
allCommands.push( command.join(" ") );
});
return allCommands.join(" ");
};
}
实时示例:http://jsfiddle.net/4VnHn/8/
为了让它与您的甜甜圈图表配合使用,我从上面的版本开始生成直线,并更改了线条生成器的插值参数以使用我的自定义函数。我必须做的唯一额外更改是添加一个额外的检查,以确保图表上的任何角度都不超过360度(我确定这只是最后一个弧段的舍入问题,但导致我的函数将最终弧完全绕着圆形向后绘制):
var curveFunction = d3.svg.line.radial()
.interpolate( arcInterpolator(r-45) )
.tension(0)
.radius(r-45)
.angle(function(d, i) {
return Math.min(
i? d.endAngle : d.startAngle,
Math.PI*2
);
});
实时示例:http://jsfiddle.net/MX7JC/690/
最后,要将这些曲线用作文本路径:
- 将曲线设置为无描边和无填充;
- 为每个曲线赋予一个基于您的数据类别的唯一id值
(对于您的示例,可以使用甜甜圈标签加上数据标签来得到类似于“textcurve-Agg-Intl”的东西);
- 为每个标签添加
<textPath>
元素;
- 将文本路径的
xlink:href
属性设置为#
加上相同的数据的唯一id值。