mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Much better bezier solver
This commit is contained in:
@@ -101,7 +101,6 @@
|
||||
tf = tf(this.duration);
|
||||
|
||||
return this._run(function(percent, now, virtual) {
|
||||
console.log(percent);
|
||||
self.el[0].style[ionic.CSS.TRANSFORM] = 'translate3d(' + (percent * 400) + 'px, 0,0)';
|
||||
}, function() {
|
||||
return true;
|
||||
@@ -122,11 +121,9 @@
|
||||
* @param duration {Integer} Milliseconds to run the animation
|
||||
* @param easingMethod {Function} Pointer to easing function
|
||||
* Signature of the method should be `function(percent) { return modifiedValue; }`
|
||||
* @param root {Element} Render root, when available. Used for internal
|
||||
* usage of requestAnimationFrame.
|
||||
* @return {Integer} Identifier of animation. Can be used to stop it any time.
|
||||
*/
|
||||
_run: function(stepCallback, verifyCallback, completedCallback, duration, easingMethod, root) {
|
||||
_run: function(stepCallback, verifyCallback, completedCallback, duration, easingMethod) {
|
||||
|
||||
var start = time();
|
||||
var lastFrame = start;
|
||||
@@ -134,10 +131,6 @@
|
||||
var dropCounter = 0;
|
||||
var id = counter++;
|
||||
|
||||
if (!root) {
|
||||
root = document.body;
|
||||
}
|
||||
|
||||
// Compacting running db automatically every few new animations
|
||||
if (id % 20 === 0) {
|
||||
var newRunning = {};
|
||||
@@ -192,7 +185,7 @@
|
||||
completedCallback && completedCallback(desiredFrames - (dropCounter / ((now - start) / millisecondsPerSecond)), id, percent === 1 || duration == null);
|
||||
} else if (render) {
|
||||
lastFrame = now;
|
||||
ionic.requestAnimationFrame(step, root);
|
||||
ionic.requestAnimationFrame(step);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -200,7 +193,7 @@
|
||||
running[id] = true;
|
||||
|
||||
// Init first step
|
||||
ionic.requestAnimationFrame(step, root);
|
||||
ionic.requestAnimationFrame(step);
|
||||
|
||||
// Return unique animation ID
|
||||
return id;
|
||||
|
||||
@@ -1,3 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
(function(ionic) {
|
||||
|
||||
var bezierCoord = function (x,y) {
|
||||
@@ -13,66 +37,393 @@
|
||||
|
||||
ionic.Animation = ionic.Animation || {}
|
||||
|
||||
ionic.Animation.Bezier = {
|
||||
// Quadratic bezier solver
|
||||
getQuadraticBezier: function(percent,C1,C2,C3,C4) {
|
||||
var pos = new bezierCoord();
|
||||
pos.x = C1.x*B1(percent) + C2.x*B2(percent) + C3.x*B3(percent) + C4.x*B4(percent);
|
||||
pos.y = C1.y*B1(percent) + C2.y*B2(percent) + C3.y*B3(percent) + C4.y*B4(percent);
|
||||
return pos;
|
||||
},
|
||||
|
||||
// Cubic bezier solver from https://github.com/arian/cubic-bezier (MIT)
|
||||
getCubicBezier: function(x1, y1, x2, y2, duration) {
|
||||
// Precision
|
||||
epsilon = (1000 / 60 / duration) / 4;
|
||||
|
||||
var curveX = function(t){
|
||||
var v = 1 - t;
|
||||
return 3 * v * v * t * x1 + 3 * v * t * t * x2 + t * t * t;
|
||||
|
||||
/**
|
||||
* JavaScript port of Webkit implementation of CSS cubic-bezier(p1x.p1y,p2x,p2y) by http://mck.me
|
||||
* http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/platform/graphics/UnitBezier.h
|
||||
*/
|
||||
ionic.Animation.Bezier = (function(){
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Duration value to use when one is not specified (400ms is a common value).
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
var DEFAULT_DURATION = 400;//ms
|
||||
|
||||
/**
|
||||
* The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds.
|
||||
* The longer the animation, the more precision we need in the timing function result to avoid ugly discontinuities.
|
||||
* http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/page/animation/AnimationBase.cpp
|
||||
*/
|
||||
var solveEpsilon = function(duration) {
|
||||
return 1.0 / (200.0 * duration);
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines a cubic-bezier curve given the middle two control points.
|
||||
* NOTE: first and last control points are implicitly (0,0) and (1,1).
|
||||
* @param p1x {number} X component of control point 1
|
||||
* @param p1y {number} Y component of control point 1
|
||||
* @param p2x {number} X component of control point 2
|
||||
* @param p2y {number} Y component of control point 2
|
||||
*/
|
||||
var unitBezier = function(p1x, p1y, p2x, p2y) {
|
||||
|
||||
// private members --------------------------------------------
|
||||
|
||||
// Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
|
||||
|
||||
/**
|
||||
* X component of Bezier coefficient C
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
var cx = 3.0 * p1x;
|
||||
|
||||
/**
|
||||
* X component of Bezier coefficient B
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
var bx = 3.0 * (p2x - p1x) - cx;
|
||||
|
||||
/**
|
||||
* X component of Bezier coefficient A
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
var ax = 1.0 - cx -bx;
|
||||
|
||||
/**
|
||||
* Y component of Bezier coefficient C
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
var cy = 3.0 * p1y;
|
||||
|
||||
/**
|
||||
* Y component of Bezier coefficient B
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
var by = 3.0 * (p2y - p1y) - cy;
|
||||
|
||||
/**
|
||||
* Y component of Bezier coefficient A
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
var ay = 1.0 - cy - by;
|
||||
|
||||
/**
|
||||
* @param t {number} parametric timing value
|
||||
* @return {number}
|
||||
*/
|
||||
var sampleCurveX = function(t) {
|
||||
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
|
||||
return ((ax * t + bx) * t + cx) * t;
|
||||
};
|
||||
|
||||
var curveY = function(t){
|
||||
var v = 1 - t;
|
||||
return 3 * v * v * t * y1 + 3 * v * t * t * y2 + t * t * t;
|
||||
|
||||
/**
|
||||
* @param t {number} parametric timing value
|
||||
* @return {number}
|
||||
*/
|
||||
var sampleCurveY = function(t) {
|
||||
return ((ay * t + by) * t + cy) * t;
|
||||
};
|
||||
|
||||
var derivativeCurveX = function(t){
|
||||
var v = 1 - t;
|
||||
return 3 * (2 * (t - 1) * t + v * v) * x1 + 3 * (- t * t * t + 2 * v * t) * x2;
|
||||
|
||||
/**
|
||||
* @param t {number} parametric timing value
|
||||
* @return {number}
|
||||
*/
|
||||
var sampleCurveDerivativeX = function(t) {
|
||||
return (3.0 * ax * t + 2.0 * bx) * t + cx;
|
||||
};
|
||||
|
||||
return function(t) {
|
||||
|
||||
var x = t, t0, t1, t2, x2, d2, i;
|
||||
|
||||
|
||||
/**
|
||||
* Given an x value, find a parametric value it came from.
|
||||
* @param x {number} value of x along the bezier curve, 0.0 <= x <= 1.0
|
||||
* @param epsilon {number} accuracy limit of t for the given x
|
||||
* @return {number} the t value corresponding to x
|
||||
*/
|
||||
var solveCurveX = function(x, epsilon) {
|
||||
var t0;
|
||||
var t1;
|
||||
var t2;
|
||||
var x2;
|
||||
var d2;
|
||||
var i;
|
||||
|
||||
// First try a few iterations of Newton's method -- normally very fast.
|
||||
for (t2 = x, i = 0; i < 8; i++){
|
||||
x2 = curveX(t2) - x;
|
||||
if (Math.abs(x2) < epsilon) return curveY(t2);
|
||||
d2 = derivativeCurveX(t2);
|
||||
if (Math.abs(d2) < 1e-6) break;
|
||||
for (t2 = x, i = 0; i < 8; i++) {
|
||||
x2 = sampleCurveX(t2) - x;
|
||||
if (Math.abs (x2) < epsilon) {
|
||||
return t2;
|
||||
}
|
||||
d2 = sampleCurveDerivativeX(t2);
|
||||
if (Math.abs(d2) < 1e-6) {
|
||||
break;
|
||||
}
|
||||
t2 = t2 - x2 / d2;
|
||||
}
|
||||
|
||||
t0 = 0, t1 = 1, t2 = x;
|
||||
|
||||
if (t2 < t0) return curveY(t0);
|
||||
if (t2 > t1) return curveY(t1);
|
||||
|
||||
// Fallback to the bisection method for reliability.
|
||||
while (t0 < t1){
|
||||
x2 = curveX(t2);
|
||||
if (Math.abs(x2 - x) < epsilon) return curveY(t2);
|
||||
if (x > x2) t0 = t2;
|
||||
else t1 = t2;
|
||||
|
||||
// Fall back to the bisection method for reliability.
|
||||
t0 = 0.0;
|
||||
t1 = 1.0;
|
||||
t2 = x;
|
||||
|
||||
if (t2 < t0) {
|
||||
return t0;
|
||||
}
|
||||
if (t2 > t1) {
|
||||
return t1;
|
||||
}
|
||||
|
||||
while (t0 < t1) {
|
||||
x2 = sampleCurveX(t2);
|
||||
if (Math.abs(x2 - x) < epsilon) {
|
||||
return t2;
|
||||
}
|
||||
if (x > x2) {
|
||||
t0 = t2;
|
||||
} else {
|
||||
t1 = t2;
|
||||
}
|
||||
t2 = (t1 - t0) * 0.5 + t0;
|
||||
}
|
||||
|
||||
// Failure
|
||||
return curveY(t2);
|
||||
|
||||
// Failure.
|
||||
return t2;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0
|
||||
* @param epsilon {number} the accuracy of t for the given x
|
||||
* @return {number} the y value along the bezier curve
|
||||
*/
|
||||
var solve = function(x, epsilon) {
|
||||
return sampleCurveY(solveCurveX(x, epsilon));
|
||||
};
|
||||
|
||||
// public interface --------------------------------------------
|
||||
|
||||
/**
|
||||
* Find the y of the cubic-bezier for a given x with accuracy determined by the animation duration.
|
||||
* @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0
|
||||
* @param duration {number} the duration of the animation in milliseconds
|
||||
* @return {number} the y value along the bezier curve
|
||||
*/
|
||||
return function(x, duration) {
|
||||
return solve(x, solveEpsilon(+duration || DEFAULT_DURATION));
|
||||
};
|
||||
};
|
||||
|
||||
// http://www.w3.org/TR/css3-transitions/#transition-timing-function
|
||||
return {
|
||||
/**
|
||||
* @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0
|
||||
* @param duration {number} the duration of the animation in milliseconds
|
||||
* @return {number} the y value along the bezier curve
|
||||
*/
|
||||
linear: unitBezier(0.0, 0.0, 1.0, 1.0),
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0
|
||||
* @param duration {number} the duration of the animation in milliseconds
|
||||
* @return {number} the y value along the bezier curve
|
||||
*/
|
||||
ease: unitBezier(0.25, 0.1, 0.25, 1.0),
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0
|
||||
* @param duration {number} the duration of the animation in milliseconds
|
||||
* @return {number} the y value along the bezier curve
|
||||
*/
|
||||
easeIn: unitBezier(0.42, 0, 1.0, 1.0),
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0
|
||||
* @param duration {number} the duration of the animation in milliseconds
|
||||
* @return {number} the y value along the bezier curve
|
||||
*/
|
||||
easeOut: unitBezier(0, 0, 0.58, 1.0),
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0
|
||||
* @param duration {number} the duration of the animation in milliseconds
|
||||
* @return {number} the y value along the bezier curve
|
||||
*/
|
||||
easeInOut: unitBezier(0.42, 0, 0.58, 1.0),
|
||||
|
||||
/**
|
||||
* @param p1x {number} X component of control point 1
|
||||
* @param p1y {number} Y component of control point 1
|
||||
* @param p2x {number} X component of control point 2
|
||||
* @param p2y {number} Y component of control point 2
|
||||
* @param x {number} the value of x along the bezier curve, 0.0 <= x <= 1.0
|
||||
* @param duration {number} the duration of the animation in milliseconds
|
||||
* @return {number} the y value along the bezier curve
|
||||
*/
|
||||
cubicBezier: function(p1x, p1y, p2x, p2y, x, duration) {
|
||||
return unitBezier(p1x, p1y, p2x, p2y)(x, duration);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
* Various fast approximations and alternates to cubic-bezier easing functions.
|
||||
* http://www.w3.org/TR/css3-transitions/#transition-timing-function
|
||||
*/
|
||||
var Easing = (function(){
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @const
|
||||
*/
|
||||
var EASE_IN_OUT_CONST = 0.5 * Math.pow(0.5, 1.925);
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
linear: function(x) {
|
||||
return x;
|
||||
},
|
||||
|
||||
// /**
|
||||
// * @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
// * @return {number} the y value along the curve
|
||||
// */
|
||||
// ease: function(x) {
|
||||
// // TODO: find fast approximations
|
||||
// return x;
|
||||
// },
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
easeInApprox: function(x) {
|
||||
// very close approximation to cubic-bezier(0.42, 0, 1.0, 1.0)
|
||||
return Math.pow(x, 1.685);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
easeInQuadratic: function(x) {
|
||||
return (x * x);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
easeInCubic: function(x) {
|
||||
return (x * x * x);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
easeOutApprox: function(x) {
|
||||
// very close approximation to cubic-bezier(0, 0, 0.58, 1.0)
|
||||
return 1 - Math.pow(1-x, 1.685);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
easeOutQuadratic: function(x) {
|
||||
x -= 1;
|
||||
return 1 - (x * x);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
easeOutCubic: function(x) {
|
||||
x -= 1;
|
||||
return 1 + (x * x * x);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
easeInOutApprox: function(x) {
|
||||
// very close approximation to cubic-bezier(0.42, 0, 0.58, 1.0)
|
||||
if (x < 0.5) {
|
||||
return EASE_IN_OUT_CONST * Math.pow(x, 1.925);
|
||||
|
||||
} else {
|
||||
return 1 - EASE_IN_OUT_CONST * Math.pow(1-x, 1.925);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
easeInOutQuadratic: function(x) {
|
||||
if (x < 0.5) {
|
||||
return (2 * x * x);
|
||||
|
||||
} else {
|
||||
x -= 1;
|
||||
return 1 - (2 * x * x);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
easeInOutCubic: function(x) {
|
||||
if (x < 0.5) {
|
||||
return (4 * x * x * x);
|
||||
|
||||
} else {
|
||||
x -= 1;
|
||||
return 1 + (4 * x * x * x);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
easeInOutQuartic: function(x) {
|
||||
if (x < 0.5) {
|
||||
return (8 * x * x * x * x);
|
||||
|
||||
} else {
|
||||
x -= 1;
|
||||
return 1 + (8 * x * x * x * x);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param x {number} the value of x along the curve, 0.0 <= x <= 1.0
|
||||
* @return {number} the y value along the curve
|
||||
*/
|
||||
easeInOutQuintic: function(x) {
|
||||
if (x < 0.5) {
|
||||
return (16 * x * x * x * x * x);
|
||||
|
||||
} else {
|
||||
x -= 1;
|
||||
return 1 + (16 * x * x * x * x * x);
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
})(ionic);
|
||||
|
||||
@@ -7,32 +7,27 @@
|
||||
ionic.Animation.TimingFn = {
|
||||
'linear': function(duration) {
|
||||
return function(t) {
|
||||
return t;
|
||||
return ionic.Animation.Bezier.linear(t, duration);
|
||||
}
|
||||
},
|
||||
'ease': function(duration) {
|
||||
var bz = ionic.Animation.Bezier.getCubicBezier(0.25, 0.1, 0.25, 1.0, duration);
|
||||
return function(t) {
|
||||
return bz(t);
|
||||
return ionic.Animation.Bezier.ease(t, duration);
|
||||
}
|
||||
},
|
||||
'ease-in': function(duration) {
|
||||
//0.42, 0.0, 1.0, 1.0
|
||||
var bz = ionic.Animation.Bezier.getCubicBezier(0.42, 0.0, 1.0, 1.0, duration);
|
||||
return function(t) {
|
||||
return bz(t);
|
||||
return ionic.Animation.Bezier.easeIn(t, duration);
|
||||
}
|
||||
},
|
||||
'ease-out': function(duration) {
|
||||
var bz = ionic.Animation.Bezier.getCubicBezier(0.0, 0.0, 0.58, 1.0, duration);
|
||||
return function(t) {
|
||||
return bz(t);
|
||||
return ionic.Animation.Bezier.easeOut(t, duration);
|
||||
}
|
||||
},
|
||||
'ease-in-out': function(duration) {
|
||||
var bz = ionic.Animation.Bezier.getCubicBezier(0.42, 0.0, 0.58, 1.0, duration);
|
||||
return function(t) {
|
||||
return bz(t);
|
||||
return ionic.Animation.Bezier.easeInOut(t, duration);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user