0

I know this Q/A may be related but using the solutions there I can't clear my canvas completely.
After I set the globalCompositeOperation of my context, my canvas still had some layer after calling clearRect().

The canvas.width = canvas.width solution will do the trick, but there says it is not supported in all browsers and also a bad practice.

How do we properly clear a canvas after globalComposite operation?

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const img = new Image();
const reader = new FileReader();
const filterRed = document.getElementById("red");
const addText = document.getElementById("addText");
const upload = document.getElementById("upload");

upload.addEventListener("change", function(evnt) {
  const file = evnt.target.files[0];
  reader.onload = function(e) {
    img.src = e.target.result;
    img.onload = function() {
      ctx.drawImage(img, 0, 0, canvas.clientWidth, canvas.height);
    };
  };
  reader.readAsDataURL(file);
});

filterRed.addEventListener("click", function(e) {
  // redraw image again to prevent double clicking
  // behave not normaly
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
  ctx.fillStyle = "red";
  ctx.filter = "contrast(0.6) brightness(100%)";
  ctx.globalCompositeOperation = "multiply";
  ctx.fillRect(0, 0, canvas.width, canvas.height);
});

addText.addEventListener("click", function(e) {
  // redraw all things again
  // but here not behave normaly
  canvas.toBlob(function(blob) {
    img.src = URL.createObjectURL(blob);
    img.onload = function() {
      // using canvas.width = canvas.width solve the problem
      // but it is not the right way
      canvas.width = canvas.width;
      ctx.drawImage(img, 0, 0, canvas.width, canvas.width);
      ctx.font = "50px serif";
      ctx.fillStyle = "#00ff00";
      ctx.fillText("Hello world", 50, 90);
    };
  });
});
<p>
  Upload Image First
</p>
<label for="upload">Click to select file</label>
<input type="file" accept="image/*|video/*" id="upload" hidden>


<canvas id="canvas"></canvas>
<button id="red">
  red
</button>
<button id="addText">
  redraw with text
</button>

Here the reproduction codesandbox

The image should not have a white layer on top of it, the text should be white not the image.

mandaputtra
  • 922
  • 3
  • 18
  • 36

1 Answers1

1

You have to reinitialize your context globalCompositeOperation to its default value: source-over.

Note that you may also need to reset the context transformation matrix to its default, this can be done by using setTransform method and an identity matrix 1, 0, 0, 1, 0, 0.

The only thing that may now block our clearRect from working correctly would be an active clipping rule. So when you use clip() be sure that you always did call ctx.save() before, and then call ctx.restore() afterward to disable the clipping region (or don't use clip at all).

const ctx = canvas.getContext('2d');
draw_btn.onclick = drawStuffs;
simpleclear_btn.onclick = brokenClear;
better_btn.onclick = betterClear;

drawStuffs();

function drawStuffs() {
  ctx.fillStyle = 'rgba(0,34,123, .75)';
  ctx.fillRect(0,0,45,45);
  ctx.globalCompositeOperation = 'source-atop';
  ctx.fillStyle = "red";
  ctx.translate(25, 25);
  ctx.fillRect(0,0,45,45);
}

function brokenClear() {
  ctx.clearRect(0,0,canvas.width,canvas.height);
}
function betterClear() {
 ctx.globalCompositeOperation = 'source-over';
 ctx.setTransform(1,0,0,1,0,0);
 ctx.clearRect(0,0,canvas.width,canvas.height);
}
<button id="draw_btn">draw stuff</button>
<button id="simpleclear_btn">simple clear (broken)</button>
<button id="better_btn">better clear</button>


<canvas id="canvas"></canvas>
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Thanks, a lot so `ctx.clearRect()` arent clear `fillStyle` `globalComposite` in canvas. Will change question title to related of `globalComposite` – mandaputtra May 17 '19 at 08:39