Javascript 圆图上的曲线标签(D3.js)

Javascript 圆图上的曲线标签(D3.js),javascript,d3.js,svg,Javascript,D3.js,Svg,所以,我基本上是在尝试用D3.js(v4)和JSON数据创建一个多级循环分区(也称为sunburst图) 我放置了一些标签,这些标签必须根据其在分区上的级别(圆)具有不同的角度: -标高0&&parseInt(d.data.level)90){ 角度=角度-180; } 结果=“平移(“+质心+”)旋转(“+角度+”); }否则{ 角度=(180/Math.PI*(arc.startAngle()(d)+arc.endAngle()(d))/2); 结果=“平移(“+质心+”)旋转(“+角度+”

所以,我基本上是在尝试用D3.js(v4)和JSON数据创建一个多级循环分区(也称为sunburst图)

我放置了一些标签,这些标签必须根据其在分区上的级别(圆)具有不同的角度:
-标高<3必须是弯曲的,并且“遵循”圆弧半径。
-标高==3必须笔直且垂直于弧半径

我没有使用textPath标记,因为我对SVG没有真正的经验,而且它看起来过于复杂,我也不知道如何使用它

以下是我的代码(没有JSON,但这是一个非常经典的代码,如果需要,我可以添加一部分):

var宽度=800;
var高度=800;
var半径=400;
var formatNumber=d3.format(“,d”);
var x=d3.scaleLinear().range([0,2*Math.PI]);
变量y=d3.scaleSqrt().range([0,radius]);
var arc=d3.arc()
.startAngle(函数(d){返回Math.max(0,Math.min(2*Math.PI,x(d.x0));})
.endAngle(函数(d){返回Math.max(0,Math.min(2*Math.PI,x(d.x1));})
.innerRadius(函数(d){返回setRadius(“inner”,d.data.level);})
.outerRadius(函数(d){return setRadius(“outer”,d.data.level);});
var svg=d3。选择(“图表”)
.append(“svg”)
.attr(“宽度”,宽度)
.attr(“高度”,高度)
.附加(“g”)
.attr(“变换”、“平移”(+width/2+)、“+(height/2)+”);
var hierarchy=d3.hierarchy(数据集)
.sum(函数(d){返回d.size;});
var partition=d3.partition();
svg.selectAll(“路径”)
.data(分区(层次结构).子体())
.enter().append(“路径”)
.attr(“id”,函数(d,i){return“path”+i;})
.attr(“d”,弧)
.attr(“笔划”、“白色”)
.attr(“笔划宽度”,“1px”)
.style(“fill”,函数(d){return(d.data.color)→d.data.color:'black';});
svg.selectAll(“文本”)
.data(分区(层次结构).子体())
.enter().append(“文本”)
.attr(“转换”,函数(d){return setLabelPosition(d);})
.attr(“文本锚定”、“中间”)
.attr(“路线基线”、“中间”)
.attr(“字体大小”,“18px”)
.attr(“fill”,函数(d){return d.data.textcolor;})
.text(函数(d){if(parseInt(d.data.level)>0&&parseInt(d.data.level)<4){return(d.data.name).toUpperCase();});
d3.select(self.frameElement)
.样式(“高度”,高度+px”);
功能设置半径(侧面、水平){
var结果=0;
var innerValues=[0、120、180、240、365];
var-outerValues=[0,180,240,365,400];
如果(!侧){
投掷误差;
}
如果(侧面=“内部”){
结果=内部值[级别];
}
如果(侧面=“外部”){
结果=外部值[级别];
}
返回结果;
};
功能设置位置(d){
var结果=“”;
var角=0;
var形心=弧形心(d);
if(parseInt(d.data.level)==3){
角度=(180/Math.PI*(arc.startAngle()(d)+arc.endAngle()(d))/2-90);
如果(角度>90){
角度=角度-180;
}
结果=“平移(“+质心+”)旋转(“+角度+”);
}否则{
角度=(180/Math.PI*(arc.startAngle()(d)+arc.endAngle()(d))/2);
结果=“平移(“+质心+”)旋转(“+角度+”);
}
返回结果;
};
结果是:

我的问题是,如何弯曲这些1级和2级标签(如有红色边框的标签),但保持我的3级标签目前的状态

这真是让人头疼,我做了很多搜索(在谷歌等网站上),但没有找到任何令人满意的答案。
如果可能的话,一个不使用文本路径的解决方案将非常棒,但是任何建议都是欢迎的

非常感谢你们,为我的英语感到抱歉(你们可能会看到这不是我的母语)


PS:这是D3.js v4。

我想答案在这里给出:我想答案在这里给出:
var width = 800;
var height = 800;
var radius = 400;
var formatNumber = d3.format(",d");
var x = d3.scaleLinear().range([0, 2 * Math.PI]);
var y = d3.scaleSqrt().range([0, radius]);

var arc = d3.arc()
    .startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x0))); })
    .endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x1))); })
    .innerRadius(function(d) { return setRadius("inner", d.data.level); })
    .outerRadius(function(d) { return setRadius("outer", d.data.level); });

var svg = d3.select("#chart")
    .append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(" + width/2 + "," + (height/2) + ")");

var hierarchy = d3.hierarchy(dataset)
    .sum(function(d) { return d.size; });

var partition = d3.partition();

svg.selectAll("path")
    .data(partition(hierarchy).descendants())
    .enter().append("path")
    .attr("id", function(d, i){ return "path" + i; })
    .attr("d", arc)
    .attr("stroke", "white")
    .attr("stroke-width", "1px")
    .style("fill", function(d) { return (d.data.color) ? d.data.color : 'black'; });

svg.selectAll("text")
    .data(partition(hierarchy).descendants())
    .enter().append("text")
    .attr("transform", function(d){ return setLabelPosition(d); })
    .attr("text-anchor", "middle")
    .attr("alignment-baseline", "middle")
    .attr("font-size", "18px")
    .attr("fill", function(d){ return d.data.textcolor; })
    .text(function(d){ if(parseInt(d.data.level) > 0 && parseInt(d.data.level) < 4){ return (d.data.name).toUpperCase(); }});

d3.select(self.frameElement)
    .style("height", height + "px");

function setRadius(side, level){
    var result = 0;
    var innerValues = [0, 120, 180, 240, 365];
    var outerValues = [0, 180, 240, 365, 400];
    if(!side){
        throw error;
    }
    if(side === "inner"){
        result = innerValues[level];
    }
    if(side === "outer"){
        result = outerValues[level];
    }
    return result;
};

function setLabelPosition(d){
    var result = '';
    var angle = 0;
    var centroid = arc.centroid(d);
    if(parseInt(d.data.level) === 3){
        angle = (180/Math.PI * (arc.startAngle()(d) + arc.endAngle()(d))/2 - 90);
        if(angle > 90){
            angle = angle - 180;
        }
        result = "translate(" + centroid + ")rotate(" + angle + ")";
    } else {
        angle = (180/Math.PI * (arc.startAngle()(d) + arc.endAngle()(d))/2);
        result = "translate(" + centroid + ")rotate(" + angle + ")";
    }
    return result;
};