<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Circle wave</title>
    <script src="https://d3js.org/d3.v4.js"></script>
    <script src="https://unpkg.com/d3-canvas-transition@0.3.7/build/d3-canvas-transition.js"></script>
    <style>
      #panel {
          background-color: rgba(245,245,245,0.9);
          padding: 5px;
          position: absolute;
          display: block;
      }
    </style>
</head>
<body>
  <div id="panel">
      <div id="paper">
      <label>
        <input id='svg' name="type" type="radio" checked>
        <span>svg</span>
      </label>
      <label>
        <input id='canvas' name="type" type="radio">
        <span>canvas</span>
      </label>
      </div>
      <div id="fps">FPS: <span>?</span></div>
  </div>
  <div id="example" style="max-width: 960px"></div>
<script>
(function () {
    d3.select('#svg').on('click', function () {
        draw('svg');
    });
    d3.select('#canvas').on('click', function () {
        draw('canvas');
    });
    if (d3.resolution() > 1) {
        d3.select('#paper').append('label').html(
            "<input id='canvas-low' name='type' type='radio'><span>canvas low resolution</span>"
        );
        d3.select('#canvas-low').on('click', function () {
            draw('canvas', 1);
        });
    }

    var angles = d3.range(0, 2 * Math.PI, Math.PI / 200),
        fps = d3.select("#fps span"),
        time0 = d3.now(), frames = 0, time1;

    draw('svg');

    d3.timer(function () {
        path.attr("d", function (d) {
            return d(angles);
        });
        frames++;
        time1 = d3.now();
        if (time1 - time0 > 1000) {
            fps.text(Math.round(1000*frames/(time1 - time0)));
            time0 = time1;
            frames = 0;
        }
    });

    function draw(type, r) {

        var example = d3.select("#example"),
                width = d3.getSize(example.style('width')),
                height = Math.min(500, width);

        example.select('.paper').remove();
        var paper = example
                .append(type)
                .classed('paper', true)
                .attr('width', width).attr('height', height).canvasResolution(r).canvas(true);

        path = paper.append("g")
                .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
                .attr("fill", "none")
                .attr("stroke-width", 10)
                .attr("stroke-linejoin", "round")
                .selectAll("path")
                .data(["#f03b20", "#2c7fb8", "#31a354"])
                .enter().append("path")
                .attr("stroke", function (d) {
                    return d;
                })
                .style("mix-blend-mode", "darken")
                .datum(function (d, i) {
                    return d3.radialLine()
                            .curve(d3.curveLinearClosed)
                            .angle(function (a) {
                                return a;
                            })
                            .radius(function (a) {
                                var t = d3.now() / 1000;
                                return 200 + Math.cos(a * 8 - i * 2 * Math.PI / 3 + t) * Math.pow((1 + Math.cos(a - t)) / 2, 3) * 32;
                            });
                });

    }
}());
</script>
</body>