Re: [css3-transforms] Interpolation of relative transitions

On Wed, Apr 4, 2012 at 8:15 AM, louis-rémi Babé <lrbabe@gmail.com> wrote:
> Hi,
>
> It is really convenient for a web author to be able to trigger a transition
> of a style property relative to its current state. For example, to animate
> an (absolutely positioned) element with a 200px transition to the right, one
> can do:
>
> elem.style.transition = "all ease 1s";
> elem.style.left = parseFloat( window.getComputedStyle( elem ).left ) + 200 +
> "px";
>
> Now imagine I want to rotate an element by 300° clockwise, relative to its
> current transform:
>
> elem.style.transition = "all ease 1s";
> var cs = window.getComputedStyle( elem ).transform;
> elem.style.transform = ( cs != "none" ? cs : " " ) + " rotate(300deg)";
>
> According to the draft of the interpolation algorithm[1], if the current
> transform of the element is "none", it will be animated as expected.
> Otherwise the web author has no way to predict if the element will be
> animated clockwise or not, as illustrated in this jsfiddle :
> http://jsfiddle.net/rhukk/6/
> If the web author tries to rotate an element by 360° relative to its current
> transform, no animation could happen at all.

For the benefit of those reading along, this happens because the
"from" and "to" states are non-matching animation lists (the "to"
state has an extra rotate() transform at the end), so each state is
instead just mashed together into a single matrix3d() transform,
broken apart into a list of matrix3d()s that handle just the
translation/rotation/etc aspect, and then numerically interpolated.
This causes rotations, in particular, to no longer reliably
interpolate based on the relative angles; you can't easily predict
whether the matrix-based interpolation will produce a CW or CCW
rotation (which is obvious in an angle-based rotation), and you can't
rotate more than 360deg, because the "extra turns" get wiped out in
the transition to a matrix.


> There's however a simple way to make those transitions happen as expected :
> it is easy to detect that the 'from' transform is a single function of same
> type and same value as the first function of the 'to' transform. This
> function can be "removed" from both function lists while they're being
> interpolated, and applied on each step of the transition before the list of
> interpolated functions.
> For example, if the 'from' is 'matrix(1,0,0,1,0,0)' and the 'to' is
> 'matrix(1,0,0,1,0,0) rotate(360deg)' then the function lists would be
> interpolated as if 'from' was 'none' and 'to' was 'rotate(360deg)', but at
> each step of the transition, the transform of the element should be
> 'matrix(1,0,0,1,0,0) rotate(<interpolated value for this step>)'.
>
> Would it be possible to add such a condition to the current #animation
> section of the transform draft?

So your proposal is that, whenever the "from" and "to" lists don't
match, first remove the common prefix of transforms they share (if
any) before running through the list again (and if removing the common
prefix removes the entirety of one state, treat it as 'none')?

This seems reasonable to me.  It has a better chance of achieving the
intended effect in common cases such as the one you bring up, and will
fall into the "just mash it all together" failure-case somewhat less
often.  It also shouldn't be too expensive of an operation.

Even if we make this change in level 4 (since we're trying to get
level 3 wrapped up so we can drop prefixes), it should be okay, since
it should generally be a strict enhancement in behavior.

I wonder if we could take this a bit further - rather than just
removing identical prefixes (where both the functions and arguments
match), we could find the prefix that just has functions matching,
with potentially different arguments.  Then we can interpolate that
common prefix normally, and run the rest of the two states back
through the list again as you describe, either matching the remainder
up with identity transforms or mashing the remainder up into a matrix.

~TJ

Received on Wednesday, 4 April 2012 18:57:57 UTC