d3-interpolate icon indicating copy to clipboard operation
d3-interpolate copied to clipboard

Interpolate transform function lists, not just matrices.

Open ccprog opened this issue 6 years ago • 2 comments

Consider this animation which interpolates using interpolateTransformSvg:

var p1 = d3.select('svg')
  .append('polygon')
  .attr('points', '100 90 100 110 10 100')
  .attr('transform', 'rotate(20, 100, 100)');

p1.transition()
  .duration(2000)
  .attr('transform', 'rotate(160, 100, 100)')
  .on('start end', function () {
    console.log(p1.node().transform.baseVal.consolidate().matrix);
  });

Codepen

It should rotate the polygon about a constant center. Instead, the rotation center moves during the transition. If you look at the logged consolidated transform matrices, this is not that suprising:

{ a: 0.9396926164627075, b: 0.3420201539993286, c: -0.3420201539993286, d: 0.9396926164627075, e: 40.23275375366211, f: -28.171276092529297 }
{ a: -0.9396926164627075, b: 0.3420201539993286, c: -0.3420201539993286, d: -0.9396926164627075, e: 228.17127990722656, f: 159.76724243164062 }

The method of blindly taking the matrix supplied by SVGTransformList.consolidate() as a basis for interpolation is clearly not appropriate in this case.

Rotating without supplying a rotation center works is as expected.

ccprog avatar Sep 12 '17 05:09 ccprog

I’ve reproduced this here:

https://bl.ocks.org/mbostock/98edae5ce16c3400b5bcd180653a3717

The way transform interpolation currently works is that it decomposes the start and end transform into a standard matrix representation, and then uses the CSS Transforms Module Level 1 specification for interpolating 2D matrices.

However, what we should be doing is following the specification for interpolating transforms, not matrices; the latter only applies in the general case when the start and end transform have different structure. This will require looking at the transform as a series of transform functions, rather than immediately decomposing it.

mbostock avatar Sep 12 '17 17:09 mbostock

Great care has to be taken when implementing this feature, as the transformation lists might look different at start and end, but they can still be interpolated by the default value that is implied.

For example, interpolating between rotateZ(90deg) and scale(0.5, 0.5) would then be the same as interpolating between rotateZ(90deg) scale(1, 1) and rotateZ(0deg) scale(0.5, 0.5).

The user could also specify a transformation matrix on either of side of the transition, in which case it probably makes sense to reinterpret everything as matrices.

Karolusrex avatar Aug 24 '18 20:08 Karolusrex