2012-07-27 14 views
5

In CSS3-Übergängen können Sie eine Zeitfunktion als 'kubisch-bezier: (0,25, 0,3, 0,8, 1,0)' angeben. In dieser Zeichenfolge geben Sie nur die XY für Punkte P1 an und P2 entlang der Kurve, da P0 und P3 immer (0,0, 0,0) bzw. (1,0, 1,0) sind.CSS3-Übergänge neu erstellen Cubic-Bezier-Kurve

Laut Apple-Website: x [ist], ausgedrückt als Anteil der Gesamtdauer und y ausgedrückt als Bruchteil der Gesamtänderung

Meine Frage ist, wie diese 1 dimensional zurück zu einem traditionellen abgebildet werden kann T-Wert in Javascript?

-

From Apple docs on animating with transitions
enter image description here

+0

Die 'length' ist eine Funktion des' t' Wert. Ich bin mir nicht wirklich sicher, wie du das machen würdest. – Wex

Antwort

16

Durchstöbern Webkit-Quelle ein wenig, der folgende Code des korrekten T-Wert für die implizite Kurve gibt in CSS3 Übergängen verwendet:

Visual demo (codepen.io)

hoffte, das hilft jemand!

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)); 
} 
0

Sie wollen den [0,1] Wert für jeden Zeitwert t finden [0,1]? Es gibt eine gut definierte Gleichung für eine kubische Bezierkurve. Wikipedia-Seite: http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves

Damit ich ihre (wahrscheinlich LaTeX-formatierte) Formel nicht eingeben muss, kopierte ich die gleiche Formel aus http://local.wasp.uwa.edu.au/~pbourke/geometry/bezier/index2.html. Dies hat auch eine C-Implementierung, die auf einen schnellen Durchlesen, sollte in den Hafen Javascript einfach sein:

B(u) = P0 * (1 - u)3 + P1 * 3 * u * (1 - u)2 + P2 * 3 * u2 * (1 - u) + P3 * u3

Was er mu auf dieser Seite ist Ihr Zeitvariable t aufrufen.

Edit: Wenn Sie nicht die Mathematik tun wollen, sieht es aus wie jemand schrieb bereits eine kleine Utility-Bibliothek in Javascript grundlegende Bezier-Kurve zu tun math: https://github.com/sporritt/jsBezier. pointOnCurve (Kurve, Ort) sieht genau so aus, wie Sie es wünschen.

+0

Das gibt den Punkt P entlang der Kurve, aber nicht, wie man das zurück in eine endgültige Position für das bewegte Objekt übersetzt. (Ich bewege das Objekt nicht entlang der Kurve) – 1dayitwillmake

-1

Ich habe versucht und suche eine Menge Zeit und Formen und auf jeden Fall habe ich eine einfache und schnelle erreicht. Der Trick ist, die kubische Bezierfunktion in dieser Form zu erhalten: P (u) = u^3 (c0 + 3c1 - 3c2 + c3) + u2 (3c0 - 6c1 + 3c2) + u (-3c0 + 3c1) + c0 wo ci die Kontrollpunkte sind. Der andere Teil ist Suche y von x mit einer binären Suche.

static public class CubicBezier { 
    private BezierCubic bezier = new BezierCubic(); 
    public CubicBezier(float x1, float y1, float x2, float y2) { 
     bezier.set(new Vector3(0,0,0), new Vector3(x1,y1,0), new Vector3(x2,y2,0), new Vector3(1,1,1)); 
    } 
    public float get(float t) { 
     float l=0, u=1, s=(u+l)*0.5f; 
     float x = bezier.getValueX(s); 
     while (Math.abs(t-x) > 0.0001f) { 
      if (t > x) { l = s; } 
      else  { u = s; } 
      s = (u+l)*0.5f; 
      x = bezier.getValueX(s); 
     } 
     return bezier.getValueY(s); 
    } 
}; 

public class BezierCubic { 
private float[][] cpoints = new float[4][3]; 
private float[][] polinom = new float[4][3]; 

public BezierCubic() {} 

public void set(Vector3 c0, Vector3 c1, Vector3 c2, Vector3 c3) { 
    setPoint(0, c0); 
    setPoint(1, c1); 
    setPoint(2, c2); 
    setPoint(3, c3); 
    generate(); 
} 

public float getValueX(float u) { 
    return getValue(0, u); 
} 

public float getValueY(float u) { 
    return getValue(1, u); 
} 

public float getValueZ(float u) { 
    return getValue(2, u); 
} 

private float getValue(int i, float u) { 
    return ((polinom[0][i]*u + polinom[1][i])*u + polinom[2][i])*u + polinom[3][i]; 
} 

private void generate() { 
    for (int i=0; i<3; i++) { 
     float c0 = cpoints[0][i], c1 = cpoints[1][i], c2 = cpoints[2][i], c3 = cpoints[3][i]; 
     polinom[0][i] = c0 + 3*(c1 - c2) + c3; 
     polinom[1][i] = 3*(c0 - 2*c1 + c2); 
     polinom[2][i] = 3*(-c0 + c1); 
     polinom[3][i] = c0; 
    } 
} 

private void setPoint(int i, Vector3 v) { 
    cpoints[i][0] = v.x; 
    cpoints[i][1] = v.y; 
    cpoints[i][2] = v.z; 
} 

}

Verwandte Themen