2

RaphaelJSを使用して、いくつかのスクリプトを調整して、組み合わせたい2つのアニメーションを作成しました。

  1. まず、座標に破線を描画しますhttp://jsfiddle.net/jbirthler/CvhKx/2/

    var canvas = Raphael('canvas_container', 322, 273);
    var set = canvas.set(canvas.circle(110, 265, 7), canvas.circle(110, 7, 7), canvas.circle(7, 151, 7)).attr({
        stroke: "none",
        fill: "#666" });
    
    var pathstr = "M 109 255 l 0 -245 l -103 141 l 265 0";
    var path = dashline(canvas, pathstr, 4000, {
        stroke: '#828282',
        'stroke-dasharray': "--",
        'stroke-linecap': "butt",
        'stroke-width': 1,
        'fill-opacity': 0 }, 1000);
    
    function dashline(canvas, pathstr, duration, attr) {
    
        var guide_path = canvas.path(pathstr).attr({
            stroke: "none",
            fill: "none"
        });
        var path = canvas.path(guide_path.getSubpath(0, 1)).attr(attr);
        var total_length = guide_path.getTotalLength(guide_path);
        var start_time = new Date().getTime();
        var interval_length = 20;
    
        var interval_id = setInterval(function() {
            var elapsed_time = new Date().getTime() - start_time;
            var this_length = elapsed_time / duration * total_length;
            var subpathstr = guide_path.getSubpath(0, this_length);
            attr.path = subpathstr;
            path.animate(attr, interval_length);
        }, interval_length);
        return path;
    }​;​
    

    そして、座標に到達するときにパスを緩和し、円をアニメーション化しますhttp://jsfiddle.net/jbirthler/KqjHh/1/

    var canvas = Raphael("holder", 322, 273);
    var set = canvas.set(canvas.circle(110, 265, 7),canvas.circle(110, 7, 7), canvas.circle(7, 151, 7)).attr({stroke:"none", fill: "#666"});
    var c = canvas.circle(110, 265, 10).attr({stroke: "#ddd", "stroke-width": 4});
    var fade = function (id) {
        return function () {
            set[id].attr({fill: "#fff", r: 12}).animate({fill: "#77bf00", r: 8}, 500);
        };
    };
    
    var run = animateCirc();
    
    function animateCirc() {
        var easex = ">",
            easey = ">";
        c.stop().animate({
            "0%":  {cy: 265, easing: easey, callback: fade(0)},
            "40%": {cy: 7, easing: easey, callback: fade(1)},
            "60%": {cy: 151, easing: easey, callback: fade(2)},
            "100%": {cy: 151, easing: easey, callback: fade(3)}
        }, 3000).animate({
            "0%":  {cx: 110, easing: easex},
            "40%": {cx: 110, easing: easex},
            "60%": {cx: 7, easing: easex},
            "100%": {cx: 300, easing: easex}
        }, 3000);
        return run;                
    };​
    

破線のパスが座標に到達したら、円をアニメートさせたいと思います。イージングを使用するための破線のパスを取得できれば、それはプラスになりますが、ほとんどの場合、2つを1つに結合することを検討しています。

私は自分のスクリプトを書くよりもJavaScriptを上手に読むことができますが、破線のスクリプトを分解する方法とコードが実行している手順について誰かが洞察を持っているなら、それは私にとって非常に有益です。

スタックオーバーフローに関する私の最初の投稿(そう、時間について)は、私が十分に具体的であることを願っています!

4

2 に答える 2

2

私は自分でラファエルを使用したことはありませんが、解決策として見つけたものは次のとおりです。

最初のアニメーションは 4 (4000 ミリ秒) 秒以内に実行されます。これは、次のブロックで確認できます。

var path = dashline(canvas, pathstr, 4000, {
    stroke: '#828282',
    'stroke-dasharray': "--",
    'stroke-linecap': "butt",
    'stroke-width': 1,
    'fill-opacity': 0
}, 1000);

