text: var margin = {top: 40, right: 340, bottom: 40, left: 200},
  width = 960 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom;
  
  var color = d3.scale.category20c();
  
  var formatNumber = d3.format(".4f");
  
  var x = d3.scale.linear()
      .domain([0, 1])
      .range([0, width]);
  
  var y = d3.scale.linear()
      .domain([0, 1])
      .range([height, 0]);
  
  var continuousLine = (function() {
    var samples = d3.range(0, 1 + 1e-6, 2 / width);
  
    var discreteLine = d3.svg.line()
        .x(function(d, i) { return x(samples[i]); })
        .y(function(d) { return y(d); });
  
    return function(f) {
      return discreteLine(samples.map(f));
    };
  })();
  
  var ease;
  
  var svg = d3.select("#kdgform")
    .append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
    .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  
  svg.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.svg.axis()
        .scale(x)
        .orient("bottom"))
      .append("text")
        .attr("x", width)
        .attr("y", -3)
        .attr("dy", "-.35em")
        .style("font-weight", "bold")
        .style("text-anchor", "middle")
        .text("time");
  
  svg.append("g")
      .attr("class", "axis axis--y")
      .call(d3.svg.axis()
        .scale(y)
        .orient("left"))
      .append("text")
        .attr("x", 6)
        .attr("dy", ".35em")
        .style("font-weight", "bold")
        .text("ease(time)");
  
  var lineEase = svg.append("path")
      .attr("class", "line")
      .style("stroke", "white")
      .style("stroke-width", "1.5px");
  
  var timeReference = svg.append("line").attr("y1", height),
      easeReference = svg.append("line");
  
  var circle = svg.append("circle")
      .attr("r", 4.5)
      .attr("cx", 0)
      .attr("cy", height);
  
  var accelerationInput = d3.select("#acceleration input").on("input", reset),
      accelerationOutput = d3.select("#acceleration output"),
      reflectionInput = d3.select("#reflection input").on("input", reset),
      reflectionOutput = d3.select("#reflection output");
  
  var accelerationInputScale = d3.scale.pow()
      .exponent(4)
      .domain([0, 1])
      .range([1, 10]);
  
  reset();
  
  !function loop() {
    circle.transition()
      .ease("linear")
      .duration(5000)
      .tween("transform", function() {
        return function(t) {
          circle.attr("cx", x(t)).attr("cy", y(ease(t)));
          timeReference.attr("x1", x(t)).attr("x2", x(t)).attr("y2", y(ease(t)));
          easeReference.attr("x2", x(t)).attr("y1", y(ease(t))).attr("y2", y(ease(t)));
        };
      })
      .each("end", loop);
  }();
  
  function reset() {
    var acceleration = accelerationInputScale(accelerationInput.property("value")),
        reflection = reflectionInput.property("value");
    accelerationOutput.text(formatNumber(acceleration));
    reflectionOutput.text(formatNumber(reflection));
    ease = easeReflect(easeAccelerateThenCoast(acceleration), reflection);
    lineEase.attr("d", continuousLine(ease));
  }
  
  // Like in-out reflection, except around the specified center.
  // If center = .5, this is the same as in-out reflection.
  function easeReflect(ease, center) {
    return function(t) {
      return t < center ? center * ease(t / center) : 1 - ease((1 - t) / (1 - center)) * (1 - center);
    };
  }
  
  // Constant acceleration followed by constant speed.
  // If acceleration = 1, this is the same as quadratic easing.
  // If acceleration = Infinity, this is the same as linear easing.
  function easeAccelerateThenCoast(acceleration) {
    if (acceleration < 1) throw new Error("unpossible");
    if (!isFinite(acceleration)) return d3.ease("linear");
    var speed = 2 * (acceleration - Math.sqrt((acceleration - 1) * acceleration)),
        t0 = speed / 2 / acceleration;
    return function(t) {
      return t < t0 ? acceleration * t * t : speed * t - speed + 1;
    };
  }