d3js将动画文本显示为饼图

时间:2017-04-07 15:56:20

标签: javascript d3.js charts

我有3个饼图加载动画。 每个图表中都有一个文本,百分比数字,一个图表加载后跟随动画并开始计数从0%到总计%

我能够在一个饼图中显示文本,但是当我从3个饼图中调整使用的代码时,我找不到显示3个文本的方法。 我循环使用3 div并且输出3%的数字,我可以在控制台中看到正确的百分比数字,但是在饼图中没有显示任何内容:/

我是d3的新手,所以它可能比我能看到的要容易得多。

app.numbers = {
    calcPerc : function(percent) {
      return [percent, 100-percent];
    },

    drawDonutChart : function(el, percent, width, height, text_y) {
      width = typeof width !== undefined ? width : 290; //width
      height = typeof height !== undefined ? height : 290; //height
      text_y = typeof text_y !== undefined ? text_y : "-.10em";

      var radius = Math.min(width, height) / 2;
      var pie = d3.pie().sort(null);

      var dataset = {
        lower: this.calcPerc(0),
        upper: this.calcPerc(percent)
      }
      //this.percents = percent;

      this.arc = d3.arc()
            .innerRadius(radius - 20)
            .outerRadius(radius);

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

      var path = svg.selectAll("path")
            .data(pie(dataset.lower))
            .enter().append("path")
            .attr("class", function(d, i) { return "color" + i })
            .attr("d", this.arc)
            .each(function(d) { this._currentArc = d; }); // store the initial values

      // add text in the center of the donut
      this.text = svg.append('text')
                .attr("text-anchor", "middle")
                .attr("dy", text_y)
                .attr("d", percent)

      if (typeof(percent) === "string") {
        this.text.text(percent);
      } else {

        var self = this;
        var timeout = setTimeout( function () {
          clearTimeout(timeout);

          path = path.data(pie(dataset.upper)); // update the data
          path.transition().ease(d3.easeExp).duration('500').attrTween("d", function(a){
            var progress = 0;
            var format = d3.format(".0%");
            // Store the displayed angles in _currentArc.
            // Then, interpolate from _currentArc to the new angles.
            // During the transition, _currentArc is updated in-place by d3.interpolate.
            var i  = d3.interpolate(this._currentArc, a);
            var i2 = d3.interpolate(progress, percent);
            this._currentArc = i(0);

            return function(t) {
              $(self.text).each(function(){
                $(this).text( format(i2(t) / 100) );
              });
              return self.arc(i(t));
            };

          }); // redraw the arcs

        }, 200);
      }
    },

    init : function(){

      $('.donut').each( function() {
        var percent = $(this).data('donut');

        app.numbers.drawDonutChart(
          this,
          percent,
          190,
          190,
          ".35em"
        );
      })
    }
  }
}

// initialize pie on scroll
window.onscroll = function() {
  app.numbers.init();
}

HTML:

<section class="row numbers section-bkg section-bkg--blue">
  <div class="container">
    <div class="col-xs-12 col-sm-4">
      <div class="donut" data-donut="42"></div>
    </div>
    <div class="col-xs-12 col-sm-4">
      <div class="donut" data-donut="12"></div>
    </div>
    <div class="col-xs-12 col-sm-4">
      <div class="donut" data-donut="86"></div>
    </div>
  </div>
</section>

知道我应该如何显示文字? 我很确定问题出在这里:

$(self.text).each(function(){
  $(this).text( format(i2(t) / 100) );
});

1 个答案:

答案 0 :(得分:0)

尽管混合jQuery和D3永远不是一个好主意(尽量避免它),但似乎这不是问题。问题似乎是您使用之前分配的self来更改工厂内的文本。

一个解决方案(没有太多改变你的代码,当然有更好的方法来重构它)是根据当前的<path>获取文本:

var self2 = this;//this is the transitioning path
return function(t) {
    d3.select(self2.parentNode).select("text").text(format(i2(t) / 100));
    return self.arc(i(t));
};

这是你的代码(没有jQuery):

&#13;
&#13;
var app = {};

var color = d3.scaleOrdinal(d3.schemeCategory10)

app.numbers = {
  calcPerc: function(percent) {
    return [percent, 100 - percent];
  },

  drawDonutChart: function(el, percent, width, height, text_y) {
    width = typeof width !== undefined ? width : 290; //width
    height = typeof height !== undefined ? height : 290; //height
    text_y = typeof text_y !== undefined ? text_y : "-.10em";

    var radius = Math.min(width, height) / 2;
    var pie = d3.pie().sort(null);

    var dataset = {
        lower: this.calcPerc(0),
        upper: this.calcPerc(percent)
      }
      //this.percents = percent;

    this.arc = d3.arc()
      .innerRadius(radius - 20)
      .outerRadius(radius);

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

    var path = svg.selectAll("path")
      .data(pie(dataset.lower))
      .enter().append("path")
      .attr("fill", function(d, i) {
        return color(i)
      })
      .attr("d", this.arc)
      .each(function(d) {
        this._currentArc = d;
      }); // store the initial values

    // add text in the center of the donut
    this.text = svg.append('text')
      .attr("text-anchor", "middle")
      .attr("dy", text_y)
      .attr("d", percent)

    this.text.text(percent);

    var self = this;

    path = path.data(pie(dataset.upper)); // update the data
    path.transition().ease(d3.easeExp).duration(1000).attrTween("d", function(a) {
      var progress = 0;
      var format = d3.format(".0%");
      // Store the displayed angles in _currentArc.
      // Then, interpolate from _currentArc to the new angles.
      // During the transition, _currentArc is updated in-place by d3.interpolate.
      var i = d3.interpolate(this._currentArc, a);
      var i2 = d3.interpolate(progress, percent);
      this._currentArc = i(0);

      var self2 = this;

      return function(t) {
        d3.select(self2.parentNode).select("text").text(format(i2(t) / 100));
        return self.arc(i(t));
      };

    }); // redraw the arcs
  },

  init: function() {

    d3.selectAll('.donut').each(function() {
      var percent = d3.select(this).node().dataset.donut;

      app.numbers.drawDonutChart(
        this,
        percent,
        190,
        190,
        ".35em"
      );
    })
  }
}

app.numbers.init();
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<section class="row numbers section-bkg section-bkg--blue">
  <div class="container">
    <div class="col-xs-12 col-sm-4">
      <div class="donut" data-donut="42"></div>
    </div>
    <div class="col-xs-12 col-sm-4">
      <div class="donut" data-donut="12"></div>
    </div>
    <div class="col-xs-12 col-sm-4">
      <div class="donut" data-donut="86"></div>
    </div>
  </div>
</section>
&#13;
&#13;
&#13;