UNPKG

animare

Version:

Advanced animation library for modern JavaScript.

11 lines 2.79 kB
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.default=cubicBezier;/** * https://github.com/gre/bezier-easing * BezierEasing - use bezier curve for transition easing function * by Gaëtan Renaudeau 2014 - 2015 – MIT License */ // These values are established by empiricism with tests (tradeoff: performance VS precision) const NEWTON_ITERATIONS=4,NEWTON_MIN_SLOPE=0.001,SUBDIVISION_PRECISION=0.0000001,SUBDIVISION_MAX_ITERATIONS=10,kSplineTableSize=11,kSampleStepSize=1.0/(kSplineTableSize-1.0);const A=(aA1,aA2)=>1.0-3.0*aA2+3.0*aA1;const B=(aA1,aA2)=>3.0*aA2-6.0*aA1;const C=aA1=>3.0*aA1;// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. const calcBezier=(aT,aA1,aA2)=>((A(aA1,aA2)*aT+B(aA1,aA2))*aT+C(aA1))*aT;// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2. const getSlope=(aT,aA1,aA2)=>3.0*A(aA1,aA2)*aT*aT+2.0*B(aA1,aA2)*aT+C(aA1);function binarySubdivide(aX,aA,aB,mX1,mX2){let currentX,currentT,i=0;do{currentT=aA+(aB-aA)/2.0;currentX=calcBezier(currentT,mX1,mX2)-aX;if(currentX>0.0){aB=currentT;}else{aA=currentT;}}while(Math.abs(currentX)>SUBDIVISION_PRECISION&&++i<SUBDIVISION_MAX_ITERATIONS);return currentT;}function newtonRaphsonIterate(aX,aGuessT,mX1,mX2){for(let i=0;i<NEWTON_ITERATIONS;++i){const currentSlope=getSlope(aGuessT,mX1,mX2);if(currentSlope===0.0)return aGuessT;const currentX=calcBezier(aGuessT,mX1,mX2)-aX;aGuessT-=currentX/currentSlope;}return aGuessT;}const LinearEasing=x=>x;function cubicBezier(mX1,mY1,mX2,mY2){if(!(0<=mX1&&mX1<=1&&0<=mX2&&mX2<=1))throw new Error('/n/n⛔ [animare] ➡️ [ease] ➡️ [cubicBezier] : bezier x values must be in [0, 1] range. !!\n\n');if(mX1===mY1&&mX2===mY2)return LinearEasing;// Precompute samples table const sampleValues=typeof Float32Array==='function'?new Float32Array(kSplineTableSize):new Array(kSplineTableSize);for(let i=0;i<kSplineTableSize;++i)sampleValues[i]=calcBezier(i*kSampleStepSize,mX1,mX2);function getTForX(aX){let intervalStart=0.0,currentSample=1;const lastSample=kSplineTableSize-1;for(;currentSample!==lastSample&&sampleValues[currentSample]<=aX;++currentSample)intervalStart+=kSampleStepSize;--currentSample;// Interpolate to provide an initial guess for t const dist=(aX-sampleValues[currentSample])/(sampleValues[currentSample+1]-sampleValues[currentSample]),guessForT=intervalStart+dist*kSampleStepSize,initialSlope=getSlope(guessForT,mX1,mX2);if(initialSlope>=NEWTON_MIN_SLOPE)return newtonRaphsonIterate(aX,guessForT,mX1,mX2);if(initialSlope===0.0)return guessForT;return binarySubdivide(aX,intervalStart,intervalStart+kSampleStepSize,mX1,mX2);}return t=>{// Because JavaScript number are imprecise, we should guarantee the extremes are right. if(t===0||t===1)return t;return calcBezier(getTForX(t),mY1,mY2);};}