-
Notifications
You must be signed in to change notification settings - Fork 663
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #189 from Popmotion/spring
Adding dedicated `spring` action
- Loading branch information
Showing
8 changed files
with
191 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
--- | ||
title: Spring | ||
description: A UI spring simulation, based on Apple's CASpringAnimation. | ||
category: action | ||
--- | ||
|
||
# Spring | ||
|
||
A highly-accurate spring simulation based on Apple's `CASpringAnimation` implementation. | ||
|
||
This simulation offers greater variety and accuracy than the basic spring equations in [`physics`](/api/physics). | ||
|
||
`spring(props <Object>)` | ||
|
||
## Props | ||
- `stiffness <Number>`: The spring stiffness (default: `100`) | ||
- `damping <Number>`: The strength of the friction force used to dampen motion (default: `10`) | ||
- `mass <Number>`: Mass of the moving object. (default: `1.0`) | ||
- `velocity <Number>`: The initial velocity of the spring. (default: `0.0`) | ||
- `from <Number>`: Start from this number. (default `0`) | ||
- `to <Number>`: End at this number. (default `0`) | ||
- `restDisplacement <Number>`: End the animation if the distance to target is below this value (and `restSpeed`) (default: `0.01`) | ||
- `restSpeed <Number>`: End the animation if the speed drops below this value (and `restDisplacement`) (default: `0.01`) | ||
|
||
## Methods | ||
|
||
[...Action](/api/action) | ||
|
||
## Playground | ||
|
||
```javascript | ||
import { spring } from 'popmotion'; | ||
``` | ||
|
||
```marksy | ||
<Example template="Ball">{` | ||
const ball = document.querySelector('.ball'); | ||
const ballRenderer = css(ball); | ||
spring({ | ||
mass: 2, | ||
stiffness: 1000, | ||
damping: 50, | ||
to: 300 | ||
}).start(); | ||
`}</Example> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import React from 'react'; | ||
import { spring } from '../../../../lib/popmotion'; | ||
import { MotionValue } from '../../src'; | ||
|
||
const makeSpring = (value, to) => spring({ | ||
stiffness: 1000, | ||
damping: 500, | ||
mass: 3, | ||
from: value.get(), | ||
to, | ||
velocity: value.getVelocity(), | ||
onUpdate: value | ||
}); | ||
|
||
export default () => ( | ||
<MotionValue | ||
onStateChange={{ | ||
on: ({value}) => { | ||
console.log(value.getVelocity()) | ||
makeSpring(value, 800).start(); | ||
}, | ||
off: ({value}) => { | ||
console.log(value.getVelocity()) | ||
makeSpring(value, 0).start(); | ||
} | ||
}} | ||
> | ||
{({ v, state, setStateTo }) => ( | ||
<div style={{ width: '100vw', height: '100vh' }} onClick={state === 'on' ? setStateTo.off : setStateTo.on}> | ||
<div | ||
style={{ | ||
background: 'red', | ||
width: '100px', | ||
height: '100px', | ||
transform: 'translateX(' + v + 'px)' | ||
}} | ||
/> | ||
</div> | ||
)} | ||
</MotionValue> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
The closed-form damped harmonic oscillating spring. | ||
Or, spring. | ||
This is a direct port of Adam Miskiewicz's (@skevy) React Animated | ||
PR #15322 https://github.com/facebook/react-native/pull/15322/ | ||
``` | ||
spring({ | ||
mass: 2, | ||
damping: 10, | ||
stiffness: 100, | ||
to: 100 | ||
}).start(); | ||
``` | ||
Adam Miskiewicz: | ||
@skevy (twitter.com/skevy, github.com/skevy) | ||
*/ | ||
import Action from './'; | ||
import { timeSinceLastFrame } from '../framesync'; | ||
|
||
class Spring extends Action { | ||
static defaultProps = { | ||
stiffness: 100, | ||
damping: 10, | ||
mass: 1.0, | ||
velocity: 0.0, | ||
from: 0.0, | ||
to: 0.0, | ||
restSpeed: 0.01, | ||
restDisplacement: 0.01 | ||
}; | ||
|
||
onStart() { | ||
const { velocity, to, from } = this.props; | ||
this.t = 0; | ||
this.initialVelocity = velocity ? velocity / 1000 : 0.0; | ||
this.isComplete = false; | ||
this.delta = to - from; | ||
} | ||
|
||
update() { | ||
const { stiffness, damping, mass, from, to, restSpeed, restDisplacement } = this.props; | ||
const { delta, initialVelocity } = this; | ||
|
||
const timeDelta = timeSinceLastFrame() / 1000; | ||
const t = this.t = this.t + timeDelta; | ||
|
||
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass)); | ||
const angularFreq = Math.sqrt(stiffness / mass); | ||
const expoDecay = angularFreq * Math.sqrt(1.0 - (dampingRatio * dampingRatio)); | ||
|
||
const x0 = 1; | ||
let oscillation = 0.0; | ||
|
||
// Underdamped | ||
if (dampingRatio < 1) { | ||
const envelope = Math.exp(-dampingRatio * angularFreq * t); | ||
oscillation = envelope * (((initialVelocity + dampingRatio * angularFreq * x0) / expoDecay) * Math.sin(expoDecay * t) + (x0 * Math.cos(expoDecay * t))); | ||
this.velocity = (envelope * ((Math.cos(expoDecay * t) * (initialVelocity + dampingRatio * angularFreq * x0)) - (expoDecay * x0 * Math.sin(expoDecay * t))) - | ||
((dampingRatio * angularFreq * envelope) * ((((Math.sin(expoDecay * t) * (initialVelocity + dampingRatio * angularFreq * x0)) ) / expoDecay) + (x0 * Math.cos(expoDecay * t))))); | ||
|
||
// Critically damped | ||
} else { | ||
const envelope = Math.exp(-angularFreq * t); | ||
oscillation = envelope * (x0 + (initialVelocity + (angularFreq * x0)) * t); | ||
this.velocity = envelope * ((t * initialVelocity * angularFreq) - (t * x0 * (angularFreq * angularFreq)) + initialVelocity); | ||
} | ||
|
||
const fraction = 1 - oscillation; | ||
let position = from + fraction * delta; | ||
|
||
// Check if simulation is complete | ||
// We do this here instead of `isActionComplete` as it allows us | ||
// to clamp to end during update) | ||
const isBelowVelocityThreshold = Math.abs(this.velocity) <= restSpeed; | ||
const isBelowDisplacementThreshold = Math.abs(to - position) <= restDisplacement; | ||
this.isComplete = isBelowVelocityThreshold && isBelowDisplacementThreshold; | ||
|
||
if (this.isComplete) { | ||
position = to; | ||
} | ||
|
||
return position; | ||
} | ||
|
||
isActionComplete() { | ||
return this.isComplete; | ||
} | ||
} | ||
|
||
export default (props) => new Spring(props); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters