block by bycoffe c3849a0b15234d7e32fc

Element rotation with point-along-path interpolation

Full Screen

This example uses point-along-path interpolation, but also changes the rotation of the moving element depending on its place on the path.

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  #chart path.line {
    fill: none;
    stroke-width: 1;
    stroke: #666;
    stroke-dasharray: 3,3;
  }
  line {
    stroke: #000;
    stroke-width: 1;
  }
  text {
    font-family: Helvetica, sans-serif;
    font-size: 11px;
    text-anchor: middle;
  }
</style>

<body>

  <div id="chart"></div>

</body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>

  var margin = {top: 20, right: 20, bottom: 20, left: 20},
      width = 800 - margin.left - margin.right,
      height = 400 - margin.top - margin.bottom,

      x = d3.scale.linear()
              .domain([0, 20])
              .range([10, width]),

      y = d3.scale.linear()
              .domain([0, 1])
              .range([height, 0]),

      data = d3.range(x.domain()[1]).map(function(x) {
        return Math.random();
      }),

      line = d3.svg.line()
                  .interpolate("basis")
                  .x(function(d, i) {
                    return x(i);
                  })
                  .y(y),

      svg = d3.select("#chart").append("svg").attr({
        width: width + margin.left + margin.right,
        height: height + margin.top + margin.bottom
      }),

      g = svg.append("g").attr({
        transform: "translate(" + margin.left + "," + margin.top + ")"
      }),

      path = g.append("path")
                .datum(data)
              .attr({
                "class": "line",
                d: line
              })

      pointer = g.append("g"),

      label = pointer.append("text")
                .attr({
                  transform: "translate(0, -10)"
                })
                .text("Hi!"),

      tri = pointer.append("path")
              .attr({
                "class": "tri",
                d: d3.svg.symbol().type("triangle-down").size(50)()
              });

var direction = -1,
    atLength;

// From //bl.ocks.org/mbostock/1705868
function transition() {
  direction *= -1;
  pointer.transition()
    .ease("linear")
    .duration(10000)
    .attrTween("transform", translateAlong(path.node()))
    .each("end", transition);
}

transition();

function translateAlong(path) {
  var l = path.getTotalLength();
  return function(d, i, a) {
    return function(t) {
      atLength = direction === 1 ? (t * l) : (l - (t * l));
      var p1 = path.getPointAtLength(atLength),
          p2 = path.getPointAtLength((atLength)+direction),
          angle = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
      label.text(Math.round(angle) + "°");
      return "translate(" + p1.x + "," + p1.y + ")rotate(" + angle + ")";
    }
  }
}

</script>