简体   繁体   English

在d3 sunburst v4中旋转标签

[英]Rotate Labels in d3 sunburst v4

I try to use the d3 v4 sunburst to visulize some data from a .json I can display the sunburst diagramm with the labels i want, but the labels on the left side are upside down. 我尝试使用d3 v4 sunburst来查看来自.json的一些数据我可以用我想要的标签显示sunburst diagramm,但是左边的标签是颠倒的。 I tried various methode, which i found on so or other sources but nothing works for me. 我尝试了各种方法,我在这样或其他来源找到,但没有什么对我有用。

Heres my coding 继承我的编码

<!DOCTYPE html>
<meta charset="utf-8">
<style>

path {
stroke: #fff;
}

text {
font-family: Arial, sans-serif;
font-size: 18px;
}

</style>
<body>
<script src="d3.min.js"></script>
<script src="data.js" charset="utf-8"></script>

<script language="javascript">

var width = 1200,
height = 1000,
radius = Math.min(width, height) / 2;

var x = d3.scaleLinear()
.range([0, 2 * Math.PI]);

var y = d3.scaleLinear()
.range([0, radius]);

var formatNumber = d3.format(",d");

var color = d3.scaleOrdinal(d3.schemeCategory20c);



var partition = d3.partition();

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 Math.max(0, y(d.y0)); })
.outerRadius(function(d) { return Math.max(0, y(d.y1)); });

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

 root = d3.hierarchy(root);
root.sum(function(d) { return d.size; });
svg.selectAll("path")
    .data(partition(root).descendants())
    .enter().append("g").attr("class", "node");

 path = svg.selectAll(".node")
  .append("path")
  .attr("d", arc)
  .style("fill", function(d) { return color((d.children ? d : 
 d.parent).data.name); })
  .on("click", click);

text = svg.selectAll(".node")
   .append("text")
      .attr("transform", function(d) { 
         return  "rotate(" + computeTextRotation(d) + ")"; 
      })

      .attr("x", function(d) { 
         return y(d.y0); 
      })
      .attr("dx", "6") // margin
      .attr("dy", ".35em") // vertical-align
      .text(function(d) { 
          return d.data.name === "root" ? "" : d.data.name
      });


  function click(d) {
  //Hide text while Sunburst transitions
  text.transition().attr("opacity", 0);

  svg.transition()
  .duration(750)
  .tween("scale", function() {
    var xd = d3.interpolate(x.domain(), [d.x0, d.x1]),
        yd = d3.interpolate(y.domain(), [d.y0, 1]),
        yr = d3.interpolate(y.range(), [d.y0 ? 20 : 0, radius]);
    return function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); };
   })
  .selectAll("path")
  .attrTween("d", function(d) { return function() { return arc(d); }; })
  .on("end", function(e, i) {
      // Check if the animated element's data e lies within the visible 
      // angle span given in d:
      if (e.x0 >= d.x0 && e.x0 < d.x1) {
          // get a selection of the associated text element
          var arcText = d3.select(this.parentNode).select("text");
          // fade in the text element and recalculate positions
          arcText.transition().duration(750)
              .attr("opacity", 1)

              .attr("transform", function() { return "rotate(" + 
  computeTextRotation(e) + ")" })
              .attr("x", function(d) { return y(d.y0); })
              .text(function(d) { 
                  return d.data.name === "root" ? "" : d.data.name
              });
      }
  });
  }

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

 // Interpolate the scales!
 function arcTween(d) {
  var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
  yd = d3.interpolate(y.domain(), [d.y, 1]),
  yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
  return function(d, i) {
 return i
    ? function(t) { return arc(d); }
    : function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return 
 arc(d); };
  };
 }

 function computeTextRotation(d) {
  var angle = (x((d.x0 + d.x1)/2) - Math.PI / 2) / Math.PI * 180;
  return (angle >  90 || angle < 270) ?  angle : 180 + angle ;

  }



  </script>

and this is the data.json: 这是data.json:

var root={
"id":"00000001", "name": "",
"children": [
{
"id":"00000003", "name":"#",
"children": [
{
"id":"00000003", "name":"2017",
"children": [
{
"id":"00000002", "name":"Nov","size":           12608.00},
] },
] },
{
"id":"00000010", "name":"A",
"children": [
{
"id":"00000010", "name":"2017",
"children": [
{
"id":"00000003", "name":"Dez","size":          119215.80},
{
"id":"00000004", "name":"Jul","size":            5000.00},
{
"id":"00000005", "name":"Jun","size":           45536.00},
{
"id":"00000006", "name":"Mai","size":           18500.00},
{
"id":"00000007", "name":"Nov","size":           20107.31},
{
"id":"00000008", "name":"Okt","size":           70303.00},
{
"id":"00000009", "name":"Sep","size":           11240.00},
] },
] },
{
"id":"00000018", "name":"DIR",
"children": [
{
"id":"00000018", "name":"2017",
"children": [
{
"id":"00000010", "name":"Aug","size":          705110.07},
{
"id":"00000011", "name":"Dez","size":          667101.28},
{
"id":"00000012", "name":"Jul","size":          684326.04},
{
"id":"00000013", "name":"Jun","size":          975615.11},
{
"id":"00000014", "name":"Mai","size":          625832.83},
{
"id":"00000015", "name":"Nov","size":          488444.60},
{
"id":"00000016", "name":"Okt","size":          578924.89},
{
"id":"00000017", "name":"Sep","size":          755968.14},
] },
] },
{
"id":"00000020", "name":"EU",
"children": [
{
"id":"00000020", "name":"2017",
"children": [
{
"id":"00000018", "name":"Nov","size":          505400.00},
{
"id":"00000019", "name":"Sep","size":          505400.00},
] },
] },
{
"id":"00000028", "name":"NAT",
"children": [
{
"id":"00000028", "name":"2017",
"children": [
{
"id":"00000020", "name":"Aug","size":         1882688.00},
{
"id":"00000021", "name":"Dez","size":          268861.33},
{
"id":"00000022", "name":"Jul","size":         1174708.67},
{
"id":"00000023", "name":"Jun","size":         3860969.90},
{
"id":"00000024", "name":"Mai","size":          917468.75},
{
"id":"00000025", "name":"Nov","size":         2233213.25},
{
"id":"00000026", "name":"Okt","size":         2340277.41},
{
"id":"00000027", "name":"Sep","size":         1667464.09},
] },
] },
{
"id":"00000036", "name":"X",
"children": [
{
"id":"00000036", "name":"2017",
"children": [
{
"id":"00000028", "name":"Aug","size":          249939.37},
{
"id":"00000029", "name":"Dez","size":          289363.70},
{
"id":"00000030", "name":"Jul","size":           98847.32},
{
"id":"00000031", "name":"Jun9","size":            7799.00},
{
"id":"00000032", "name":"Mai","size":           19520.00},
{
"id":"00000033", "name":"Nov","size":         1177309.62},
{
"id":"00000034", "name":"Okt","size":          224970.85},
{
"id":"00000035", "name":"Sep","size":          167309.57},
] },
] },
] }

This is how it looks like at the moment 这就是目前的样子
]

as you can see the left side is upside down 你可以看到左侧是颠倒的

The idea is to rotate by an additional 180° text labels which have an angle between 90° and 270° (left part of the graph). 这个想法是通过额外的180°文本标签旋转,角度在90°和270°之间(图的左侧部分)。

