d3:curve

by Richard Hunter

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
<div id="chart"></div>

JavaScript

var width = 500,
  height = 500,
  start = 0,
  end = 2.25,
  numSpirals = 4;

var theta = function(r) {
  return numSpirals * Math.PI * r;
};

var r = d3.min([width, height]) / 2 - 40;

var radius = d3.scaleLinear()
  .domain([start, end])
  .range([40, r]);

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

// create the spiral, borrowed from http://bl.ocks.org/syntagmatic/3543186
var points = d3.range(start, end + 0.001, (end - start) / 1000);

var spiral = d3.radialLine()
  .curve(d3.curveCardinal)
  .angle(theta)
  .radius(radius);

var path = svg.append("path")
  .datum(points)
  .attr("id", "spiral")
  .attr("d", spiral)
  .style("fill", "none")
  .style("stroke", "steelblue");

// fudge some data, 2 years of data starting today
var spiralLength = path.node().getTotalLength(),
  N = 730,
  barWidth = (spiralLength / N) - 1;
  
var someData = [];

for (var i = 0; i < N; i++) {
  var currentDate = new Date();
  
  currentDate.setDate(currentDate.getDate() + i);
  
  someData.push({
    date: currentDate,
    value: Math.random()
  });
}

// here's our time scale that'll run along the spiral
var timeScale = d3.scaleTime()
  .domain(d3.extent(someData, function(d) {
    return d.date;
  }))
  .range([0, spiralLength]);

// yScale for the bar height
var yScale = d3.scaleLinear()
  .domain([0, d3.max(someData, function(d) {
    return d.value;
  })])
  .range([0, (r / numSpirals) - 30]);

// append our rects
svg.selectAll("rect")
  .data(someData)
  .enter()
  .append("rect")
  .attr("x", function(d, i) {

    // placement calculations
    var linePer = timeScale(d.date),
      posOnLine = path.node().getPointAtLength(linePer),
      angleOnLine = path.node().getPointAtLength(linePer - barWidth);

    d.linePer = linePer; // % distance are on the spiral
    d.x = posOnLine.x; // x postion on the spiral
    d.y = posOnLine.y; // y...