Drawing an Arc with D3

by JP Obley

HTML

<script src="//d3js.org/d3.v4.min.js"></script>
<div id="canvas">
  <svg width="100%" height="100%"></svg>
</div>

CSS

body {
  background-color:#bbbbbb;
}
#canvas {
  width: 960px;
  height: 500px;
  margin: auto;
}

JavaScript

var minDeg = -90;
var maxDeg = 90;
var minValue = 0;
var maxValue = 100;
var currentValue = 40;
var n = 500;
var tailLength = 30;

var div = d3.select("#canvas");
var divBox = div.node().getBoundingClientRect();
var svg = d3.select("svg");
var width = divBox.width;
var height = divBox.height;
var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

function randomValue() {
  return Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
}

function deg2rad(deg) {
  return deg * Math.PI / 180;
}

function val2rad(val) {
  return deg2rad(val2deg(val));
}

function rad2deg(rad) {
  return rad * 180 / Math.PI;
}

var val2deg = d3.scaleLinear()
  .range([minDeg, maxDeg])
  .domain([minValue, maxValue])
  .clamp(true);

var color = d3.scaleLinear()
  .domain([0, n])
  .range(['#bbbbbb', 'tomato'])
  .clamp(true);

var fullArc = d3.arc()
  .innerRadius(210)
  .outerRadius(220)
  .startAngle(val2rad(minValue))
  .endAngle(val2rad(maxValue));

g.append("path")
  .style("fill", "dodgerblue")
  .attr("d", fullArc);

var tailArcs = d3.range(n).map(i => ({
  i,
  color: color(i),
  startAngle: deg2rad(minDeg),
  endAngle: deg2rad(minDeg)
}));

var tailArc = d3.arc()
  .innerRadius(169)
  .outerRadius(210)
  .startAngle(d => d.startAngle)
  .endAngle(d => d.endAngle);

var tails = g.selectAll("path.tail")
  .data(tailArcs)
    .enter()
      .append('path')
      .attr("class", "tail")
      .attr("d", tailArc)
      .style("fill", d => d.color)
      .style("stroke", d => d.i === n - 1 ? 'none' : d.color);

function update(value) {
  var maxDeg = val2deg(value);
  var minDeg = val2deg(value - tailLength);
  var step = (maxDeg - minDeg) / n;

  tails.data(tailArcs)
  .transition().duration(500)
    .attrTween('d', tweenArc(d => {
      var startAngle = minDeg + (d.i * step);
      return {
        startAngle: deg2rad(startAngle),
        endAngle: deg2rad(startAngle + step)
      }
    }));
}

function tweenArc(getNextAngles) {
 ...