In CSS3 transitions, you can specify a timing function as 'cubic-bezier:(0.25, 0.3, 0.8, 1.0)' In that string, you are only specifying the XY for points P1 and P2 along the curve, as P0 and P3 are always (0.0, 0.0), and (1.0, 1.0) respectively.
According to Apple's site: x [is] expressed as a fraction of the overall duration and y expressed as a fraction of the overall change
My question is how can this be mapped back to a traditional 1 dimensional T value in javascript?
--
From Apple docs on animating with transitions
Browsing through webkit-source a bit, the following code will give the correct T value for the implicit curve used in CSS3 transitions:
Visual demo (codepen.io)
Hope this helps someone!
function loop(){
var t = (now - animationStartTime) / ( animationDuration*1000 );
var curve = new UnitBezier(Bx, By, Cx, Cy);
var t1 = curve.solve(t, UnitBezier.prototype.epsilon);
var s1 = 1.0-t1;
// Lerp using solved T
var finalPosition.x = (startPosition.x * s1) + (endPosition.x * t1);
var finalPosition.y = (startPosition.y * s1) + (endPosition.y * t1);
}
/**
* Solver for cubic bezier curve with implicit control points at (0,0) and (1.0, 1.0)
*/
function UnitBezier(p1x, p1y, p2x, p2y) {
// pre-calculate the polynomial coefficients
// First and last control points are implied to be (0,0) and (1.0, 1.0)
this.cx = 3.0 * p1x;
this.bx = 3.0 * (p2x - p1x) - this.cx;
this.ax = 1.0 - this.cx -this.bx;
this.cy = 3.0 * p1y;
this.by = 3.0 * (p2y - p1y) - this.cy;
this.ay = 1.0 - this.cy - this.by;
}
UnitBezier.prototype.epsilon = 1e-6; // Precision
UnitBezier.prototype.sampleCurveX = function(t) {
return ((this.ax * t + this.bx) * t + this.cx) * t;
}
UnitBezier.prototype.sampleCurveY = function (t) {
return ((this.ay * t + this.by) * t + this.cy) * t;
}
UnitBezier.prototype.sampleCurveDerivativeX = function (t) {
return (3.0 * this.ax * t + 2.0 * this.bx) * t + this.cx;
}
UnitBezier.prototype.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 = this.sampleCurveX(t2) - x;
if (Math.abs (x2) < epsilon)
return t2;
d2 = this.sampleCurveDerivativeX(t2);
if (Math.abs(d2) < epsilon)
break;
t2 = t2 - x2 / d2;
}
// No solution found - use bi-section
t0 = 0.0;
t1 = 1.0;
t2 = x;
if (t2 < t0) return t0;
if (t2 > t1) return t1;
while (t0 < t1) {
x2 = this.sampleCurveX(t2);
if (Math.abs(x2 - x) < epsilon)
return t2;
if (x > x2) t0 = t2;
else t1 = t2;
t2 = (t1 - t0) * .5 + t0;
}
// Give up
return t2;
}
// Find new T as a function of Y along curve X
UnitBezier.prototype.solve = function (x, epsilon) {
return this.sampleCurveY( this.solveCurveX(x, epsilon) );
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With