block by fil b65e5d5daa4cbd6d11225de08021d161

Sinusoidal interpolation

Full Screen

Join points with a sinusoidal interpolator, for Chris Henrick.

Compare with:

Built with blockbuilder.org

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
  </style>
</head>

<body>
  <script>
    var svg = d3.select("body").append("svg")
      .attr("width", width = 960)
      .attr("height", height = 500)

    var steps = 400;

    var parset = d3.timeParse('%m/%d/%y %H:%M');
    var data = d3.csvParse(`Date_Time,Event,Speed
3/31/17 0:24,flood,1.59
3/31/17 3:42,slack,0
3/31/17 7:12,ebb,-1.86
3/31/17 10:30,slack,0
3/31/17 13:12,flood,1.43
3/31/17 17:00,slack,0
3/31/17 20:00,ebb,-1.45
3/31/17 22:42,slack,0
4/1/17 1:12,flood,1.48
4/1/17 4:24,slack,0
4/1/17 8:06,ebb,-1.74
4/1/17 11:30,slack,0
4/1/17 14:06,flood,1.23
4/1/17 18:06,slack,0
4/1/17 21:00,ebb,-1.25
4/1/17 23:36,slack,0`)
    .map(d => {
      d.time = +parset(d.Date_Time);
      d.speed = +d.Speed;
      return d;
    });
    
    var x = d3.scaleLinear()
    .domain(d3.extent(data.map(d => d.time)))
    .range([0,width]);

    var y = d3.scaleLinear()
    .domain(d3.extent(data.map(d => d.speed)))
    .range([height,0]);

    function inter(t){
      var prev = d3.bisectLeft(data.map(d => d.time), t)-1,
          r = 0;
      if (!data[prev]) return 0;
      var alpha = (t - data[prev].time) / (data[prev+1].time - data[prev].time);
      if (data[prev].Event == 'slack')
        alpha = Math.sin(Math.PI/2 * alpha);
      else
        alpha = 1-Math.cos(Math.PI/2 * alpha);
	    r = d3.interpolateNumber(data[prev].speed, data[prev+1].speed)(alpha);
      return r;
    }
    
    var line = d3.line().x(x).y(u => y(inter(u)));
    
    svg.append('path')
    .attr('fill', 'none')
    .attr('stroke', 'lightblue')
    .attr('d', line(d3.range(
      ...x.domain(),
      (x.domain()[1] - x.domain()[0]) / steps
    )))

    svg.selectAll('circle')
    .data(data)
    .enter()
    .append('circle')
    .attr('r', 4)
    .attr('cx', d => x(d.time))
    .attr('cy', d => y(d.speed))
    

  </script>
</body>