Sebastian Kazenbroot-Guppy Sebastian Kazenbroot-Guppy - 3 months ago 37
CSS Question

d3.js: How to rotate an SVG around its center while translating?

The Problem:



I have been trying, to no avail, to find a general solution for simultaneously rotating and translating an SVG with d3.js v4.2.2.

I can get the SVG starting and ending in the correct positions, but the easing in-between is all wrong. Below is a JSFiddle where I have done a rotate+translate on many instances of the same SVG pulled from the DOM, each to a different amount rotation according to the datapoint.

A key thing to note is that I need this solution to work when translating from (100,100) to (500,500) just as well as when I start from (0,0).

https://jsfiddle.net/3jbv23em/

var serializer = new XMLSerializer();

var svgNode = serializer.serializeToString(document.querySelector('#svgs svg defs svg'));

var dataset = [1,8,15,22,29,36,43,50,57,64,71,78,85,92,99,106,113,120,127,134,141,148,155,162,169,176,183,190,197,204,211,218,225,232,239,246,253,260,267,274,281,288,295,302,309,316,323,330,337,344,351,358]

var wrapper = d3
.select('#game svg')
.attr('width', window.innerWidth)
.attr('height', window.innerHeight)
.selectAll('g')
.data(dataset)
.enter()
.append('g')
.html(function(d) { return svgNode; })
.transition()
.duration(1500)
.attr('transform', function(d) {
return 'translate(500,300)' +
'rotate(' + d * 1.8 + ', 63, 54.77)';
});


(Unfortunately, I wasn't able to get D3 v4 working in JSFiddle, so JSFiddle is using v3 here. However, the problem is the same).

My expected behaviour: All of the chickens rotate around the same center, never extending past the dimensions of the circle seen at the end of the animation.

The actual result: All chickens rotate around the translated original position of the top left corner before returning to the correct position at the end.

Solutions That Didn't Work for Me:



How to rotate an object around the center in d3.js


  • This is about rotating around a fixed point further away, not around a point on the object one is trying to rotate



SVG rotation anchorpoint


  • This might work, but completely takes me out of the D3 ecosystem



How do I rotate or scale (transform) an SVG path relative to its center point?


  • I need the solution to start from an arbitrary point, not always the origin @ (0,0)



In Conclusion:



I'm pretty bewildered at the moment, and any help is greatly appreciated. Thanks for your time.

Answer

Because D3 transitions applies both the translate and the rotate together you get some awkward looking animations even though the end result is what you are looking for.

D3 provides a d3.interpolateString which handles executing the animation the way you would like. d3.interpolateString requires a starting and ending transform. d3.interpolateString is used within attrTween.

Replace

.attr('transform', function(d) { 
    return 'translate(500,300)' +
           'rotate(' + d * 1.8 + ', 63, 54.77)';
});

With

.attrTween('transform', function(d, i, a) { 
    return d3.interpolateString('translate(0,0) rotate(0)',
                                'translate(500,300)' +
                                'rotate(' + d * 1.8 + ', 63, 54.77)');
});

Here is an updated jsfiddle with a tweak to the translation for better viewability for smaller screens.

https://jsfiddle.net/3jbv23em/16/

A helpful link with the same issue is "D3.js animate rotation".

Comments