Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 550
Sebastian Kazenbroot-Guppy Avatar asked Aug 31 '16 05:08

Sebastian Kazenbroot-Guppy


People also ask

Can I rotate SVG?

Rotate. The rotate(<a> [<x> <y>]) transform function specifies a rotation by a degrees about a given point. If optional parameters x and y are not supplied, the rotation is about the origin of the current user coordinate system. If optional parameters x and y are supplied, the rotation is about the point (x, y) .

How do you rotate a path?

Path points can be rotated numerically using the Tool Options bar settings. Set a rotation angle in the field and click Rotate to apply the rotation.

How does translate work in D3?

Translate is an important functionality in D3. js and is used to move the SVG elements inside the webpage. It takes two values, namely x and y. The x value translates the SVG element along the x-axis, while y translates the SVG element along the y-axis.

What does transform do in D3?

translate() Function. The transform. translate() function in D3. js library is used to get the transformation whose translation tx1 and ty1 is equal to tx0 + tk x and ty0 + tk y, where tx0 and ty0 is the transform's translation and tk is the transform's scale.


1 Answers

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".

like image 175
Jason Avatar answered Oct 23 '22 03:10

Jason