Simple animated donut chart using D3

by Rishabh Sharma

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<div id="donut" data-donut="19"></div>

CSS

body {
  font-family: sans-serif;
  margin: 0 auto;
  width: 960px;
  padding-top: 10%;
  background-color: #fff;
}

text {
  font-family: sans-serif;
  font-size: 4rem;
  letter-spacing: -.2rem;
  font-weight: 600;
  line-height: 12rem;
  fill: #0096D6;
}

#donut {
  width: 28rem;
  height: 28rem;
  margin: 0 auto;
}

path.color0 {
  fill: #0096D6;
}

path.color1 {
  fill: transparent;
}

JavaScript

var duration   = 1200,
    transition = 200;

drawDonutChart(
  '#donut',
  $('#donut').data('donut'),
  280,
  280,
  ".4em"
);

function drawDonutChart(element, percent, width, height, text_y) {
  width = typeof width !== 'undefined' ? width : 280;
  height = typeof height !== 'undefined' ? height : 280;
  text_y = typeof text_y !== 'undefined' ? text_y : "-.10em";

  var dataset = {
        lower: calcPercent(0),
        upper: calcPercent(percent)
      },
      radius = Math.min(width, height) / 2,
      pie = d3.layout.pie().sort(null),
      format = d3.format(".0%");

  var arc = d3.svg.arc()
        .innerRadius(radius - 40)
        .outerRadius(radius)
  pie.startAngle(180 * (Math.PI/180));
  pie.endAngle(540 * (Math.PI/180));

  var svg = d3.select(element).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", arc)
        .each(function(d) { this._current = d; });

  var text = svg.append("text")
        .attr("text-anchor", "middle")
        .attr("dy", text_y);

  if (typeof(percent) === "string") {
    text.text(percent);
  }
  else {
    var progress = 0;
    var timeout = setTimeout(function () {
      clearTimeout(timeout);
      path = path.data(pie(dataset.upper));
      path.transition().duration(duration).attrTween("d", function (a) {

        var i  = d3.interpolate(this._current, a);
        var i2 = d3.interpolate(progress, percent)
        this._current = i(0);
        return function(t) {
          text.text( format(i2(t) / 100) );
          return arc(i(t));
        };
      });
    }, 1000);
  }
};

function calcPercent(percent) {
  return [percent, 100-percent];
};