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(), } } |