ember-animation / ember-animated

Core animation primitives for Ember.
https://ember-animation.github.io/ember-animated/
MIT License
244 stars 90 forks source link

How best to animated child elements of a Sprite? #149

Open samselikoff opened 5 years ago

samselikoff commented 5 years ago

I'm looking for some general advice on how best to animate children of a Sprite differently from each other. In other words, applying different motions to different parts of a Sprite.

For example, if we're moving an Article detail page into the screen, I might want to apply move to the entire article, but apply a fadeIn to the body of the article.

How should I approach this sort of thing?

I've tried so far adding in nested animators, but sometimes they seem to be treated atomically. Also, I often don't want them removed from the DOM – they are in the correct place and its the parent that's controlling movement. I just want some other motion applied to them, for example.

I'll attach an example here in a sec to show what I mean.

samselikoff commented 5 years ago

Here's the demo.

Transition A does what I want. The parent moves in, and a child fades in halfway through the animation.

You can see from the code that I'm using the Web Animations API to accomplish this:

sprite.element
  .querySelector('[data-animation-id="article-body"]')
  .animate([{ opacity: 0 }, { opacity: 1 }], {
    fill: "backwards",
    delay: duration / 2,
    duration: duration / 2
  });

This is obviously not ideal because it goes outside of Ember Animated, can't be manipulated with Ember Animated Tools, can't be tested as easily, etc.

Transition B is my attempt to use a nested animator to accomplish the same thing. You can see from the template for Transition B that there is a nested Animated Value animator. It reuses the isShowingB state, although that state isn't really meaningful in a sense. It's just there to trigger the transition. I also have to use initialInsertion and finalRemoval to get the child transition to fire as the parent is being mounted and unmounted.

If you try Transition B in the demo you'll see this:

Kapture 2019-08-16 at 10 07 40

If I pause the animation after the nested animator has finished fading out, and the bug happens where the body reappears all narrow, I can see basically two instances of my body contents rendering:

image

I think this has something to do with what's going on. I'm not sure why adding the animator makes it render twice. Almost like one belongs to the parent transition and one to the child.

ef4 commented 5 years ago

I have a list of changes I want to make to solve this class of problems.

samselikoff commented 5 years ago

gotcha.

If you had to do this today what would you recommend? Keeping animators siblings?

ef4 commented 5 years ago

Depends a lot on the particulars, but one good workaround is to always animate sentSprites, which are necessarily cloned out of their regular document positions. This allows a child element like your title to move while avoiding an opacity animation on one of its ancestors.

On Mon, Aug 19, 2019 at 1:30 PM Sam Selikoff notifications@github.com wrote:

gotcha.

If you had to do this today what would you recommend? Keeping animators siblings?

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/ember-animation/ember-animated/issues/149?email_source=notifications&email_token=AACN6MUVOIF7VIW7ESJ4Q7LQFLKCHA5CNFSM4IMHCU32YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD4TWUII#issuecomment-522676769, or mute the thread https://github.com/notifications/unsubscribe-auth/AACN6MQQICDOHMT4V6SCQXDQFLKCHANCNFSM4IMHCU3Q .

samselikoff commented 5 years ago

I see. What if you actually needed to animated receivedSprites (if there was something there that you needed that wasn't in sentSprites)?

emattias commented 4 years ago

This works well for me (so far 😅):

yield new Promise(resolve => {
  removedSprites[0].element
    .querySelector('[data-animation-inner]')
    .animate({ opacity: [1, 0] }, { fill: 'forwards', duration: 1 })
    .addEventListener('finish', resolve);
});

Do we know of or think that there might be some problem with doing it like this?

One limitation I see here is that these child elements dont access to all the goodness in the ember-animated sprite api.

Before I came up with the solution above I thought to use beacons for this but since the beacons are not grouped by inserted, removed, kept etc. Its not possible for my case. I guess beacons are not built for this.