キャンバスの描画を取得しようとして、後で同じキャンバスに再描画すると、予期しない動作が発生します。たとえば、 Jsfiddleを参照してください。
ロジックはかなり単純です。
- キャンバス上の画像と、中央への移動が与えられた場合 (説明のために四角形を使用しています)。
- 画像の一部を切り取ります。この例では、「画像」全体を単純にコピーしています。
- おそらく操作を行います。
- クリアした後、同じキャンバスに貼り付けます。ポイントは、幅/高さのある特定のポイントで元の画像のセクションをクリップし、後で変更して貼り付けることです。
var c=document.getElementById("cvs1"),
ctx = c.getContext("2d"),
bufferCvs = document.createElement('canvas'),
bufferCtx = bufferCvs.getContext('2d');
bufferCvs.width = c.width;
bufferCvs.height = c.height;
ctx.translate( c.width/2, c.height/2 );
ctx.fillStyle="#FF0000";
ctx.fillRect( -75, -50 ,150,100);
//Image data experiment
//Set the buffer width / height same size as rectangle
bufferCvs.width = 150;
bufferCvs.height = 100;
//Draw the "image" from the first context to the buffer by clipping the first, and pasting to 0,0 width the same "image" dimensions.
bufferCtx.drawImage( c, -75, -50, 150, 100, 0, 0, 150, 100 );
//clear out old canvas drawing
ctx.save()
ctx.setTransform(1,0,0,1,0,0,1,0,0);
ctx.clearRect(0, 0, c.width, c.height);
ctx.restore();
ctx.drawImage( bufferCvs, -75, -50, 150, 100 );
私はまったく同じ座標/寸法を維持しているので、期待される出力は、最初にキャンバスにあったものになります。ただし、左上隅の一部のみが描画されます (フィドルを参照)。効率上の理由からdrawImage を使用していますが、get/putImageData を使用しても同じ結果が得られました。幅と高さの両方が前述のように定義され、他の奇妙な動作を修正します。
上隅だけではなく、バッファ キャンバスに格納されているすべてのものが描画されるようにするにはどうすればよいでしょうか?
編集:私の質問と、私が信じている行動を支援するために、いくつかの画面を投稿します。
ステップ 1: コンテキスト 1 を中央に移動し、イメージを表す長方形を描画します。
ctx.translate( c.width/2, c.height/2 );
ctx.fillStyle="#FF0000";
ctx.fillRect( -75, -50 ,150,100);
ステップ 2: drawImage を使用して -75、-50 ポイントから「クリップ」し、幅 150、100 を使用して長方形だけを切り取ります。これはキャンバス バッファに描画する必要がありますが、そうではありません。
bufferCvs.width = 150;
bufferCvs.height = 100;
//Draw the "image" from the first context to the buffer by clipping the first at -75, -50 (the start of the image), and pasting to 0,0 width the same "image" dimensions.
bufferCtx.drawImage( c, -75, -50, 150, 100, 0, 0, 150, 100 );
バッファキャンバスは次のようになると思います(そうではありません):
ただし、drawImage を
bufferCtx.drawImage( c, 0, 0, 150, 100, 0, 0, 150, 100 );
バッファに予想される量の空白を取得します(そして、最後の drawImage は問題なくコンテキストに戻ります)
ステップ 3: 最初のコンテキストから古い「イメージ」を消去します。クリアを実行した後にコンテキストの状態を復元するため、これによって翻訳が変更されることはありません。(これは期待どおりに動作します)
ctx.save()
ctx.setTransform(1,0,0,1,0,0,1,0,0);
ctx.clearRect(0, 0, c.width, c.height);
ctx.restore();
ステップ 4: バッファ キャンバスにあるものを取得し、これに戻り始めた元のコンテキストに描画します。
アイデアは、元の領域をより「クリップ」し、古い画像をクリアし、新しいクリップされた領域を元のコンテキストの中央に貼り付けることです。MDN の exampleを見てきましたが、drawImage のクリッピング部分が期待どおりに機能していません。