Il semble que la seule façon d'effacer une région d'un canevas est d'utiliser la commande clearRect () - j'ai besoin d'effacer un cercle (je masque des zones d'un canevas rempli, des lumières ponctuelles dans ce cas spécifique) et malgré toutes les tentatives ne semble pas possible.
J'ai essayé de dessiner un cercle avec une valeur alpha de 0 mais simplement rien n'apparaîtrait à moins que l'alpha soit plus élevé (ce qui est contraire au point: P) - je suppose parce qu'un context.fill () le dessine comme un ajout plutôt que comme un remplacement .
Avez-vous des suggestions sur la façon dont je pourrais (rapidement) effacer les cercles à des fins de masque?
Utilisez .arc
Pour créer un trait circulaire, puis utilisez .clip()
pour en faire la zone de découpage actuelle.
Vous pouvez ensuite utiliser .clearRect()
pour effacer tout le canevas, mais seule la zone découpée changera.
Si vous créez un jeu ou quelque chose où la compression de chaque bit de performance est importante, regardez comment j'ai fait cette réponse: Canvas - Remplissez un rectangle dans toutes les zones qui sont entièrement transparentes
Plus précisément, la modification de la réponse qui mène à ceci: http://jsfiddle.net/a2Age/2/
Les énormes avantages ici:
(1) En fait, je m'en suis plaint et resetClip () a été placé dans la spécification officielle à cause de cela, mais il faudra un certain temps avant que les navigateurs ne l'implémentent.
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>
Compte tenu des exigences, ces réponses sont bonnes. Mais disons que vous êtes comme moi et que vous avez des exigences supplémentaires:
Pour la première exigence, la solution consiste à utiliser context.globalCompositeOperation = 'destination-out'
Le bleu est la première forme et le rouge est la deuxième forme. Comme vous pouvez le voir, destination-out
Supprime la section de la première forme.
Voici un exemple de code:
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()
Voici le problème potentiel avec ceci: La deuxième fill()
effacera tout en dessous, y compris l'arrière-plan. Parfois, vous souhaiterez effacer uniquement la première forme, mais vous souhaitez toujours voir les couches qui se trouvent en dessous.
La solution est de dessiner ceci sur un canevas temporaire puis drawImage
pour dessiner le canevas temporaire sur votre canevas principal. Le code ressemblera à ceci:
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
Vous avez quelques options.
Tout d'abord, voici une fonction que nous utiliserons pour remplir un cercle.
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);
};
Voir ceci sur 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();
};
Voir ceci sur jsFiddle .
Les deux ont donné le résultat souhaité à l'écran, mais les performances n'étaient pas suffisantes dans mon cas car je dessinais et effaçais beaucoup de cercles chaque image pour un effet. En fin de compte, j'ai trouvé une manière différente d'obtenir un effet similaire à ce que je voulais en dessinant simplement des lignes plus épaisses sur un arc, mais ce qui précède peut toujours être utile à quelqu'un ayant des exigences de performances différentes.
Où x = position gauche, y = position droite, r = rayon et ctx = votre toile:
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 );
}
}
Utilisez canvas.getContext("2d").arc(...)
pour dessiner un cercle sur la zone avec la couleur d'arrière-plan?
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();