2012-07-27 36 views
5

Trong chuyển tiếp CSS3, bạn có thể chỉ định hàm thời gian là 'khối bezier: (0.25, 0.3, 0.8, 1.0)' Trong chuỗi đó, bạn chỉ xác định XY cho điểm P1 và P2 dọc theo đường cong, vì P0 và P3 luôn là (0.0, 0.0) và (1.0, 1.0) tương ứng.Tái tạo chuyển tiếp CSS3 Đường tròn Cubic-Bezier

Theo trang web của Apple: x [là] thể hiện dưới dạng một phần nhỏ của thời gian tổng thể và y thể hiện như một phần của sự thay đổi tổng thể

Câu hỏi của tôi là như thế nào điều này có thể được ánh xạ trở lại một truyền thống 1 chiều T giá trị trong javascript?

-

From Apple docs on animating with transitions
enter image description here

+0

Lệnh 'length' là một hàm của' giá trị t'. Không thực sự chắc chắn làm thế nào bạn muốn đi về việc đó mặc dù. – Wex

Trả lời

16

Duyệt qua webkit nguồn một chút, đoạn code sau sẽ cho giá trị T chính xác cho các đường cong ngầm được sử dụng trong quá trình chuyển đổi CSS3:

Visual demo (codepen.io)

Hy vọng điều này sẽ giúp người!

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

Bạn muốn tìm [0,1] giá trị đối với bất kỳ giá trị thời gian t [0,1]? Có một phương trình được xác định rõ ràng cho một đường cong bezier khối. Trang Wikipedia: http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves

Vì vậy, tôi không phải loại bỏ công thức của họ (có thể là định dạng LaTeX), tôi đã sao chép cùng một công thức từ http://local.wasp.uwa.edu.au/~pbourke/geometry/bezier/index2.html. Điều này cũng có một thực hiện C đó, trên một cách nhanh chóng đọc qua, nên dễ cổng để javascript:

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

Những gì ông đang gọi mu trên trang đó là thời gian của bạn biến t.

Chỉnh sửa: Nếu bạn không muốn làm toán, có vẻ như ai đó đã viết một thư viện tiện ích nhỏ trong javascript để thực hiện phép toán đường cong bezier cơ bản: https://github.com/sporritt/jsBezier. pointOnCurve (đường cong, vị trí) trông giống như những gì bạn đang yêu cầu.

+0

Điều đó cho điểm P dọc theo đường cong, nhưng không phải cách dịch ngược lại thành vị trí cuối cùng cho đối tượng đang được di chuyển. (Tôi không di chuyển đối tượng dọc theo đường cong) – 1dayitwillmake

-1

Tôi đã thử và tìm kiếm rất nhiều thời gian và biểu mẫu và chắc chắn tôi đã đạt được một cách đơn giản và nhanh chóng. Bí quyết là lấy hàm bezier khối theo dạng này: P (u) = u^3 (c0 + 3c1 -3c2 + c3) + u^2 (3c0 -6c1 + 3c2) + u (-3c0 + 3c1) + c0 trong đó ci là điểm kiểm soát. Phần khác là tìm kiếm y từ x với tìm kiếm nhị phân.

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

}

Các vấn đề liên quan