- From: Kevin Doughty <socallednonflipped@gmail.com>
- Date: Sat, 21 Nov 2015 17:08:16 -0500
- To: Brian Birtles <bbirtles@mozilla.com>
- Cc: public-fx@w3.org, www-style@w3.org
- Message-ID: <CAAbwtRwrgmP=J8NoS3o=e31202rhZ8r5f6t86TG=-npw_URSXA@mail.gmail.com>
Of course the link doesn't work. addAnimation:forKey: On Sat, Nov 21, 2015 at 4:58 PM, Kevin Doughty <socallednonflipped@gmail.com > wrote: > > 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 22:08:45 UTC