Löschen kreisförmiger Bereiche aus HTML5 Canvas

Lesezeit: 7 Minuten

Es scheint, dass die einzige Möglichkeit, eine Region von einer Leinwand zu löschen, darin besteht, den Befehl clearRect () zu verwenden – ich muss einen Kreis löschen (ich maskiere Bereiche aus einer gefüllten Leinwand, in diesem speziellen Fall Punktlichter) und trotz aller Versuche es scheint nicht möglich.

Ich habe versucht, einen Kreis mit einem Alpha-Wert von 0 zu zeichnen, aber es würde einfach nichts angezeigt, es sei denn, das Alpha wäre höher (was dem Punkt zuwiderläuft: P) – ich nehme an, weil ein contex.fill() es als Hinzufügen und nicht als Ersetzen zeichnet .

Irgendwelche Vorschläge, wie ich Kreise für Maskenzwecke (schnell) löschen kann?

  • Hier gibt es zwei gute Antworten, aber ich würde gerne einen Screenshot von dem sehen, was Sie erreichen möchten, nur für den Fall, dass es einen leistungsfähigeren und clevereren Weg gibt, dieselbe Aufgabe zu erledigen

    – Simon Sarris

    1. Mai ’12 um 15:49 Uhr

  • Ich habe die Antwort von clip() akzeptiert, aber um Ihre Neugier zu stillen (und vielleicht haben Sie eine bessere Technik!), mache ich Folgendes: Ich rendere 2D-Punktlichter in einen Puffer. Ich rendere diesen Puffer über mein Spiel mit dem Lighten-Stil, er erzielt einen großartigen Effekt! Aber ich wollte auch alles, was nicht beleuchtet ist, auf einen Umgebungswert abdunkeln – das zeichnet nicht mit Lighten, also muss es ein separates Zeichnen sein. Das Rendern eines separaten Umgebungspuffers verdunkelt jedoch die Lichter, was ich nicht wollte, daher möchte ich die beleuchteten Regionen in meinem Umgebungspuffer “ausblenden” 🙂

    – David Burford

    1. Mai ’12 um 17:00 Uhr

  • Danke. Ich habe mit ein paar Informationen geantwortet, die nützlich sein könnten, je nachdem, was Sie tun

    – Simon Sarris

    1. Mai ’12 um 17:34 Uhr

Benutzen .arc um einen kreisförmigen Strich zu erstellen und dann zu verwenden .clip() um dies zum aktuellen Clipping-Bereich zu machen.

Dann können Sie verwenden .clearRect() um die gesamte Leinwand zu löschen, aber nur der beschnittene Bereich ändert sich.

  • alleine hätte ich das nie hinbekommen – danke gute lösung! Auch zum Löschen aller möglichen seltsamen Formen!

    – David Burford

    1. Mai ’12 um 16:56 Uhr

  • Beachten Sie, dass viele mobile Browser nur rechteckige Clipping-Bereiche unterstützen.

    – Viesturs

    24. Februar 14 um 10:17 Uhr

Loschen kreisformiger Bereiche aus HTML5 Canvas
Simon Sarri

Wenn Sie ein Spiel oder etwas machen, bei dem es auf jedes bisschen Leistung ankommt, sehen Sie sich an, wie ich diese Antwort gegeben habe: Canvas – Füllen Sie ein Rechteck in allen Bereichen, die vollständig transparent sind

Insbesondere die Bearbeitung der Antwort, die dazu führt: http://jsfiddle.net/a2Age/2/

Die großen Pluspunkte hier:

  • Keine Nutzung von Wegen (langsam)
  • Keine Verwendung von Clips (langsam)
  • Keine Notwendigkeit zum Speichern/Wiederherstellen (da es keine Möglichkeit gibt, einen Clipping-Bereich zurückzusetzen, ohne den gesamten Status (1) zu löschen, bedeutet dies, dass Sie auch Speichern/Wiederherstellen verwenden müssen)

(1) Ich eigentlich beschwerte sich darüber und resetClip() wurde deshalb in die offizielle Spezifikation aufgenommen, aber es wird eine Weile dauern, bis Browser es implementieren.

Code

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>

  • Hey, da ist ein brillanter Code! Ich wähle dies nicht als meine Antwort aus, da die vorherige Antwort die von mir gestellte Frage direkt beantwortet (und daher für Personen nützlicher ist, die aus anderen Gründen nach demselben suchen), aber Ihr Link kann direkt auf das angewendet werden, was ich wahrscheinlich besser gemacht habe Weg! Ich würde dafür stimmen, aber ich habe anscheinend nicht genug Stack-Repräsentanten xD Also muss mein herzlicher Dank reichen 🙂

    – David Burford

    1. Mai ’12 um 17:48 Uhr

  • Gute Arbeit beim Hinzufügen von resetClip()!

    – ellisbben

    3. Mai 12 um 18:24 Uhr

  • Auch eine riesig Plus dazu ist, dass Sie radiale Farbverläufe machen können!

    – Jared Forsyth

    10. Februar 17 um 17:16 Uhr

1642792327 842 Loschen kreisformiger Bereiche aus HTML5 Canvas
Daniel Kaplan

Angesichts der Anforderungen sind diese Antworten in Ordnung. Aber nehmen wir an, Sie sind wie ich und haben zusätzliche Anforderungen:

  1. Sie möchten einen Teil einer Form “löschen”, der möglicherweise teilweise außerhalb der Grenzen der zu löschenden Form liegt.
  2. Sie möchten den Hintergrund unter der Form sehen, anstatt den Hintergrund zu löschen.

Für die erste Anforderung ist die Lösung zu verwenden context.globalCompositeOperation = 'destination-out' Das Blau ist die erste Form und das Rot ist die zweite Form. Wie du sehen kannst, destination-out entfernt den Abschnitt aus der ersten Form.

Geben Sie hier die Bildbeschreibung ein

Hier ist ein Beispielcode:

  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()

Hier ist das potenzielle Problem dabei: Das zweite fill() wird klar alles darunter, einschließlich des Hintergrunds. Manchmal möchten Sie nur die erste Form löschen, aber die darunter liegenden Ebenen trotzdem sehen wollen.

Die Lösung dafür besteht darin, dies auf eine temporäre Leinwand zu zeichnen und dann drawImage um die temporäre Leinwand auf Ihre Hauptleinwand zu zeichnen. Der Code wird wie folgt aussehen:

  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

1642792327 819 Loschen kreisformiger Bereiche aus HTML5 Canvas
Zeichnete Noakes

Sie haben einige Möglichkeiten.

Zuerst ist hier eine Funktion, die wir verwenden werden, um einen Kreis zu füllen.

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);
};

Sehen Sie dies an 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();
};

Sehen Sie dies an jsFiddle.


Beide lieferten das gewünschte Ergebnis auf dem Bildschirm, aber die Leistung war in meinem Fall nicht ausreichend, da ich für einen Effekt viele Kreise in jedem Frame gezeichnet und gelöscht habe. Am Ende fand ich einen anderen Weg, um einen ähnlichen Effekt wie ich wollte, indem ich einfach dickere Linien auf einem Bogen zeichnete, aber das Obige kann dennoch für jemanden mit anderen Leistungsanforderungen nützlich sein.

Benutzen canvas.getContext("2d").arc(...) einen Kreis über die Fläche mit der Hintergrundfarbe ziehen?

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();

  • Aus Leistungsgründen sollte dies anstelle von Clip gemacht werden, wenn der Hintergrund undurchsichtig ist, aber das ist leider etwas unwahrscheinlich. Dies funktioniert nicht, wenn der Hintergrund überhaupt transparent ist.

    – Simon Sarris

    1. Mai ’12 um 15:47 Uhr

  • Vielen Dank, dass Sie sich die Zeit genommen haben, um zu antworten 🙂 Leider ist der Hintergrund in diesem Fall nicht undurchsichtig und würde daher nicht das Ergebnis liefern, nach dem ich gesucht habe.

    – David Burford

    1. Mai 2012 um 17:07 Uhr

1642792327 871 Loschen kreisformiger Bereiche aus HTML5 Canvas
Alex

Wobei x = linke Position, y = rechte Position, r = Radius und ctx = Ihre Leinwand:

function clearCircle( x , y , r ){
    for( var i = 0 ; i < Math.round( Math.PI * r ) ; i++ ){
        var angle = ( i / Math.round( Math.PI * r )) * 360;
        ctx.clearRect( x , y , Math.sin( angle * ( Math.PI / 180 )) * r , Math.cos( angle * ( Math.PI / 180 )) * r );
    }
}

  • Aus Leistungsgründen sollte dies anstelle von Clip gemacht werden, wenn der Hintergrund undurchsichtig ist, aber das ist leider etwas unwahrscheinlich. Dies funktioniert nicht, wenn der Hintergrund überhaupt transparent ist.

    – Simon Sarris

    1. Mai ’12 um 15:47 Uhr

  • Vielen Dank, dass Sie sich die Zeit genommen haben, um zu antworten 🙂 Leider ist der Hintergrund in diesem Fall nicht undurchsichtig und würde daher nicht das Ergebnis liefern, nach dem ich gesucht habe.

    – David Burford

    1. Mai 2012 um 17:07 Uhr

.

579740cookie-checkLöschen kreisförmiger Bereiche aus HTML5 Canvas

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy