문제

I'm making a sunburst diagram creation tool using d3.js, and I'm trying to replicate the way that labels on this page flip so that they are never upside-down. The problem is that I would use rotate with the transform attribute, but that's already used to position the label. This is my code currently:

svg.selectAll("text")
    .data(partition.nodes)
    .enter()
    .append("text")
    .attr("transform", function(d) { return "rotate(" + ((d.x + d.dx / 2 - Math.PI / 2) / Math.PI * 180) + ")"; }) 
    .attr("x", function(d) { return Math.sqrt(d.y); })
    .attr("dx", "6") // margin
    .attr("dy", ".35em") // vertical-align
    .text(function(d) { return d.name;});

I found the tspan rotate attribute, but that turned out to be a red herring as it rotates the individual letters. I'm basing my diagram on this page.

Thanks in advance!

도움이 되었습니까?

해결책

One option is to nest the text inside a group. The group would get positioned mostly like you're currently positioning the text, except instead of using an "x" attribute, you'd use the transform attribute with a translate in addition to your existing rotate directive. Note that the order of the transformations matters here; you need to first rotate THEN translate.

Then you'd apply local transformation to the text within the group. I.e. it would get rotated 180 degrees if it needs to be flipped. This way the text doesn't need to be moved into position –– the group takes care of that –– but it will probably need to have small local adjustments when it's flipped (also, ir would probably have to be aligned right in this case).

The code below should more or less do it, though it's impossible for me to test and tweak it without a working jsFiddle.

svg.selectAll("g.label")
  .data(partition.nodes)
  .enter()
  .append("g")
  .attr("class", "label")
  .attr("transform", function(d) {
    // First, rotate the group (not the text) and then translate it
    // by the same amount that used to be applied via "x" attr
    return
      "rotate(" + ((d.x + d.dx / 2 - Math.PI / 2) / Math.PI * 180) + ") " +
      "translate(" + Math.sqrt(d.y) + ")";
  })
  .each(function(d, i) {
    d3.select(this) // select the containing group (which was just created above)
      .append('text') // append text inside the group
      .attr("dx", "6") // margin
      .attr("dy", ".35em") // vertical-align
      .attr("transform", function(d) {
        // Locally transform the text within the containing group:
        // Label should be flipped if group's rotation is greater than Math.PI (aka 180 degs)
        var shouldBeFlipped = d.x + d.dx / 2 - Math.PI / 2 > Math.PI;
        return "rotate(" + (shouldBeFlippled ? 180 : 0) + ")"
      })
      .text(function(d) { return d.name;});
  });
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top