d3 饼图排序过渡

d3 pie sort transition

如何在排序饼图时应用动画过渡?我不是说更新值,我的意思是将饼图的每个弧排序为 move into place the way bars do here.

现有数据集(或切换数据集)有很多转换 examples for updating using new values。我找不到任何关于如何重新排序的信息(使用相同的值,相同的数据集)。

我现在正在使用它,它只是通过应用初始化渲染时使用的相同补间来重绘弧线,但它从零开始每个弧线。

        .attr('d', arc)
        .transition()
        .duration(1000)
        .attrTween("d", tweenPie);

    function tweenPie(b) {
        var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
        return function(t) { return arc(i(t)); };
    };

我是否需要以某种方式存储现有的开始和结束角度以及 运行 来自那些的补间?

我看到了 something kind of like that here,虽然这个例子是更新值,而不是排序。

谢谢。

以 Bostock 示例为基础 here

  setInterval(change, 2000);

  var sort = false;
  function change() {

    sort = !sort;

    if (sort){
      pie = d3.layout.pie() //<-- pie with default sort
        .value(function(d) {
          return d.value;
        });
    } else {
      pie = d3.layout.pie() //<-- pie with no sort
        .value(function(d) {
          return d.value;
        })
        .sort(null);
    }

    path = path.data(pie); // compute the new angles
    path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
  }

完整代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  body {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    margin: auto;
    position: relative;
    width: 400px;
  }
  
  text {
    font: 10px sans-serif;
  }
  
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<body>
<script>
  var width = 400,
    height = 500,
    radius = Math.min(width, height) / 2;
    
  var color = d3.scale.category20();
  
  var pie = d3.layout.pie()
    .value(function(d) {
      return d.value;
    })
    .sort(null);
    
  var defaultSort = pie.sort;
    
  var arc = d3.svg.arc()
    .innerRadius(radius - 100)
    .outerRadius(radius - 20);
    
  var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

  var data = [{
      value: 1
    }, {
      value: 5
    }, {
      value: 2
    }, {
      value: 6
    }
  ];

  var path = svg.datum(data).selectAll("path")
    .data(pie)
    .enter().append("path")
    .attr("fill", function(d, i) {
      return color(i);
    })
    .attr("d", arc)
    .each(function(d) {
      this._current = d;
    }); // store the initial angles
    
  setInterval(change, 2000);

  var sort = false;
  function change() {

    sort = !sort;

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

    path = path.data(pie); // compute the new angles
    path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
  }

  // Store the displayed angles in _current.
  // Then, interpolate from _current to the new angles.
  // During the transition, _current is updated in-place by d3.interpolate.
  function arcTween(a) {
    var i = d3.interpolate(this._current, a);
    this._current = i(0);
    return function(t) {
      return arc(i(t));
    };
  }
</script>
</body>