Svg D3 JS颠倒路径文本
在这种情况下,文本是否可以不颠倒显示 代码:Svg D3 JS颠倒路径文本,svg,d3.js,Svg,D3.js,在这种情况下,文本是否可以不颠倒显示 代码: 看起来,当d3创建一个填充弧时,它实际上创建了一个填充路径形状,该形状总是(?)从右侧开始,并顺时针进行-即使您反转startAngle和endAngle 如果您手动创建自己的圆弧路径,并将文本放在该路径上,则可以让它执行正确的操作 var cfg = { w:400, h:400 }; var g = d3.select("#testdiv").append("svg").attr("width", cfg.w).attr("h
看起来,当d3创建一个填充弧时,它实际上创建了一个填充路径形状,该形状总是(?)从右侧开始,并顺时针进行-即使您反转startAngle和endAngle 如果您手动创建自己的圆弧路径,并将文本放在该路径上,则可以让它执行正确的操作
var cfg = {
w:400,
h:400
};
var g = d3.select("#testdiv").append("svg").attr("width", cfg.w).attr("height", cfg.h).append("g")
var arct = d3.svg.arc()
.innerRadius(cfg.h / 5)
.outerRadius(cfg.h / 3)
.startAngle(Math.PI/2)
.endAngle(Math.PI*1.5);
var path = g.append("svg:path")
.attr("id","yyy")
.attr("d", arct)
.style("fill","blue")
.attr("transform", "translate("+cfg.w/2+","+cfg.h/6+")");
// Radius of line text sits on. A value of 3.5 makes it slightly closer to the
// outer radius (so text is placed in the middle of the blue line).
var textpathRadius = (cfg.h / 3.5);
// Make a path for the text to sit on that goes in an anti-clockwise direction.
var textpath = g.append("svg:path")
.attr("id","zzz")
.style("display","none")
.attr("d", "M -"+textpathRadius+" 0 A "+textpathRadius+" "+textpathRadius+" 0 0 0 "+textpathRadius+" 0")
.attr("transform", "translate("+cfg.w/2+","+cfg.h/6+")");
var text = g.append("text")
.style("font-size",30)
.style("fill","#F8F8F8")
.attr("dy",0)
.append("textPath")
.attr("xlink:href","#zzz")
.attr("startOffset","50%")
.style("text-anchor","middle")
.text("some text");
我以前从未使用过d3,因此可能有一种更简单或更干净的方法来完成我所做的事情。但至少它应该给你一个开始的地方
更新的小提琴:Nadieh Bremer就是一个很好的例子。一个包含许多图片的长篇博客,以下为摘录:
翻转下半部分的文本
你可能已经觉得这样的造型已经结束了。但我发现那些标签沿下半部分,是颠倒的,很难阅读。我更喜欢把标签翻过来,这样我就可以从左到右再看一遍
要实现这一点,我们需要沿下半部分切换当前圆弧路径的起点和终点坐标,以便从左向右绘制。此外,扫描标志必须设置为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 1、大圆弧标志和扫掠标志之间的所有内容表示。最后,结束位置由0 1和字符串结尾之间的all in给出(由正则表达式中的$表示)
因此,我们将所有部分保存在不同的变量中,并使用if语句中切换开始和结束位置的最后一行来构建/替换新弧
textPath部分需要做一些小的更改。对于下半弧,“dy”属性不应将标签升高到弧路径上方,而应将标签降低到弧路径下方。所以我们需要一个小的if语句,它将导致两个不同的dy值。
(为了能够在if语句中使用d.endAngle,我在.data()步骤中将donutData替换为pie(donutData)。您仍然可以通过使用d.data而不仅仅是d来引用数据本身,这可以在.text()代码行中看到。)
//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");
});
//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;});