UNPKG

@tamagui/react-native-web-lite

Version:
125 lines (124 loc) 8.69 kB
import { invariant } from "@tamagui/react-native-web-internals"; import { shouldUseNativeDriver } from "../NativeAnimatedHelper.mjs"; import SpringConfig from "../SpringConfig.mjs"; import Animation from "./Animation.mjs"; class SpringAnimation extends Animation { constructor(config) { var _config$overshootClam, _config$restDisplacem, _config$restSpeedThre, _config$velocity, _config$velocity2, _config$delay, _config$isInteraction, _config$iterations; if (super(), this._overshootClamping = (_config$overshootClam = config.overshootClamping) !== null && _config$overshootClam !== void 0 ? _config$overshootClam : !1, this._restDisplacementThreshold = (_config$restDisplacem = config.restDisplacementThreshold) !== null && _config$restDisplacem !== void 0 ? _config$restDisplacem : 1e-3, this._restSpeedThreshold = (_config$restSpeedThre = config.restSpeedThreshold) !== null && _config$restSpeedThre !== void 0 ? _config$restSpeedThre : 1e-3, this._initialVelocity = (_config$velocity = config.velocity) !== null && _config$velocity !== void 0 ? _config$velocity : 0, this._lastVelocity = (_config$velocity2 = config.velocity) !== null && _config$velocity2 !== void 0 ? _config$velocity2 : 0, this._toValue = config.toValue, this._delay = (_config$delay = config.delay) !== null && _config$delay !== void 0 ? _config$delay : 0, this._useNativeDriver = shouldUseNativeDriver(config), this._platformConfig = config.platformConfig, this.__isInteraction = (_config$isInteraction = config.isInteraction) !== null && _config$isInteraction !== void 0 ? _config$isInteraction : !this._useNativeDriver, this.__iterations = (_config$iterations = config.iterations) !== null && _config$iterations !== void 0 ? _config$iterations : 1, config.stiffness !== void 0 || config.damping !== void 0 || config.mass !== void 0) { var _config$stiffness, _config$damping, _config$mass; invariant(config.bounciness === void 0 && config.speed === void 0 && config.tension === void 0 && config.friction === void 0, "You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one"), this._stiffness = (_config$stiffness = config.stiffness) !== null && _config$stiffness !== void 0 ? _config$stiffness : 100, this._damping = (_config$damping = config.damping) !== null && _config$damping !== void 0 ? _config$damping : 10, this._mass = (_config$mass = config.mass) !== null && _config$mass !== void 0 ? _config$mass : 1; } else if (config.bounciness !== void 0 || config.speed !== void 0) { var _config$bounciness, _config$speed; invariant(config.tension === void 0 && config.friction === void 0 && config.stiffness === void 0 && config.damping === void 0 && config.mass === void 0, "You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one"); var springConfig = SpringConfig.fromBouncinessAndSpeed((_config$bounciness = config.bounciness) !== null && _config$bounciness !== void 0 ? _config$bounciness : 8, (_config$speed = config.speed) !== null && _config$speed !== void 0 ? _config$speed : 12); this._stiffness = springConfig.stiffness, this._damping = springConfig.damping, this._mass = 1; } else { var _config$tension, _config$friction, _springConfig = SpringConfig.fromOrigamiTensionAndFriction((_config$tension = config.tension) !== null && _config$tension !== void 0 ? _config$tension : 40, (_config$friction = config.friction) !== null && _config$friction !== void 0 ? _config$friction : 7); this._stiffness = _springConfig.stiffness, this._damping = _springConfig.damping, this._mass = 1; } invariant(this._stiffness > 0, "Stiffness value must be greater than 0"), invariant(this._damping > 0, "Damping value must be greater than 0"), invariant(this._mass > 0, "Mass value must be greater than 0"); } __getNativeAnimationConfig() { var _this$_initialVelocit; return { type: "spring", overshootClamping: this._overshootClamping, restDisplacementThreshold: this._restDisplacementThreshold, restSpeedThreshold: this._restSpeedThreshold, stiffness: this._stiffness, damping: this._damping, mass: this._mass, initialVelocity: (_this$_initialVelocit = this._initialVelocity) !== null && _this$_initialVelocit !== void 0 ? _this$_initialVelocit : this._lastVelocity, toValue: this._toValue, iterations: this.__iterations, platformConfig: this._platformConfig }; } start(fromValue, onUpdate, onEnd, previousAnimation, animatedValue) { if (this.__active = !0, this._startPosition = fromValue, this._lastPosition = this._startPosition, this._onUpdate = onUpdate, this.__onEnd = onEnd, this._lastTime = Date.now(), this._frameTime = 0, previousAnimation instanceof SpringAnimation) { var internalState = previousAnimation.getInternalState(); this._lastPosition = internalState.lastPosition, this._lastVelocity = internalState.lastVelocity, this._initialVelocity = this._lastVelocity, this._lastTime = internalState.lastTime; } var start = () => { this._useNativeDriver ? this.__startNativeAnimation(animatedValue) : this.onUpdate(); }; this._delay ? this._timeout = setTimeout(start, this._delay) : start(); } getInternalState() { return { lastPosition: this._lastPosition, lastVelocity: this._lastVelocity, lastTime: this._lastTime }; } /** * This spring model is based off of a damped harmonic oscillator * (https://en.wikipedia.org/wiki/Harmonic_oscillator#Damped_harmonic_oscillator). * * We use the closed form of the second order differential equation: * * x'' + (2ζ⍵_0)x' + ⍵^2x = 0 * * where * ⍵_0 = √(k / m) (undamped angular frequency of the oscillator), * ζ = c / 2√mk (damping ratio), * c = damping constant * k = stiffness * m = mass * * The derivation of the closed form is described in detail here: * http://planetmath.org/sites/default/files/texpdf/39745.pdf * * This algorithm happens to match the algorithm used by CASpringAnimation, * a QuartzCore (iOS) API that creates spring animations. */ onUpdate() { var MAX_STEPS = 64, now = Date.now(); now > this._lastTime + MAX_STEPS && (now = this._lastTime + MAX_STEPS); var deltaTime = (now - this._lastTime) / 1e3; this._frameTime += deltaTime; var c = this._damping, m = this._mass, k = this._stiffness, v0 = -this._initialVelocity, zeta = c / (2 * Math.sqrt(k * m)), omega0 = Math.sqrt(k / m), omega1 = omega0 * Math.sqrt(1 - zeta * zeta), x0 = this._toValue - this._startPosition, position = 0, velocity = 0, t = this._frameTime; if (zeta < 1) { var envelope = Math.exp(-zeta * omega0 * t); position = this._toValue - envelope * ((v0 + zeta * omega0 * x0) / omega1 * Math.sin(omega1 * t) + x0 * Math.cos(omega1 * t)), velocity = zeta * omega0 * envelope * (Math.sin(omega1 * t) * (v0 + zeta * omega0 * x0) / omega1 + x0 * Math.cos(omega1 * t)) - envelope * (Math.cos(omega1 * t) * (v0 + zeta * omega0 * x0) - omega1 * x0 * Math.sin(omega1 * t)); } else { var _envelope = Math.exp(-omega0 * t); position = this._toValue - _envelope * (x0 + (v0 + omega0 * x0) * t), velocity = _envelope * (v0 * (t * omega0 - 1) + t * x0 * (omega0 * omega0)); } if (this._lastTime = now, this._lastPosition = position, this._lastVelocity = velocity, this._onUpdate(position), !!this.__active) { var isOvershooting = !1; this._overshootClamping && this._stiffness !== 0 && (this._startPosition < this._toValue ? isOvershooting = position > this._toValue : isOvershooting = position < this._toValue); var isVelocity = Math.abs(velocity) <= this._restSpeedThreshold, isDisplacement = !0; if (this._stiffness !== 0 && (isDisplacement = Math.abs(this._toValue - position) <= this._restDisplacementThreshold), isOvershooting || isVelocity && isDisplacement) { this._stiffness !== 0 && (this._lastPosition = this._toValue, this._lastVelocity = 0, this._onUpdate(this._toValue)), this.__debouncedOnEnd({ finished: !0 }); return; } this._animationFrame = requestAnimationFrame(this.onUpdate.bind(this)); } } stop() { super.stop(), this.__active = !1, clearTimeout(this._timeout), global.cancelAnimationFrame(this._animationFrame), this.__debouncedOnEnd({ finished: !1 }); } } var SpringAnimation_default = SpringAnimation; export { SpringAnimation_default as default }; //# sourceMappingURL=SpringAnimation.mjs.map