2012-01-02 15 views
3

私は今、何ヶ月もインスピレーションと問題解決の源としてstackoverflow.comを使用してきました。私はこれまで解決策がなくても問題に遭遇したことはありません。なぜなら、私が最初に自分自身を紹介したいと思っていて、関心のある人と私の問題を共有したいからです。<canvas>要素のクリッピング領域をアニメ化する

私は過去数週間、手書きなどの興味深い効果を作成するために、キャンバス要素に特定の図形や線をアニメーション化してみました。
これを達成するために、キャンバス要素の.clip()コマンドを使用して、プレレンダリングされたイメージ(フォーム、ライン...)が待機する領域を隠して徐々に表示する方法を使用します。 私がここに取り組む問題は、キャンバス要素のクリッピング領域を決定する変数と関係しています。これは、アニメーションの値を増やす(ただし減少させない)のには奇妙な問題があるようです。
これは私が知っている非常に奇妙に聞こえるので、ここで私が話しているコードの関連部分です。

$(document).ready(function() { 
    var ctx = $("#canvas")[0].getContext("2d"); 
    ctx.fillStyle = "#a00"; 
    var recW = 200; 

    function animate() { 
     ctx.clearRect(0,0,400,400); 

     ctx.beginPath(); 
     ctx.rect(50,50,recW,100); 
     ctx.clip(); 

     ctx.beginPath(); 
     ctx.arc(250,100,90,0,Math.PI*2,true); 
     ctx.fill(); 

     recW--; 

     if (recW == 150) clearInterval(run); 
    } 
    var run = setInterval(function() { animate(); },60); 
}); 

上記のコードは完全に正常に動作します。 400 * 400キャンバスに矩形を描き、それをクリッピング領域として使用し、その後に円を描画し、それに応じてこの円を切り抜きます。アニメーションインターバルを通して、クリッピング矩形の長さは150のテスト値に減少します。これまでのところ、とても良いです。私の周り全体のアニメーションを有効にした場合、クリッピング矩形のための150の幅で始まる

$(document).ready(function() { 
    var ctx = $("#canvas")[0].getContext("2d"); 
    ctx.fillStyle = "#a00"; 
    var recW = 150; 

    function animate() { 
     ctx.clearRect(0,0,400,400); 

     ctx.beginPath(); 
     ctx.rect(50,50,recW,100); 
     ctx.clip(); 

     ctx.beginPath(); 
     ctx.arc(250,100,90,0,Math.PI*2,true); 
     ctx.fill(); 

     recW++; 

     if (recW == 200) clearInterval(run); 
    } 
    var run = setInterval(function() { animate(); },60); 
}); 

、およびテストまで++ recWでそれを増やす:しかし、ここで最後の時間だらけ私を維持しています部分です値が200の場合、突然アニメーションが機能しなくなります。変数の段階的な増加は問題なく機能しますが、目に見えるクリッピング領域は成長しません。

私はおそらくちょうどここに明らかを見下ろす午前と思われるが、私は単にエラーを見つけるように見えることができず、誰かが正しい方向に私を指すことができれば、私は非常に感謝するだろう;)

感謝多くの場合
Tricon

+1

を開始するには絶好の場所には、オンラインで完全なコードを公開することです。 [jsfiddle](http://jsfiddle.net/)に移動し、コードを実行して、それをよりうまく実行し、それを使って遊ぶことができます – puk

+0

一度それを置くと、あなたのスニペットコード=) – puk

+0

解決策は以下を参照してください。また、コメントに応答するときには、アンパサンド '@'にユーザ名を付けてください。この場合、あなたの回答の一番最初の行は '@ puk'だったはずです。これに対する例外は、質問/回答をした実際の人に返事をしてから、それをする必要がないときです。 – puk

答えて

1

多くの経験がある場合を除き、問題は難しいものです(私はどちらもそうしませんでした)。

シェイプを小さくして大きくすることができない理由は、クリップを一緒に結合していると思われるからです。したがって、クリップが小さくなるにつれて、最小のクリップ領域が必要になるため、すべてが問題なく表示されます。しかし、クリップが大きくなると、元の小さなクリップエリアとANDingしているので、アニメーションがないように見えます。

これを修正するには、クリップの最後にrestore()コールを配置する必要があります。ただし、これを行うには、クリップの先頭にsave()コールが必要です。最後に、クリップが正確にどこにあるかを示す境界ボックスを追加しました。これは塗りつぶしとストロークであるため、別のbeginPathステートメントをクリップ領域外の円を描画しないようにしました。

ここでここでフルjsFiddle code

var canvas = document.getElementById('canvas'); 
var ctx = canvas.getContext('2d'); 

ctx.fillStyle = "#a00"; 
var recW = 150; 

