Home > Back-end >  Animate rotation of a polygon around a vertex
Animate rotation of a polygon around a vertex

Time:01-02

I'm trying to rotate a triangle around one of it's vertices in d3.js, and although it ends up in the correct place it takes a meandering path to get there.

I've tried rotating the group (in each case click the triangle to start rotation): Rotate group

function rotateUp() {
    d3.selectAll("g")
    .transition()
    .duration(2000)
    .attr("transform","rotate(-90,50,50)");
}

Rotating the polygon within the group: Rotate triangle

function rotateUp() {
    d3.selectAll("polygon")
    .transition()
    .duration(2000)
    .attr("transform","rotate(-90,0,50)");
}

And using a bare polygon with no group, and absolution coordinates without translate(): Rotate triangle, no group

function rotateUp() {
    d3.selectAll("polygon")
    .transition()
    .duration(2000)
    .attr("transform","rotate(-90,50,50)");
}

In each case I can get it to the right destination, but always with the circuitous route.

I tried positioning the triangle at 0,0 and rotating around that point, and it works. So the problems, it seems, have something to do with rotating around something other than the origin?

CodePudding user response:

D3 interpolators are great, but sometimes those strange behaviours happen (you can read more about it in this Github issue). The solution here is using attrTween with a interpolator only for the angle:

function myTween(angle, x, y) {
  const i = d3.interpolate(0, angle);
  return t => `rotate(${i(t)},${x},${y})`;
};

Here's a demo based on your 2nd code, rotating the triangle around its bottom-left point:

function loaded() {
  let g = d3.select("#graph")
    .append("g")
    .attr("transform", "translate(50,50)");

  g
    .append("polygon")
    .attr("id", "triangle")
    .attr("points", "0,0 50,100 0,50")
    .style("fill", "red")
    .on("click", rotateUp)
}

function rotateUp() {
  d3.selectAll("polygon")
    .transition()
    .duration(2000)
    .attrTween("transform", () => myTween(-90, 0, 50));
}

function myTween(angle, x, y) {
  const i = d3.interpolate(0, angle);
  return t => `rotate(${i(t)},${x},${y})`;
};
<html lang="en">

<head>
  <meta charset="UTF-8" />

  <meta http-equiv="X-UA-Compatible" content="ie=edge" />

  <script src="https://d3js.org/d3.v5.min.js"></script>
</head>

<body onl oad="loaded()">
  <div id='layout'>
    <div id='container'>
      <svg id="graph" />
    </div>
  </div>
</body>

</html>

  • Related