Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 4x 2x 1x 4x 4x 18x 18x 2x 2x 2x 2x 2x 2x 2x 10x 10x 10x 10x 2x 2x 2x | import {
InertiaOptions,
PlaybackControls,
AnimationOptions,
SpringOptions,
} from "./types"
import { animate } from "."
import { velocityPerSecond } from "../utils/velocity-per-second"
import { getFrameData } from "framesync"
export function inertia({
from = 0,
velocity = 0,
min,
max,
power = 0.8,
timeConstant = 750,
bounceStiffness = 500,
bounceDamping = 10,
restDelta = 1,
modifyTarget,
driver,
onUpdate,
onComplete,
}: InertiaOptions) {
let currentAnimation: PlaybackControls
function isOutOfBounds(v: number) {
return (min !== undefined && v < min) || (max !== undefined && v > max)
}
function boundaryNearest(v: number) {
if (min === undefined) return max
Eif (max === undefined) return min
return Math.abs(min - v) < Math.abs(max - v) ? min : max
}
function startAnimation(options: AnimationOptions<number>) {
currentAnimation?.stop()
currentAnimation = animate({
...options,
driver,
onUpdate: (v: number) => {
onUpdate?.(v)
options.onUpdate?.(v)
},
onComplete,
})
}
function startSpring(options: SpringOptions) {
startAnimation({
type: "spring",
stiffness: bounceStiffness,
damping: bounceDamping,
restDelta,
...options,
})
}
Iif (isOutOfBounds(from)) {
// Start the animation with spring if outside the defined boundaries
startSpring({ from, velocity, to: boundaryNearest(from) })
} else {
/**
* Or if the value is out of bounds, simulate the inertia movement
* with the decay animation.
*
* Pre-calculate the target so we can detect if it's out-of-bounds.
* If it is, we want to check per frame when to switch to a spring
* animation
*/
let target = power * velocity + from
Iif (typeof modifyTarget !== "undefined") target = modifyTarget(target)
const boundary = boundaryNearest(target)
const heading = boundary === min ? -1 : 1
let prev: number
let current: number
const checkBoundary = (v: number) => {
prev = current
current = v
velocity = velocityPerSecond(v - prev, getFrameData().delta)
if (
(heading === 1 && v > boundary) ||
(heading === -1 && v < boundary)
) {
startSpring({ from: v, to: boundary, velocity })
}
}
startAnimation({
type: "decay",
from,
velocity,
timeConstant,
power,
restDelta,
modifyTarget,
onUpdate: isOutOfBounds(target) ? checkBoundary : undefined,
})
}
return {
stop: () => currentAnimation?.stop(),
}
}
|