function animate2() { 
    ctx.clearRect(50,50,canvas.width,recW - 1); 

    ctx.save(); 

    ctx.beginPath(); 
    ctx.rect(50, 50, recW, recW); 
    ctx.clip(); 

    ctx.beginPath(); 
    ctx.arc(250,100,90,0,Math.PI*2,true); 
    ctx.fill(); 

    ctx.restore(); 
    ctx.beginPath(); 
    ctx.rect(50 - 1, 50 - 1, recW + 2, recW + 2); 
    ctx.lineWidth = 10; 
    ctx.stroke(); 
    console.log(recW); 
    recW++; 

    if (recW == 300) clearInterval(run); 
} 
var run = setInterval(function() { animate2(); },5); 
+0

クイック返信をお寄せいただきありがとうございます。 – tricon

+0

@tricon私はCanvasに50,000行以上のコードを書いていますが、私はまだ最も単純なものでもGoogleにしなければなりません(私は現在、これらのコードを積極的に使用していないので、コード、save() (つまり、 'ctx.lineWidth'や' ctx.linewidth'や 'ctx.lw'など) – puk

+0

@triconは' clip'に加えて、 'globalCompositeOperation'も本当にクールです。 [ここをクリック](https://developer.mozilla.org/ja/Canvas_tutorial/Compositing) – puk

1

はあなたの問題をanimate a clipping path.する方法についての素敵なガイドですが、クリップが行われた後、あなたはそれを成長させるためにそれを奪うように持っているので、あなたが使用していることですこの効果を出すために州やキャンバスのワイプを保存します。

ここにいくつかのコード例を示します。

<canvas id="slide29Canvas2" width="970px" height="600px"></canvas> 

<script> 
    // Grabs the canvas element we made above 
var ca1=document.getElementById("slide29Canvas1"); 

// Defines the 2d thing, standard for making a canvas 
var c1=ca1.getContext("2d"); 

// Creates an image variable to hold and preload our image (can't do animations on an image unless its fully loaded) 
var img1 = document.createElement('IMG'); 

// Loads image link into the img element we created above 
img1.src = "http://tajvirani.com/wp-content/uploads/2012/03/slide29-bg_1.png"; 

// Creates the first save event, this gives us a base to clear our clipping/mask to since you can't just delete elements. 
c1.save(); 

// Our function for when the image loads 
img1.onload = function() { 

    // First call to our canvas drawing function, the thing that is going to do all the work for us. 
     // You can just call the function but I did it through a timer 
    setTimeout(function() { drawc1r(0); },5); 

     // The function that is doing all the heavy lifting. The reason we are doing a function is because 
     // to make an animation we have to draw the circle (or element) frame by frame, to do this manually would be to time 
     // intensive so we are just going to create a loop to do it. 'i' stands for the radius of our border 
     // so over time our radius is going to get bigger and bigger. 
    function drawc1r(i) { 

     // Creates a save state. Imagine a save state like an array, when you clear one it pops last element in the array off the stack 
     // When you save, it creates an element at the top of the stack. So if we cleared without making new ones, we would end up with nothing on our stage. 
    c1.save(); 

     // This clears everything off the stage, I do this because our image has transparency, and restore() (the thing that pops one off the stack) 
     // Doesn't clear off images, and so if we stick an image on the stage over and over, the transparency will stack on top of each other and 
     // That isn't quite what we want. 
    c1.clearRect(0, 0, ca1.width, ca1.height); 

     // Adds one to the radius making the circle a little bigger with every step 
    i++; 

     // Tells canvas we are going to start creating an item on the stage - it can be a line, a rectangle or any shape you draw, but whatever 
     // after this path will be added to the clip when its called. I can have 3 rectangles drawn and that would make a clip. 
    c1.beginPath(); 

     // Can't make a true circle, so we make an arced line that happens to trace a circle - 'i' is used to define our radius. 
    c1.arc(853, 320, i, 0, 2 * Math.PI, false); 

     // After everything is defined, we make a clip area out of it. 
    c1.clip(); 

     // Now that we have the clip added to it, we are going to add the image to the clip area. 
    c1.drawImage(img1, 0, 0); 

     // This pops one off the stack which gets rid of the clip so we can enlarge it and make it again on the next pass 
    c1.restore(); 

     // Here is the final size of the circle, I want it to grow the circle until it hits 800 so we set a timeout to run this function again 
     // until we get the size we want. The time in milliseconds pretty much defines your framerate for growing the circle. There are other 
     // methods for doing this that give you better frame rates, but I didn't have much luck with them so I'm not going to include them. 
    if(i < 800) { 
     setTimeout(function() { drawc1r(i); },5); 
    } 

} 

関連する問題