如何在D3中检测标签冲突并重新组织标签

时间:2019-02-26 09:05:31

标签: javascript html css d3.js svg

尝试构建一个带有标签的饼形图,如此所附图像。问题是我们如何检测标签文本冲突并重新组织标签,使它们不会相互重叠?

enter image description here

这是代码

    <!DOCTYPE html>
<meta charset="utf-8">
<style>
  body {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    width: 960px;
    height: 500px;
    position: relative;
  }

  svg {
    width: 100%;
    height: 100%;
  }

  path.slice {
    stroke-width: 2px;
  }

  polyline {
    opacity: .3;
    stroke: black;
    stroke-width: 2px;
    fill: none;
  }

</style>

<body>
  <button class="randomize">randomize</button>
  <script>
    var svg = d3.select("body")
      .append("svg")
      .append("g")

    svg.append("g")
      .attr("class", "slices");
    svg.append("g")
      .attr("class", "labels");
    svg.append("g")
      .attr("class", "lines");

    var width = 960,
      height = 450,
      radius = Math.min(width, height) / 2;

    var pie = d3.layout.pie()
      .sort(null)
      .value(function(d) {
        return d.value;
      });

    var arc = d3.svg.arc()
      .outerRadius(radius * 0.8)
      .innerRadius(radius * 0.4);

    var outerArc = d3.svg.arc()
      .innerRadius(radius * 0.9)
      .outerRadius(radius * 0.9);

    svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

    var key = function(d) {
      return d.data.label;
    };

    var color = d3.scale.ordinal()
      .domain(["vvbgsd","hyjikbb", "koehyvnk", "lkoijwnvj","bgerhyjtyu", "vgbergv", "vfgbsdfsd", "asdasddc", "adip", "dolor", "sit", "dolor sit", "dolor sit", "amet", "consectetur", "adipisicing", "elit", "sed", "do", "eiusmod", "tempor", "incididunt"])
      .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

    function randomData() {
      var labels = color.domain();
      return labels.map(function(label) {
        return {
          label: label,
          value: Math.random()
        }
      });
    }

    change(randomData());

    d3.select(".randomize")
      .on("click", function() {
        change(randomData());
      });


    function change(data) {

      /* ------- PIE SLICES -------*/
      var slice = svg.select(".slices").selectAll("path.slice")
        .data(pie(data), key);

      slice.enter()
        .insert("path")
        .style("fill", function(d) {
          return color(d.data.label);
        })
        .attr("class", "slice");

      slice
        .transition().duration(1000)
        .attrTween("d", function(d) {
          this._current = this._current || d;
          var interpolate = d3.interpolate(this._current, d);
          this._current = interpolate(0);
          return function(t) {
            return arc(interpolate(t));
          };
        })

      slice.exit()
        .remove();

      /* ------- TEXT LABELS -------*/

      var text = svg.select(".labels").selectAll("text")
        .data(pie(data), key);

      text.enter()
        .append("text")
        .attr("dy", ".35em")
        .text(function(d) {
          return d.data.label;
        });

      function midAngle(d) {
        return d.startAngle + (d.endAngle - d.startAngle) / 2;
      }

      text.transition().duration(1000)
        .attrTween("transform", function(d) {
            console.log('d' + JSON.stringify(d));
          this._current = this._current || d;
          var interpolate = d3.interpolate(this._current, d);
          this._current = interpolate(0);
          return function(t) {
            var d2 = interpolate(t);
            var pos = outerArc.centroid(d2);
            pos[0] = radius * (midAngle(d2) < Math.PI ? 1 : -1);
            return "translate(" + pos + ")";
          };
        })
      .styleTween("text-anchor", function(d) {
          this._current = this._current || d;
          var interpolate = d3.interpolate(this._current, d);
          this._current = interpolate(0);
          return function(t) {
            var d2 = interpolate(t);
            return midAngle(d2) < Math.PI ? "start" : "end";
          };
        });

      text.exit()
        .remove();

      /* ------- SLICE TO TEXT POLYLINES -------*/

      var polyline = svg.select(".lines").selectAll("polyline")
        .data(pie(data), key);

      polyline.enter()
        .append("polyline");

      polyline.transition().duration(1000)
        .attrTween("points", function(d){
          this._current = this._current || d;
          var interpolate = d3.interpolate(this._current, d);
          this._current = interpolate(0);
          return function(t) {
            var d2 = interpolate(t);
            var pos = outerArc.centroid(d2);
            pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1);
            return [arc.centroid(d2), outerArc.centroid(d2), pos];
          };            
        });

      polyline.exit()
        .remove();
    };

  </script>
</body>

这是JSFiddle上的代码。

也许在绘制标签之后,然后有逻辑可以检测标签是否相互重叠,这是可能的,但是我仍然不太清楚如何放置标签框,从而不会重叠...

0 个答案:

没有答案