Here is the updated demo: 这是更新的演示:

 <meta charset="utf-8"> <style> path { stroke: #fff; } text { font-family: Arial, sans-serif; font-size: 18px; } </style> <body> <script src="https://d3js.org/d3.v4.min.js"></script> <script language="javascript"> var root={ "id":"00000001", "name": "", "children": [ { "id":"00000003", "name":"#", "children": [ { "id":"00000003", "name":"2017", "children": [ { "id":"00000002", "name":"Nov","size": 12608.00}, ] }, ] }, { "id":"00000010", "name":"A", "children": [ { "id":"00000010", "name":"2017", "children": [ { "id":"00000003", "name":"Dez","size": 119215.80}, { "id":"00000004", "name":"Jul","size": 5000.00}, { "id":"00000005", "name":"Jun","size": 45536.00}, { "id":"00000006", "name":"Mai","size": 18500.00}, { "id":"00000007", "name":"Nov","size": 20107.31}, { "id":"00000008", "name":"Okt","size": 70303.00}, { "id":"00000009", "name":"Sep","size": 11240.00}, ] }, ] }, { "id":"00000018", "name":"DIR", "children": [ { "id":"00000018", "name":"2017", "children": [ { "id":"00000010", "name":"Aug","size": 705110.07}, { "id":"00000011", "name":"Dez","size": 667101.28}, { "id":"00000012", "name":"Jul","size": 684326.04}, { "id":"00000013", "name":"Jun","size": 975615.11}, { "id":"00000014", "name":"Mai","size": 625832.83}, { "id":"00000015", "name":"Nov","size": 488444.60}, { "id":"00000016", "name":"Okt","size": 578924.89}, { "id":"00000017", "name":"Sep","size": 755968.14}, ] }, ] }, { "id":"00000020", "name":"EU", "children": [ { "id":"00000020", "name":"2017", "children": [ { "id":"00000018", "name":"Nov","size": 505400.00}, { "id":"00000019", "name":"Sep","size": 505400.00}, ] }, ] }, { "id":"00000028", "name":"NAT", "children": [ { "id":"00000028", "name":"2017", "children": [ { "id":"00000020", "name":"Aug","size": 1882688.00}, { "id":"00000021", "name":"Dez","size": 268861.33}, { "id":"00000022", "name":"Jul","size": 1174708.67}, { "id":"00000023", "name":"Jun","size": 3860969.90}, { "id":"00000024", "name":"Mai","size": 917468.75}, { "id":"00000025", "name":"Nov","size": 2233213.25}, { "id":"00000026", "name":"Okt","size": 2340277.41}, { "id":"00000027", "name":"Sep","size": 1667464.09}, ] }, ] }, { "id":"00000036", "name":"X", "children": [ { "id":"00000036", "name":"2017", "children": [ { "id":"00000028", "name":"Aug","size": 249939.37}, { "id":"00000029", "name":"Dez","size": 289363.70}, { "id":"00000030", "name":"Jul","size": 98847.32}, { "id":"00000031", "name":"Jun9","size": 7799.00}, { "id":"00000032", "name":"Mai","size": 19520.00}, { "id":"00000033", "name":"Nov","size": 1177309.62}, { "id":"00000034", "name":"Okt","size": 224970.85}, { "id":"00000035", "name":"Sep","size": 167309.57}, ] }, ] }, ] } var width = 1200, height = 1000, radius = Math.min(width, height) / 2; var x = d3.scaleLinear() .range([0, 2 * Math.PI]); var y = d3.scaleLinear() .range([0, radius]); var formatNumber = d3.format(",d"); var color = d3.scaleOrdinal(d3.schemeCategory20c); var partition = d3.partition(); 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 Math.max(0, y(d.y0)); }) .outerRadius(function(d) { return Math.max(0, y(d.y1)); }); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + (height / 2) + ")"); root = d3.hierarchy(root); root.sum(function(d) { return d.size; }); svg.selectAll("path") .data(partition(root).descendants()) .enter().append("g").attr("class", "node"); path = svg.selectAll(".node") .append("path") .attr("d", arc) .style("fill", function(d) { return color((d.children ? d : d.parent).data.name); }) .on("click", click); text = svg.selectAll(".node") .append("text") .attr("transform", function(d) { var rotation = computeTextRotation(d); var translation = y(d.y0); if (rotation > 90 && rotation < 270) { rotation = rotation + 180; translation = -translation - 13; } return ( "rotate(" + rotation + ")" + "translate(" + translation + ",0)" ); }) .attr("text-anchor", function(d) { var rotation = computeTextRotation(d); return (rotation > 90 && rotation < 270) ? "end" : "start"; }) .attr("dx", function(d) { var rotation = computeTextRotation(d); return (rotation > 90 && rotation < 270) ? -6 : 6; }) .attr("dy", ".35em") // vertical-align .text(function(d) { return d.data.name === "root" ? "" : d.data.name }); function click(d) { //Hide text while Sunburst transitions text.transition().attr("opacity", 0); svg.transition() .duration(750) .tween("scale", function() { var xd = d3.interpolate(x.domain(), [d.x0, d.x1]), yd = d3.interpolate(y.domain(), [d.y0, 1]), yr = d3.interpolate(y.range(), [d.y0 ? 20 : 0, radius]); return function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); }; }) .selectAll("path") .attrTween("d", function(d) { return function() { return arc(d); }; }) .on("end", function(e, i) { // Check if the animated element's data e lies within the visible // angle span given in d: if (e.x0 >= d.x0 && e.x0 < d.x1) { // get a selection of the associated text element var arcText = d3.select(this.parentNode).select("text"); // fade in the text element and recalculate positions arcText.transition().duration(750) .attr("opacity", 1) .attr("transform", function() { return "rotate(" + computeTextRotation(e) + ")" }) .attr("x", function(d) { return y(d.y0); }) .text(function(d) { return d.data.name === "root" ? "" : d.data.name }); } }); } d3.select(self.frameElement).style("height", height + "px"); // Interpolate the scales! function arcTween(d) { var xd = d3.interpolate(x.domain(), [dx, dx + d.dx]), yd = d3.interpolate(y.domain(), [dy, 1]), yr = d3.interpolate(y.range(), [dy ? 20 : 0, radius]); return function(d, i) { return i ? function(t) { return arc(d); } : function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); }; }; } function computeTextRotation(d) { var angle = (x((d.x0 + d.x1)/2) - Math.PI / 2) / Math.PI * 180; return (angle > 90 || angle < 270) ? angle : 180 + angle ; } </script> 

Let's go step by step: 让我们一步一步走:

First we'll apply this conditional additional rotation: 首先,我们将应用此条件额外轮换:

.attr("transform", function(d) {
  var rotation = computeTextRotation(d);
  if (rotation > 90 && rotation < 270)
    rotation = rotation + 180;
  return "rotate(" + rotation + ")";
})

But then all labels are on the right part of the graph... 但是所有标签都在图表的右侧...

This means we then have to reverse the translation for left labels: 这意味着我们必须反转左标签的翻译:

.attr("transform", function(d) {
  var rotation = computeTextRotation(d);
  var translation = y(d.y0);
  if (rotation > 90 && rotation < 270) {
    rotation = rotation + 180;
    translation = -translation;
  }
  return (
    "rotate(" + rotation + ")" +
    "translate(" + translation + ",0)"
  );
})

Here I've prefered to perform the translate using the transform operator rather than the x attribute the text element. 在这里,我更喜欢使用transform运算符而不是x属性text元素来执行translate

But then the text is not exactly at the right spot in its shape... 但后来文字并没有完全处于形状的正确位置......

This can be fixed by modifying the text-anchor of labels for left elements to be at the end of the text. 这可以通过将左边元素的标签的text-anchor修改为text-anchor的末尾来修复。 We can do this by using this attribute: 我们可以使用以下属性来完成此操作:

.attr("text-anchor", function(d) {
  var rotation = computeTextRotation(d);
  return (rotation > 90 && rotation < 270) ? "end" : "start";
})

And finally, it's still not perfect since we'd like the same margin for labels on the left than on the right. 最后,它仍然不完美,因为我们希望左侧标签的边距与右侧相同。 We can thus adjust our translation for left items: 因此,我们可以调整左侧项目的翻译:

.attr("dx", function(d) {
  var rotation = computeTextRotation(d);
  return (rotation > 90 && rotation < 270) ? -6 : 6;
})

You can replicate this method to adapt the click function as well. 您也可以复制此方法以适应click功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM