12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- export function cubicBezier(p1x : number, p1y : number, p2x : number, p2y : number):(x: number)=> number {
- const ZERO_LIMIT = 1e-6;
- // Calculate the polynomial coefficients,
- // implicit first and last control points are (0,0) and (1,1).
- const ax = 3 * p1x - 3 * p2x + 1;
- const bx = 3 * p2x - 6 * p1x;
- const cx = 3 * p1x;
- const ay = 3 * p1y - 3 * p2y + 1;
- const by = 3 * p2y - 6 * p1y;
- const cy = 3 * p1y;
- function sampleCurveDerivativeX(t : number) : number {
- // `ax t^3 + bx t^2 + cx t` expanded using Horner's rule
- return (3 * ax * t + 2 * bx) * t + cx;
- }
- function sampleCurveX(t : number) : number {
- return ((ax * t + bx) * t + cx) * t;
- }
- function sampleCurveY(t : number) : number {
- return ((ay * t + by) * t + cy) * t;
- }
- // Given an x value, find a parametric value it came from.
- function solveCurveX(x : number) : number {
- let t2 = x;
- let derivative : number;
- let x2 : number;
- // https://trac.webkit.org/browser/trunk/Source/WebCore/platform/animation
- // first try a few iterations of Newton's method -- normally very fast.
- // http://en.wikipedia.org/wikiNewton's_method
- for (let i = 0; i < 8; i++) {
- // f(t) - x = 0
- x2 = sampleCurveX(t2) - x;
- if (Math.abs(x2) < ZERO_LIMIT) {
- return t2;
- }
- derivative = sampleCurveDerivativeX(t2);
- // == 0, failure
- /* istanbul ignore if */
- if (Math.abs(derivative) < ZERO_LIMIT) {
- break;
- }
- t2 -= x2 / derivative;
- }
- // Fall back to the bisection method for reliability.
- // bisection
- // http://en.wikipedia.org/wiki/Bisection_method
- let t1 = 1;
- /* istanbul ignore next */
- let t0 = 0;
- /* istanbul ignore next */
- t2 = x;
- /* istanbul ignore next */
- while (t1 > t0) {
- x2 = sampleCurveX(t2) - x;
- if (Math.abs(x2) < ZERO_LIMIT) {
- return t2;
- }
- if (x2 > 0) {
- t1 = t2;
- } else {
- t0 = t2;
- }
- t2 = (t1 + t0) / 2;
- }
- // Failure
- return t2;
- }
- return function (x : number) : number {
- return sampleCurveY(solveCurveX(x));
- }
- // return solve;
- }
|