D3.js animate rotation

2019-01-16 21:39发布

问题:

I'm having trouble when I try to correctly execute a rotation animation using the D3.js library. The problem has to do with the point at which I want to rotate the element about.

Here is a fiddle I made to show what I mean (in slow motion): http://jsfiddle.net/74mCb/

It seems like the source of the problem lies here:

.attr("transform", "rotate(-60, 150,130)");

And then I rotate it like so:

.attr("transform", "rotate(40 150,130)");

I would like the butt of the needle to stay in position (to be the center of rotation), could someone please explain what I am doing wrong?

Thanks!

回答1:

This is a bit tricky to grasp (I don't fully understand it myself) but D3 needs some help knowing how to interpolate between the two strings that represent your rotation.

function turnNeedle()
{

    needle
      .transition()
      .duration(2000)
      .attrTween("transform", tween);

    function tween(d, i, a) {
      return d3.interpolateString("rotate(-60, 150, 130)", "rotate(60, 150, 130)");
    }

}

d is the datum, i is the index, a is the attribute in case you want to make this data-driven.

http://jsfiddle.net/SHF2M/



回答2:

Here's what I think is going on: per the SVG spec, the transform

rotate(40 150,130)

is equivalent to:

translate(150,130) rotate(40) translate(-150, -130)

It looks like D3 is animating the translation as well as the rotation - the internal d3.transform representation of rotate(40 150,130) is a rotate component + a translation component, so both are being included in the transition.

The easiest fix here is to draw your needle at the origin, translate it with an outer g element to the correct position, then rotate it:

var needle = svg
  .append("g")
    .attr("class", "needle")
    .attr("transform", "translate(150 , 130)")
  .append("path")
    .attr("class", "tri")
    // your path may have been prettier
    .attr("d", "M-3 0 L0 -130 L3 0 S3 5 0 5 S-3 5 -3 0 Z")
    .attr("transform", "rotate(-60)");

then

needle
    .transition()
    .duration(2000)
    .attr("transform", "rotate(40)");

See working fiddle: http://jsfiddle.net/nrabinowitz/74mCb/1/