次のステップは、円をレンダリングするブロックを特定することです。ここでは、実行するのに 3 秒を与えます。これは、最後のパラメーターを 4000 に変更することで解決できます。次に、パーセンテージに注目します。これらには、ミリ秒 (4000) を各アニメーション ポイントのパーセンテージに変換するための変換計算が必要です。

アニメーション ポイントを目で確認しましたが、エンディング コードは次のようになります。

function animateCirc() {
    var easex = ">",
        easey = ">";
    c.stop().animate({
        "0%":  {cy: 265, easing: easey, callback: fade(0)},
        "35%": {cy: 7, easing: easey, callback: fade(1)},
        "60%": {cy: 151, easing: easey, callback: fade(2)},
        "100%": {cy: 151, easing: easey, callback: fade(3)}
    }, 4000).animate({
        "0%":  {cx: 110, easing: easex},
        "35%": {cx: 110, easing: easex},
        "60%": {cx: 7, easing: easex},
        "100%": {cx: 300, easing: easex}
    }, 4000);
    return run;                
};

更新された (ただし 100% 同期されていない) バージョンは、こちら で確認できます。

var canvas = Raphael('canvas_container', 322, 273);
var set = canvas.set(canvas.circle(110, 265, 7), canvas.circle(110, 7, 7), canvas.circle(7, 151, 7)).attr({
    stroke: "none",
    fill: "#666"
});

var c = canvas.circle(110, 265, 10).attr({stroke: "#999", "stroke-width": 0});
var fade = function (id) {
    return function () {
        set[id].attr({fill: "#fff", r: 12}).animate({fill: "#77bf00", r: 8}, 500);
    };
};

var pathstr = "M 109 255 l 0 -245 l -103 141 l 265 0";
var path = dashline(canvas, pathstr, 4000, {
    stroke: '#828282',
    'stroke-dasharray': "--",
    'stroke-linecap': "butt",
    'stroke-width': 1,
    'fill-opacity': 0
}, 1000);

function dashline(canvas, pathstr, duration, attr) {
    var guide_path = canvas.path(pathstr).attr({
        stroke: "none",
        fill: "none"
    });
    var path = canvas.path(guide_path.getSubpath(0, 1)).attr(attr);
    var total_length = guide_path.getTotalLength(guide_path);
    var start_time = new Date().getTime();
    var interval_length = 20;

    var interval_id = setInterval(function() {
        var elapsed_time = new Date().getTime() - start_time;
        var this_length = elapsed_time / duration * total_length;
        var subpathstr = guide_path.getSubpath(0, this_length);
        attr.path = subpathstr;
        path.animate(attr, interval_length);

    }, interval_length);
    return path;
}
var run = animateCirc();

function animateCirc() {
    var easex = ">",
        easey = ">";
    c.stop().animate({
        "0%":  {cy: 265, easing: easey, callback: fade(0)},
        "35%": {cy: 7, easing: easey, callback: fade(1)},
        "60%": {cy: 151, easing: easey, callback: fade(2)},
        "100%": {cy: 151, easing: easey, callback: fade(3)}
    }, 4000).animate({
        "0%":  {cx: 110, easing: easex},
        "35%": {cx: 110, easing: easex},
        "60%": {cx: 7, easing: easex},
        "100%": {cx: 300, easing: easex}
    }, 4000);
    return run;                
};

実際には、Raphael、Easel、Kinetic、または任意のタイプの Canvas/SVG レンダリング ツールを使用できることに注意してください。

お役に立てれば!

于 2012-11-24T14:47:18.190 に答える
1

@ adamRenny の答えは簡潔で、非常に単純な変更です (彼は私を打ち負かしました。彼が提出したとき、私はまだ答えを書いています)。しかし、実際のキューイングは含まれていないようです。アニメーションを完全に同期させるには、タイミングを手動で計算する必要があります。ただし、以下の私の答えはコードを大幅に変更します。望まれる場合と望まれない場合があります。

最初に行うことは、破線のパスを線に分割し (この場合は 3 つの別々の線セグメントに)、​​それらをキューでアニメーション化することです。単一の(結合された)パスをキューに入れることは可能かもしれませんが、私は試していません。

プロセスを容易にするために、円でも使用されるすべてのパス座標を抽出しました。このようにして、すべての要素をループで描画できます。

var canvas = Raphael('canvas_container', 322, 273),
    // here are the coordinates
    points = [ [110,265], [110,7], [7,151], [300,151] ],
    mCircle = canvas.circle(points[0][0],points[0][1],10).attr({stroke: "#999", "stroke-width": 4}),
    path = [],
    circles = [];

// draw the dots and (starting point of) lines
// note the lines are of 0 length so it's invisible, we only mark its starting point
for (var i = 0; i < points.length - 1; i++) {
    circles[i] = canvas.circle(points[i][0],points[i][1],7).attr({stroke: "none", fill: "#666"});
    path[i] = canvas.path('M'+points[i][0]+' '+points[i][1]).attr({
        stroke: '#828282',
        'stroke-dasharray': "--",
        'stroke-linecap': "butt",
        'stroke-width': 1,
        'fill-opacity': 0
    });

ループ回数はpoints.length - 1、最後の座標が移動する円によってのみ使用されるためであることに注意してください。この時点では何も描画しません。

次に、各アニメーション セットを生成するファクトリ関数を作成します。

// function to generate each set of animation
var fn = function(index) {
    var cPath = path[index], cCircle = circles[index],
        x1 = points[index][0], 
        x2 = points[index+1][0], 
        y1 = points[index][1], 
        y2 = points[index+1][1];

    return function(cb) {
        cPath.animate({path:'M'+x1+' '+y1+' L'+x2+' '+y2},500,'easeOut');
        mCircle.animate({cx:x2,cy:y2},500,'easeOut');
        cCircle.attr({fill: "#fff", r: 12}).animate({fill: "#77bf00", r: 8}, 500, cb);
    };
};

 

ここが最も難しい部分です。アニメーション キューの管理。実際には jQuery Deferred のような他のライブラリを使用できます。しかし、何時間も絶望した後、私は独自の (非常に単純な) キュー システムを作成することにしました。

// my custom Queue class
var Queue = function() {
    this.actionCount = 0;
    this.actions = [];

    var self = this;
    self._cb = function() {
        if (++self.actionCount != self.actions.length) self.run();
    };
};
Queue.prototype.run = function() {
    this.actions[this.actionCount](this._cb);
};
Queue.prototype.add = function(fn) {
    this.actions.push(fn);
};

ループでは、生成されたアニメーションの各セットをキューに登録できます。そして、ループが終了した後にキューを実行します

for (var i = 0; i < points.length - 1; i++) {
    circles[i] = canvas.circle(points[i][0],points[i][1],7).attr({stroke: "none", fill: "#666"});
    path[i] = canvas.path(/*...*/);

    queue.add(fn(i));
}
queue.run();

ここにjsFiddleがあります

 

注意事項

  • 破線のパス アニメーションが緩和されます :p
  • アニメーション化するポイントを追加するのは、それらをpoints配列に追加するのと同じくらい簡単で、残りは自動的に行われます - jsFiddle
  • fn関数からアニメーションを微調整できるはずです
  • キュー クラスは非常にシンプルで、チェックは一切行われておらず、本番用にテストされていません。このスレッドに回答するためだけに作成しました。標準予防策が適用されます
  • Raphael は初めてなので、修正を歓迎します
  • 別の関数を作成するファクトリ関数を呼び出すため、ループは JSLint を渡しません。これはループで行うのは悪いことのようです
  • 答える前にjsFiddleを作成するので、ここのコードはjsFiddleよりもコメントされています
于 2012-11-24T15:04:20.850 に答える