Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Animation #21

Closed
anthonyshort opened this issue Dec 11, 2014 · 13 comments
Closed

Adding Animation #21

anthonyshort opened this issue Dec 11, 2014 · 13 comments

Comments

@anthonyshort
Copy link
Owner

WIP

We've been thinking about how animation should work with components. Animation properties are basically another form of state, but it's cumbersome to store that stuff in state. Things like x and y position are a different kind of state. We'd like to be able to include it all in the serialized state too.

We could implement animation in a couple of ways...

  1. Using style tweens with easing and duration
  2. Using a physics library like Impluse.js

Here's an example using an API similar to Impluse

var MyComponent = component({
  afterMount: function(el){
    var position = getPosition(el); 
    this.translate()
      .spring({ tension: 100, damping: 10 })
      .from(position.x, position.y)
      .to(100, 100)
      .start();
  }
});

This would start another requestAnimationFrame loop on the component separate from the virtual DOM loop. This lets us avoid needing to do virtual tree diffing just to update some element animated properties.

If we provide a done method to beforeUnmount we could easily animate an element out:

var MyComponent = component({
  beforeUnmount: function(el, state, props, done){
    var stats = getPosition(el); 
    var position = this.translate()
      .spring({ tension: 100, damping: 10 })
      .from(stats.x, stats.y)
      .to(100, 100)
      .start();
    var opacity = this.fade(1, 0)
       .accelerate(100)
       .start();
    Promise.all([position, opacity], done);
  }
});

This is kind of long, but it's not overly abstract on purpose. We could make this into a plugin, or you could just use another library entirely. We'd just need to make sure whatever library it was played nicely with the updates from the virtual DOM.

@mattdesl
Copy link

Here's my thoughts on animation:

Simple callbacks are good; it forces the user to implement their animation logic. Since there are so many ways of doing animation (tweening, integration, hybrid approach, etc) it should not be baked into the framework.

Some real-world challenges we have faced, and which tend to be difficult with most frameworks:

  • animating one thing based on the completion of several animations; e.g. all buttons in a sidebar animate out, then the sidebar can animate out
  • animations that are dependent on application state or previous route; e.g. sometimes when going from X to Y, different delays or durations lead to better UX
  • overriding animations; user quickly clicks X -> Y -> X -> Y, with a traditional tween/callback approach this can cause problems
  • overlapping transitions: e.g. button slides model text from "Next" to "OK" but for a brief period both labels are visible within the button container; or more complex: cross-fading between routes

@anthonyshort
Copy link
Owner Author

animating one thing based on the completion of several animations; e.g. all buttons in a sidebar animate out, then the sidebar can animate out

If we were able to manually animate out elements using beforeUnmount you'd need to block all parent components from unmounting. This could work but it's definitely tricky and could cause a whole lot of other issues. Like, if a render gets triggered again and it's not expecting an element to be there but it is then 💥

overlapping transitions: e.g. button slides model text from "Next" to "OK" but for a brief period both labels are visible within the button container; or more complex: cross-fading between routes

This is a tough one I seen using "sheet" modals. When it's sliding off the page to hide, the content inside of it might have been removed by the diff, so the sheet is empty.

From what I can tell it's mostly just entering/leaving animations that are the main problem for UI. If we were to say we weren't going to try and cover every animation use-case and focus on animations for UI it might be easier too.

@ds0nt
Copy link

ds0nt commented May 19, 2015

Animation = state change middleware

@ds0nt
Copy link

ds0nt commented May 19, 2015

They are interactive. They are user targetes language. They dont make components unusable. Especially with the completely unstandardised rangr of dependencies. They are often dirty and make no sence in the dom tree.

However.. The catch is that they are high level interactions on really low level details.

You wrote a component DOM selector. I think all animations should go in a compiled CSS-like tween file.

Another thought, tweening can benefit from using a generator instead of a tween fn.

@ds0nt
Copy link

ds0nt commented May 19, 2015

I think layers of semanticly appripriate expressiveness are required. img_20150519_111515

@ds0nt
Copy link

ds0nt commented May 19, 2015

How about, streams. :)

Jsdaily email:
Because each document only has a single template element, it means that any associated stylesheets are "namespaced" to that component. This means CSS doesn't bleed over to other components. This level of encapsulation is important because components work best when they're highly self-contained. I'm not sure if Adam is advocating using standard CSS over React-Style -- the stylesheets in JavaScript approach has some advantages, but I believe Maple's approach will be more accessible to Polymer developers.

@ds0nt
Copy link

ds0nt commented May 19, 2015

Anyways, I think we might like these
https://github.com/yoshuawuyts/fsm-event

@ds0nt
Copy link

ds0nt commented May 20, 2015

Sorry: fsm event was the wrong link. Sorry for shotgunning my thoughts a little.

https://github.com/paldepind/flyd
or
https://github.com/ubolonton/js-csp

@tinchoz49
Copy link

Hi @anthonyshort how are you!

What is the status of this feature?

@blup
Copy link

blup commented Sep 15, 2015

What's the status on this? A done callback would be perfect, at least while a better solution pops up.

@anthonyshort
Copy link
Owner Author

The callback is a difficult one to implement, as you need to block any other UI updates from happening at the same time. We wouldn't be able to run the diff again until it all of the unmount callbacks are done. I think the solution would be to do something like React Motion, a meta-component controls whether a child node exists or not.

Here's a presentation on the various ways it can be handled with React https://speakerdeck.com/vjeux/react-rally-animated-react-performance-toolbox. It's possible to implement the data-bound solution at the end with Deku now using afterRender.

@blup
Copy link

blup commented Sep 16, 2015

Looks like an interesting approach. Are you considering making this a part of Deku, or a plugin? Any chance I could get an example of the data-bound approach? Thanks.

@smmoosavi
Copy link

react-bootstrap are using Transition component in collapse component. final resault work so good. Maybe deku can get idea from this components.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants