3

キャンバス上でウィジェットを移動したいのですが、さまざまな理由からスプライトを使用したくありません。最新バージョンの Chrome を使用しています。ウィジェットを移動するには、ウィジェットを「描画解除」してから、別の場所に再描画します。「元に戻す」とは、同じ場所に同じ画像を描画することを意味しますが、背景と同じ色で描画するため、新しい画像を描画する前にウィジェットが完全に消えます。問題は、「描画を解除」すると、元の画像の痕跡がキャンバスに残ることです。ここで関連する質問を調べてみましたが、役立つものは何も見つかりませんでした。1 ピクセルの線を描画してアンチエイリアシングを行う問題を理解しているので、線幅を 2 ​​(およびその他のさまざまな非整数値) に設定しましたが、役に立ちませんでした。誰にもアイデアはありますか?ここにフィドルのデモがあります、更新を行う関数は次のとおりです。

function draw(){
    if(previousX !== null) {
        ctx.lineWidth = 1;
        ctx.fillStyle = '#ffffff';
        ctx.strokeStyle = '#ffffff';
        drawCircle(previousX, previousY, 20);
    }

    ctx.lineWidth = 1;
    ctx.fillStyle = '#000000';
    ctx.strokeStyle = '#000000';
    drawCircle(x, y, 20);

        console.log('drew circle (' + x + ', ' + y + ')');

    previousX = x;
    previousY = y;
}

PS私はグラフィックスの経験があまりない単なる愛好家なので、可能であれば答えを少し減らしてください.

4

1 に答える 1

3

アンチエイリアシングを使用してシェイプを描画すると、一部のピクセルはしっかりとカバーされますが、エッジ ピクセルは部分的にしかカバーされません。問題は、ピクセル (LCD パネルを一時的に無視する) が分割できない単位であることです。では、ピクセルを部分的にカバーするにはどうすればよいでしょうか。これは、アルファ チャネルを使用して実現します。

アルファ チャネル (およびアルファ ブレンディング) は、円の端の色とその下の色を組み合わせます。これは、円がピクセルを部分的にしか覆っていない場合に発生します。この問題を視覚化する簡単な図を次に示します。

ここに画像の説明を入力

色の混合は、背景色で円を再度描画しても元に戻されない永久的な変化を引き起こします。理由: 色の混合が再び発生しますが、それは効果を弱めるだけです。

要するに、再描画はピクセルを完全にカバーするだけです。エッジ ピクセルは円の一部ではないため、エッジ効果を隠すことはできません。

円を消す必要がある場合は、むしろ元にあったものを復元するという観点で考えてください。おそらく、元のコンテンツをコピーしてから円を描き、円を移動したい場合は元のコンテンツを復元してプロセスを繰り返すことができます。

この以前の SO の質問は、キャンバス領域のコピーに関するいくつかのアイデアを提供する場合があります。drawImage メソッドを使用します。getImageData メソッドと putImageData メソッドを組み合わせるのが最善の解決策です。これを行う方法を示すために、Fiddle の例を変更しました。次のコードを試すことができます。

var x, y, vx, vy;
var previousX = null, previousY = null;
var data = null;

function draw(){
    ctx.lineWidth = 2.5;
    ctx.fillStyle = '#000000';
    ctx.strokeStyle = '#FF0000';

    drawCircle(x, y, 20);

    previousX = x;
    previousY = y;
}

function drawCircle(x, y, r){
  // Step 3: Replace the stuff that was underneath the previous circle
  if (data != null)
  {
    ctx.putImageData(data, previousX - r-5, previousY - r-5);
  }

  // Step 1: Copy the region in which we intend to draw a circle
  data = ctx.getImageData(x - r-5, y - r-5, 2 * r + 10, 2 * r + 10);

  // Step 2: Draw the circle
  ctx.beginPath();
  ctx.arc(x, y, r, 0, Math.PI*2, true);
  ctx.closePath();
  ctx.stroke();
  ctx.fill();
}
于 2012-12-15T22:28:22.330 に答える