I'm trying to play with d3 transitions - I need to do both translate and rotate. I have original coordinates:
let data = [
{x: 100, y: 100, rotation: 45},
];
and 2 rectangles. One is doing translate first, second one is doing rotation first.
This is resulting transform after drawing rectangles:
transform="rotate(45 115 105) translate(100, 100)"
transform="translate(100, 100) rotate(45 115 105)"
they have the same translate and rotate transformations, only thing which differs is order of them.
Then I change data:
data[0].x += 30;
data[0].y += 20;
data[0].rotation += 45;
and I would expect to get some transition ending up with this transformation:
transform="rotate(90 145 125) translate(130, 120)"
transform="translate(130, 120) rotate(90 145 125)"
but what I really get is this:
transform="translate(150, 110) rotate(90)"
transform="translate(400, 100) rotate(90)"
- notice it changes order of translate rotate for the first rectangle.
- it also removes the center of rotation from rotate transformation (does it somehow compute it during transition?)
- how does it get the resulting numbers?
How does the d3 transition work? I need to get some expectable result, since I'm trying to play with some more advanced transitions.
Here is simple example: https://jsfiddle.net/pp6npw4g/2 (click move to start transition)
This is the expected behaviour for D3's standard interpolation of the
transform
attribute's value. Thetransform
attribute is notoriously hard to transition because its value may contain a complex list of transform definitions, which may come in any order and may even appear multiple times within one list. For example:To be able to transition between these values, the
transition.attr()
function usesd3.interpolateTransformSvg(a, b)
when it comes to interpolatingtransform
attributes' values. This does the following:Within the internal function
parseSvg()
of module d3-interpolate the list of transform definitions is boiled down by calling.consolidate()
of interfaceSVGTransformList
.Using the private function
decompose()
this consolidated transform is then decomposed into its values for translate, rotate, skew and scale.I have described this process of decomposing the transform list in my answer to "Replacing d3.transform in D3 v4".
During the transition the interpolator returned by
d3.interpolateTransformSvg(a, b)
will then interpolate between the respective values ofa
andb
for (1)translate
, (2)rotate
, (3)skewX
and (4)scale
in exactly this order.This leaves you with consolidated values, which may, at first, seem to come unexpected. Furthermore, it explains, why the order of transformations was changed by the transition. To work around this and implement a custom transition, you will have to provide a custom tween function which may be assigned by calling
transition.attrTween()
. The implementation of this function largely depends on your needs, though, and is beyond the scope of this answer.