- 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:42 UTC