如何使用d3.js在Sunburst图表上定位文本标签

时间:2014-03-24 23:03:09

标签: javascript jquery svg d3.js sunburst-diagram

我正在尝试将文本放置在基于d3.js的Sunburst图表的楔形内部时遇到问题。即使在缩放时,text元素似乎也没有按照需要定位..

以下是我尝试过的代码的简短代码段,但未成功:

    var slices = svg.selectAll(".form")
            .data(function(d) { return data_slices; })
            .enter()
            .append("g");

        slices.append("path")
            .attr("d", arc)
            .attr("id",function(d,i){return d[2]+""+i;})
            .style("fill", function(d) { return color(d[2]);})
            .on("click",animate)
            .attr("class","form")
            .append("svg:title")
            .text(function(d) { return Math.round(d[0]*100)/100 +" , "+ Math.round(d[1]*100)/100; });

       //Something needs to change below....
      slices.append("text")
            .style("font-size", "10px")
            .attr("x", function(d) { return y(d[1]); })
            .attr("transform", function(d) { return "rotate(" + this.parentNode.getBBox().width + ")"; })
            .attr("dx", "6") // margin
            .attr("dy", ".35em") // vertical-align
            .text(function(d){return d[2]})
            .attr("pointer-events","none");

这是图表的小提琴

Fiddle

可能出现什么问题?任何人都可以告诉我或指导我如何将<text>置于svg <path>内。看起来解决方案是对此的一个小调整,但我甚至无法达到它试了很久..

任何有关解决方案的帮助/评论都将不胜感激......在此先感谢..

2 个答案:

答案 0 :(得分:3)

我认为这与您的目标接近:http://jsfiddle.net/4PS53/3/

所需的更改如下:

function getAngle(d) {
    // Offset the angle by 90 deg since the '0' degree axis for arc is Y axis, while
    // for text it is the X axis.
    var thetaDeg = (180 / Math.PI * (arc.startAngle()(d) + arc.endAngle()(d)) / 2 - 90);
    // If we are rotating the text by more than 90 deg, then "flip" it.
    // This is why "text-anchor", "middle" is important, otherwise, this "flip" would
    // a little harder.
    return (thetaDeg > 90) ? thetaDeg - 180 : thetaDeg;
}

slices.append("text")
    .style("font-size", "10px")
    .attr("x", function(d) { return d[1]; })
     // Rotate around the center of the text, not the bottom left corner
    .attr("text-anchor", "middle")
     // First translate to the desired point and set the rotation
     // Not sure what the intent of using this.parentNode.getBBox().width was here (?)
    .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")" + "rotate(" + getAngle(d) + ")"; })                                    
    .attr("dx", "6") // margin
    .attr("dy", ".35em") // vertical-align
    .text(function(d){return d[2]})
    .attr("pointer-events","none");

现在,为了使其适用于缩放,参考点发生变化,我们需要更多的基础设施。

  1. 制作g.form-container而不仅path.form可见/不可见。这意味着我们不必担心标签会单独消失。 (我添加了form-container类。)
  2. 计算新点并为其计算centroidrotation。这有点棘手,但并不太难:

    function change_ref(data_point, reference_point) {
        return [
            get_start_angle(data_point, reference_point),
            get_stop_angle (data_point, reference_point),
            data_point[2],
            get_level      (data_point, reference_point)
        ];
    }
    
    // And while doing transitioning the `text.label`:
    
    svg.selectAll('.label')
    .filter(
        function (b)
        {
            return b[0] >= new_ref[0] && b[1] <= new_ref[1] && b[3] >= new_ref[3];
        }
    ).transition().duration(1000)
     .attr("transform", function(b) {
         var b_prime = change_ref(b, d);
         return "translate(" + arc.centroid(b_prime) + ")" + 
                "rotate("    + getAngle(b_prime) +     ")"; 
     })
    

    我已将课程label添加到text

  3. 更新了演示: http://jsfiddle.net/4PS53/6/


    但是,我认为可能有更好的方式来呈现这些数据,尤其是。如果您允许缩放和平移:D3 put arc labels in a Pie Chart if there is enough space

答案 1 :(得分:1)

我在musically_ut代码中做了一些改进。

现在您可以从一个数据更改为另一个数据。

                $('#change').click(function () {
                if (animating) {
                    return;
                }

                if (currentSet == 0) {
                    currentSet = 1;
                    svg.selectAll(".form").filter(
                            function (d) {
                                return d[0] >= ref[0] && d[1] <= ref[1] && d[level_index] >= ref[level_index];
                            }
                        )
                         .transition().duration(1000)
                        .attrTween("d", changeDatarebaseTween(0, 1, 2, 3));

                    svg.selectAll('.label').filter(
                            function (d) {
                                return d[0] >= ref[0] && d[1] <= ref[1] && d[level_index] >= ref[level_index];
                            }
                        )
                         .transition().duration(1000)
                         .attr("transform", function (b) {
                             var b_prime = change_ref_CD(b);
                             return "translate(" + arc.centroid(b_prime) + ")" +
                                    "rotate(" + getAngle(b_prime) + ")";
                         })

                }
                else {
                    currentSet = 0;
                    svg.selectAll(".form").filter(
                            function (d) {
                                return d[2] >= ref[2] && d[3] <= ref[3] && d[level_index] >= ref[level_index];
                            }
                        )
                         .transition().duration(1000).attrTween("d", changeDatarebaseTween(2, 3, 0, 1));

                    svg.selectAll('.label').filter(
                            function (d) {
                                return d[2] >= ref[2] && d[3] <= ref[3] && d[level_index] >= ref[level_index];
                            }
                        )
                         .transition().duration(1000)
                         .attr("transform", function (b) {
                             var b_prime = change_ref_CD(b);
                             return "translate(" + arc.centroid(b_prime) + ")" +
                                    "rotate(" + getAngle(b_prime) + ")";
                         })
                }

                setTimeout(function () {
                    animating = false;
                }, 1000);
            });

编辑:http://jsfiddle.net/k1031ogo/3/

(代码可能更干净,复制/粘贴太多)