- From: Kevin Doughty <socallednonflipped@gmail.com>
- Date: Sat, 21 Nov 2015 16:58:08 -0500
- To: Brian Birtles <bbirtles@mozilla.com>
- Cc: public-fx@w3.org, www-style@w3.org
- Message-ID: <CAAbwtRxF1VVaw_t9VWyYsVG_mLKi9nhPUAGkbO4bt73JxbYkjg@mail.gmail.com>
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CALayer_class/index.html#//apple_ref/occ/instm/CALayer/addAnimation:forKey
:
On Thu, Nov 19, 2015 at 2:08 AM, Brian Birtles <bbirtles@mozilla.com> wrote:
> Hi,
>
> We have a difficulty in Web Animations with regards to object lifetimes
> for animations that fill forwards. The trouble is one can do the
> following:
>
> elem.addEventListener('click', evt => {
> evt.target.animate({ opacity: [ 0, 1 ] },
> { duration: 500, fill: 'forwards' });
> });
>
> What this does, is create a new animation that fills forwards, on every
> click.
>
> Now, if we call:
>
> elem.getAnimations();
>
> It should return *all* the animations we've generated.
>
> There are few reasons for that:
>
> a. You should be able to use getAnimations() to help answer the
> question, "Why does my element have this style value?"
>
> i.e. This method needs to return any animation that is affecting
> the element in question.
>
> b. Animations can add together so you need to keep track of all the
> past animations anyway so you get the right final result.
>
> e.g. you can do the following
>
> // Nudge right
> elem.addEventListener('click', evt => {
> evt.target.animate({ transform: 'translate(50px)',
> composite: 'add' },
> { duration: 500, fill: 'forwards' });
> });
>
> The total distance the element is translated is the sum of the fill
> values of all animations that have run up to that point.
>
> All that means you really need to keep track of all the forwards-filling
> animations. Forever.
>
> Why is this a new problem?
>
> For CSS transitions and CSS animations, once animations are no longer
> referenced by specified style they are cancelled and no longer affect
> the element.
>
> You just don't accidentally end up in a situation with millions of old
> animations lying around. To do that, you'd have to have a *lot* of
> elements or have an animation-name value that is very long. Either
> case tells you to expect things to go slowly and are somewhat bounded.
>
> With the animation API, however, as shown in the examples above, it's
> quite easy to get into a situation where the UA has to keep a lot of
> Animations around without the author realizing it.
>
> Solutions we've discussed until now:
>
> a. Automatically cancel any filling animation when other filling
> animations cover the same properties.
> => Doesn't work for addition.
>
> b. Make getAnimations() only return the *last* animation that is
> filling per-property.
> => For the addition case, you'd still need to keep around some
> sort of summary of the result of previous animations. Now,
> supposing you don't expose that summary, the view you see from
> the API is inconsistent.
>
> c. Expose the summary view of underlying filling animations as
> some sort of special animation or a special attribute.
> => This is awkward, but maybe worth revisiting?
> e.g. elem.getFillStyle().opacity?
>
> d. "That's the author's problem" or "Just let UAs just do whatever
> they feel like"
> => This is our current position and it's not great.
>
> I really think we need to fix this. I don't have any brilliant ideas.
> Revisiting (c) could work, or perhaps some sort of "animation collapsing"?
>
> The rough idea of "animation collapsing" is that when the UA has two or
> more filling animations on the same properties on the same element, it
> basically takes the fill values of the underlying animations and
> squashes them into the property values specified on the top-most
> filling animation. Then the underlying animation ends becoming empty
> and can be discarded.
>
> (I'd really like to make it so that the underlying animation actually
> gets cancelled and you get an event for it, but I think when it comes to
> group effects, you want to be able to collapse individual effects
> without having to have a complete match for all effects.)
>
> Adding a bit more details I think it could be something like:
>
> Assume:
> * all finished animations do NOT fill forwards have been discarded
> * Element.getAnimations() does not return Animations targetting
> Element if the set of keyframes is empty
>
> For any two effects, A and B, (with corresponding animations, 'Animation
> A', and 'Animation B') where:
>
> a. A and B have the same non-null target element
> b. Animation A and Animation B are both finished
> c. Animation A and Animation B each have a fill mode of either
> 'forwards' or 'both'
> d. Animation A and Animation B have the same animation type
> e. The common animation type of Animation A and Animation B allows
> collapsing (disallow for CSS animations/transitions)
> f. For each animation property that is common to both A and B, there
> is no animation effect referring to that animation property whose
> corresponding animation has a composite order between that of A
> and B.
>
> Perform the following steps:
>
> 1. Assume that A refers to the effect whose corresponding animation
> has a *lower* composite order of the two.
> 2. For each animation property, |property|, that is referenced by both
> A and B, update each specified value |property| on B as follows:
> i. Let |b| be the specified value of |property| on a keyframe in
> B.
> ii. Let |a| be the fill value of |property| on a keyframe in A.
> iii. If the composite mode associated with |b| is 'replace',
> let b' = |b| and composite' = 'replace'.
> Otherwise, if the composite mode associated with |b| is 'add',
> let b' = add(|a|, b) and composite' = the composite mode of
> |a|.
> Otherwise, (the composite mode associated with |b| is
> 'acccumulate),
> let b' = accumulate(|a|, b) and composite' = the composite
> mode of |a|.
> iv. Update |b| with b' and use composite' as the composite mode
> for the keyframe.
> (TODO: Add logic here to handle when we have multiple
> properties on the same keyframe and we are changing the
> composite mode. Basically, make a new keyframe in that case,
> but then combine such keyframes at the end of the process.)
> 3. Remove all values of |property| on keyframes in A.
> 4. Remove any empty keyframes on A.
>
> It's pretty complicated and I don't love it, but I think it's a little
> closer to the pit of success we'd like to create? If nothing else, it
> might spark a better idea from someone else.
>
> Best regards,
>
> Brian
>
>
Received on Saturday, 21 November 2015 21:58:37 UTC