2

I am trying to use d3.js to animate a gauge needle, but end up with a weird animation. I have done some search from Internet, but I couldn't figure out what solution can I use to fix the problem.

Codepen

  function createNeedle(sampleAngle){
    topX = centerX - Math.cos(sampleAngle) * triLength
    topY = centerY - Math.sin(sampleAngle) * triLength

    leftX = centerX - 10 * Math.cos(sampleAngle - Math.PI / 2)
    leftY = centerY - 10 * Math.sin(sampleAngle - Math.PI / 2)

    rightX = centerX - 10 * Math.cos(sampleAngle + Math.PI / 2)
    rightY = centerY - 10 * Math.sin(sampleAngle + Math.PI / 2)


    return " M " + leftX + " " + leftY + " L " + topX + " " + topY + " L " + rightX + " " + rightY;

  }

  //animate the needle
  d3.select('.moveNeedle')
  .attr('d', createNeedle(sampleAngle1))
  .transition()
  .duration(2000)
  .attr('d', createNeedle(sampleAngle2));
Kevin
  • 272
  • 5
  • 21
  • You will to create a customTween to calculate the X and Y coordinates during the transition, for example see this SO question (https://stackoverflow.com/questions/30849961/d3-js-tween-arc-position-inner-radius-and-outer-radius-d3-js-arc) and related block (http://bl.ocks.org/mbostock/5100636) – Tom Shanley Sep 12 '17 at 01:55
  • Thank you, I figure out how to fix it according to http://bl.ocks.org/mbostock/5100636 – Kevin Sep 12 '17 at 03:04
  • Almost duplicate: [*"D3 SVG transform rotation transition behaving weirdly"*](/q/40244530). – altocumulus Sep 12 '17 at 07:46

1 Answers1

1

You can make your life so much easier if you apply a transform="rotate()" instead of redrawing the path.

Nonetheless, you need to supply a custom Tween function, as the standard d3.interpolateTransformSvg acts in unexpected ways.

var topX = centerX - triLength,
    topY = centerY,

    leftX = centerX,
    leftY = centerY + 10,

    rightX = centerX,
    rightY = centerY - 10;

function rotateNeedle(sampleAngle){
    return "rotate(" + sampleAngle + "," + centerX + "," + centerY  + ")";
}

d3.select('.moveNeedle')
    // only draw once
    .attr('d', "M" + leftX + " " + leftY + " " + topX + " " + topY + " " + rightX + " " + rightY)
    // supply angles in degrees!
    .attr('transform', rotateNeedle(sampleAngle1))
    .transition()
    .duration(2000)
    .attrTween('transform', function ()  {
        var i = d3.interpolate(sampleAngle1, sampleAngle2)
        return function (t) { 
            return rotateNeedle(i(t));
        };
    });
ccprog
  • 20,308
  • 4
  • 27
  • 44
  • If you're interested, I have just raised a [bug report](https://github.com/d3/d3-interpolate/issues/44) about the strange behavior of interpolateTransformSvg – ccprog Sep 12 '17 at 05:41
  • That's not really a bug but rather a feature request. D3 has no means for interpolating a rotation around any center other than the origin. See my [answer](https://stackoverflow.com/a/40245163/4235784) to [*"D3 SVG transform rotation transition behaving weirdly"*](/q/40244530). – altocumulus Sep 12 '17 at 07:45
  • In addition to my last comment I don't think there is an easy "fix" for that. For the transition of transforms the values are first consolidated into a single transform matrix which is then [decomponsed](https://www.w3.org/TR/css-transforms-1/#decomposing-a-2d-matrix) into the corresponding transform functions. The *explicit* information about the center of rotation is lost along these steps as it is *implicitly* available in the decomposed values. – altocumulus Sep 12 '17 at 08:37
  • 1. d3 does support transform interpolation in all cases. 2. The behavior goes contrary to both [CSS Transforms](https://www.w3.org/TR/css-transforms-1/#interpolation-of-transforms) interpolation rules and [SVG animateTransform](https://www.w3.org/TR/SVG11/animate.html#AnimateTransformElement) and [distance for paced animations](https://www.w3.org/TR/SVG11/animate.html#complexDistances) definitions. – ccprog Sep 12 '17 at 16:02