37

キャンバスから領域をクリアする唯一の方法は、clearRect()コマンドを使用することです-円をクリアする必要があります(塗りつぶされたキャンバスから領域をマスクしています、この特定のケースではポイントライト)そしてすべての試みにもかかわらず可能ではないようです。

アルファ値が0の円を描画しようとしましたが、アルファが高くない限り何も表示されません(これはポイント:Pに反します)-contex.fill()はそれを置換ではなく追加として描画するためだと思います。

マスクの目的で(すばやく)円をクリアする方法についての提案はありますか?

4

6 に答える 6

46

を使用.arcして円形のストロークを作成し、 を使用.clip()してそれを現在のクリッピング領域にします。

.clearRect()次に、キャンバス全体を消去するために使用できますが、クリップされた領域のみが変更されます。

于 2012-05-01T11:32:12.967 に答える
16

あなたがゲームやパフォーマンスのすべての部分を圧迫することが重要な何かを作っているなら、私がこの答えをどのように作ったかを見てください:キャンバス - 完全に透明なすべての領域で四角形を塗りつぶします

具体的には、これにつながる回答の編集: http://jsfiddle.net/a2Age/2/

ここでの大きなプラス:

  • パスを使用しない (遅い)
  • クリップ不使用(遅い)
  • 保存/復元の必要はありません (すべての状態をクリアせずにクリッピング領域をリセットする方法がないため(1)、保存/復元も使用する必要があることを意味します)

(1) 私は実際にこれについて不満を述べ、そのために resetClip() が公式仕様に組み込まれましたが、ブラウザーがそれを実装するまでにはしばらく時間がかかります。

コード

var ctx          = document.getElementById('canvas1').getContext('2d'),
    ambientLight = 0.1,
    intensity    = 1,
    radius       = 100,
    amb          = 'rgba(0,0,0,' + (1 - ambientLight) + ')';

addLight(ctx, intensity, amb, 200, 200, 0, 200, 200, radius); // First circle
addLight(ctx, intensity, amb, 250, 270, 0, 250, 270, radius); // Second circle
addLight(ctx, intensity, amb, 50, 370, 0, 50, 370, radius, 50); // Third!

ctx.fillStyle = amb;
ctx.globalCompositeOperation = 'xor';
ctx.fillRect(0, 0, 500, 500);

function addLight(ctx, intsy, amb, xStart, yStart, rStart, xEnd, yEnd, rEnd, xOff, yOff) {
  xOff = xOff || 0;
  yOff = yOff || 0;

  var g = ctx.createRadialGradient(xStart, yStart, rStart, xEnd, yEnd, rEnd);
  g.addColorStop(1, 'rgba(0,0,0,' + (1 - intsy) + ')');
  g.addColorStop(0, amb);
  ctx.fillStyle = g;
  ctx.fillRect(xStart - rEnd + xOff, yStart - rEnd + yOff, xEnd + rEnd, yEnd + rEnd);
}
canvas {
  border: 1px solid black;
  background-image: url('http://placekitten.com/500/500');
}
<canvas id="canvas1" width="500" height="500"></canvas>

于 2012-05-01T17:33:53.323 に答える
14

要件を考えると、これらの答えは問題ありません。しかし、あなたが私のようで、追加の要件があるとしましょう。

  1. クリアしているシェイプの境界から部分的に外側にある可能性のあるシェイプの一部を「クリア」したいとします。
  2. 背景をクリアするのではなく、図形の下にある背景を表示する必要があります。

最初の要件の解決策は、context.globalCompositeOperation = 'destination-out' 青が最初の形状で、赤が 2 番目の形状を使用することです。ご覧のとおりdestination-out、最初の形状からセクションを削除します。

ここに画像の説明を入力

コード例を次に示します。

  explosionCanvasCtx.fillStyle = "red"
  drawCircle(explosionCanvasCtx, projectile.radius, projectile.radius, projectile.radius)
  explosionCanvasCtx.fill()

  explosionCanvasCtx.globalCompositeOperation = 'destination-out' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
  drawCircle(explosionCanvasCtx, projectile.radius + 20, projectile.radius, projectile.radius)
  explosionCanvasCtx.fill()

これに関する潜在fill()的な問題は次のとおりです。場合によっては、最初のシェイプのみをクリアしたいが、その下にあるレイヤーを表示したい場合があります。

その解決策は、これを一時的なキャンバスdrawImageに描画してから、一時的なキャンバスをメインのキャンバスに描画することです。コードは次のようになります。

  diameter = projectile.radius * 2
  console.log "<canvas width='" + diameter + "' height='" + diameter + "'></canvas>"
  explosionCanvas = $("<canvas width='" + diameter + "' height='" + diameter + "'></canvas>")
  explosionCanvasCtx = explosionCanvas[0].getContext("2d")

  explosionCanvasCtx.fillStyle = "red"
  drawCircle(explosionCanvasCtx, projectile.radius, projectile.radius, projectile.radius)
  explosionCanvasCtx.fill()

  explosionCanvasCtx.globalCompositeOperation = 'destination-out' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
  durationPercent = (projectile.startDuration - projectile.duration) / projectile.startDuration
  drawCircle(explosionCanvasCtx, projectile.radius + 20, projectile.radius, projectile.radius)
  explosionCanvasCtx.fill()
  explosionCanvasCtx.globalCompositeOperation = 'source-over' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html

  ctx.drawImage(explosionCanvas[0], projectile.pos.x - projectile.radius, projectile.pos.y - projectile.radius) #center
于 2014-05-25T20:35:57.303 に答える
11

いくつかのオプションがあります。

まず、円を塗りつぶすために使用する関数を次に示します。

var fillCircle = function(x, y, radius)
{
    context.beginPath();
    context.arc(x, y, radius, 0, 2 * Math.PI, false);
    context.fill();
};

clip()

var clearCircle = function(x, y, radius)
{
    context.beginPath();
    context.arc(x, y, radius, 0, 2 * Math.PI, false);
    context.clip();
    context.clearRect(x - radius - 1, y - radius - 1,
                      radius * 2 + 2, radius * 2 + 2);
};

jsFiddleでこれを参照してください。


globalCompositeOperation

var clearCircle = function(x, y, radius)
{
    context.save();
    context.globalCompositeOperation = 'destination-out';
    context.beginPath();
    context.arc(x, y, radius, 0, 2 * Math.PI, false);
    context.fill();
    context.restore();
};

jsFiddleでこれを参照してください。


どちらも画面上で目的の結果が得られましたが、効果を得るためにフレームごとに多くの円を描画してクリアしていたため、私の場合はパフォーマンスが十分ではありませんでした。結局、弧に太い線を描くだけで、私が望んでいたものと同様の効果を得る別の方法を見つけましたが、上記は、パフォーマンス要件が異なる人にとっては依然として役立つ可能性があります。

于 2012-10-15T12:27:58.653 に答える
0

canvas.getContext("2d").arc(...)背景色の領域に円を描くために使用しますか?

var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.arc(x, y, r, 0, 2*Math.PI, false);
context.fillStyle = "#FFFFFF";
context.fill();
于 2012-05-01T11:29:11.553 に答える