8

CSS3トランジションでは、タイミング関数を「cubic-bezier:(0.25、0.3、0.8、1.0)」として指定できます。この文字列では、P0とP3が次のように、曲線に沿ったポイントP1とP2のXYのみを指定しています。常に(0.0、0.0)、および(1.0、1.0)それぞれ。

Appleのサイトによると:x [は]全体の期間の一部として表され、yは全体の変化の一部として表されます

私の質問は、これをjavascriptの従来の1次元T値にどのようにマッピングできるかということです。

-

トランジションを使用したアニメーションに関するAppleドキュメントから
ここに画像の説明を入力してください

4

3 に答える 3

20

webkit-sourceを少し参照すると、次のコードは、CSS3遷移で使用される暗黙の曲線の正しいT値を示します。

ビジュアルデモ(codepen.io)

これが誰かに役立つことを願っています!

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) );
}
于 2012-07-28T03:03:41.583 に答える
1

任意の時間値t[0,1]の[0,1]値を見つけたいですか?3次ベジェ曲線には明確に定義された方程式があります。ウィキペディアのページ: http: //en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves

したがって、(おそらくLaTeX形式の)数式を入力する必要はありません。同じ数式をhttp://local.wasp.uwa.edu.au/~pbourke/geometry/bezier/index2.htmlからコピーして貼り付けました。 。これにはCの実装もあり、簡単に読むと、JavaScriptに簡単に移植できます。

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

彼がそのページでmuと呼んでいるのは、時間変数tです。

編集:計算をしたくない場合は、誰かがすでにjavascriptで小さなユーティリティライブラリを作成して、基本的なベジェ曲線の計算を実行しているように見えます:https ://github.com/sporritt/jsBezier 。pointOnCurve(curve、location)は、まさにあなたが求めているもののように見えます。

于 2012-07-28T00:22:14.640 に答える
0

私は多くの時間とフォームを検索しようとしましたが、間違いなく1つに簡単かつ迅速に到達しました。秘訣は、次の形式で3次ベジェ関数を取得することです。P(u)= u ^ 3(c0 + 3c1 -3c2 + c3)+ u ^ 2(3c0 -6c1 + 3c2)+ u(-3c0 + 3c1)+ c0ここで、ciは制御点です。他の部分は、二分探索でxからyを探索することです。

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

}

于 2014-11-14T01:22:27.000 に答える