chenglou / react-motion

A spring that solves your animation problems.
MIT License
21.69k stars 1.16k forks source link

How to figure out or set duration? #265

Open vedmant opened 8 years ago

vedmant commented 8 years ago

I just come across this library, and it would work for me if I was able to set animation duration. I have simple task, I need to rotate object, with some easing for some duration and get callback when animation is finished. I tried this Spring Parameters Chooser, but I didn't get any idea how can I figure out duration and easing from that. Probably this is wrong library to use for my purpose...

alma-socar commented 8 years ago

+1

razh commented 8 years ago

https://github.com/chenglou/react-motion/blob/master/README.md#faq

How do I set the duration of my animation?

Hard-coded duration goes against fluid interfaces. If your animation is interrupted mid-way, you'd get a weird completion animation if you hard-coded the time. That being said, in the demo section there's a great Spring Parameters Chooser for you to have a feel of what spring is appropriate, rather than guessing a duration in the dark.

There's https://github.com/twitter-fabric/velocity-react, which allows to you to set a duration and pass a complete callback: http://julian.com/research/velocity/#beginAndComplete.

vedmant commented 8 years ago

Thanks a lot! Velocity works ok, but it fires complete callback when component mounts for some reason and also it loads whole Jquery library, I found another library on top of Greensock https://github.com/azazdeaz/react-gsap-enhancer, it looks like it will works for me.

timothyallan commented 8 years ago

I'm in the same boat... animating button positions to slide in on a menu, and it currently takes too long even with crazy spring settings. Might have to check out gsap unfortunately, thanks for the suggestion.

daniel-gustafsson commented 8 years ago

I wrote a little helper function once that you might find useful. It calculates stiffness and damping from the dampened frequency (w) and overshoot in fractions. Returns [stiffness, damping]. It maxes out at twice the natural frequency when overshoot goes to zero, which in practice means that overshoot of 0 gives very close to rested state after w seconds.

Default overshoot of zero will return a critically damped spring which is what you probably want in most cases. Overshoot is in fractions per half frequency, which is find intuitive. So o = 0.2, means the spring will overshoot by 20% on each pass.

Critically damped with w = 1 second returns about [158, 25] which in practice is pretty close to the default [170, 26] in the lib.

Overshoot of 1 gives 0 damping, i.e. the spring will run forever.

function configw(w, o = 0) {
  const s = o <= 0
    ? 1 - o
    : 1 / Math.sqrt(1 + Math.pow(2 * Math.PI / Math.log(1 / (o * o)), 2));

  const ks = (2 * Math.PI / w) / Math.max(Math.sqrt(1 - s * s), 0.5);
  const c = 2 * ks * s;
  return [ks * ks, c];
}
chenglou commented 8 years ago

^ We should... ship this.

sompylasar commented 8 years ago

:sheep: it! or :ship: it.

daniel-gustafsson commented 8 years ago

If you like it, feel free to use or derive anything from it however you want :)

chenglou commented 8 years ago

@daniel-gustafsson is there an equation which takes in the actual duration and e.g. initial overshoot percentage, and returns stiffness and damping (assuming there's a single such value)? That'd be perfect. I'm holding off shipping your helper for now because the overhead of explaining damping frequency and overshoot, on top of the existing stiffness and damping, will likely turn away lots of people. But if there's an f: (duration, overshootPercent) -> [stiffness, damping] then I can deprecate the current stiffness/damping API, which will be great.

daniel-gustafsson commented 8 years ago

Well, the duration is exact when you are using any reasonable overshoot like 5% or more (I did calculate the exact figure once but forgot what it was) and the starting velocity is zero. In this case, the time is in seconds from when you start the animation until the value passes the target the second time (the first bounce is complete).

The problem with critically damped springs is that the time to target is always infinite. It would probably be possible to add the precision into the calculation and calculate the time to onRest() this way. Not sure how complicated it would be though, and it still wouldn't be correct when adding an initial velocity.

The important thing to me was to be able to easily change the speed. So I settled for the formula above which gives kind of a "feeling" that 1 second critically damped spring is at rest after about 1 second, even if that time is not exact. And that you, with just one simple change can for example double the speed with 0.5 or double the time with 2.0.

reklawnos commented 8 years ago

I figured out a couple of equations that works fairly nicely for getting a damping and stiffness given a desired overshoot percentage, duration, and error percentage (i.e. how far from the target position can be considered "at" the target).

eqn8140-3

eqn8140-1

Where:

I tried a couple of approximate values on the demo page and it seemed to work.

Basically what this does is models the amplitude change due to damping as exponential decay, which allows for us to solve for the damping given the error percentage and duration, and then finds a value for the stiffness such that at the first negative peak of the oscillation lines up with the overshoot percentage.

reklawnos commented 8 years ago

Uhp, I realized the above doesn't exactly work. It assumes that the peak of the overshoot occurs when the oscillation is at its first minimum peak, but that's not the case. Let me take another look.

mraak commented 6 years ago

Proposal:

In addition to spring(), the library could have to() method, taking durationand easingas parameters along with properties to interpolate. And callbacks of course. Any similarity with GSAP is purely coincidental.