Meta Xenology
Meta Xenology

Reputation: 142

How to undo canvas antialiasing?

I draw some rectangles and then erase and redraw them to simulate movement to the right. However canvas antialiasing makes them leave traces and I don't want to redraw the entire canvas. Here's what I'm talking about

And here is the code for that:

var canvas = document.getElementById("canvas");
canvas.width = 800;
canvas.height = 600;
var context = canvas.getContext("2d");
maxFps = 15;


function loop(x) {
    setTimeout(function() {
        undoRect(x);
        drawRect(x + 30);   
        loop(x + 30);
    }, 1000/maxFps);
};


function undoRect(x) {
    context.clearRect(x, 0, 30, 30);
};


function drawRect(x) {
    context.fillStyle = 'black';
    context.fillRect(x, 0, 30, 30);
};

loop(0);

So far I attempted to clear a bigger rectangle than what I'm drawing but that doesn't seem to work.

Upvotes: 2

Views: 377

Answers (3)

user1693593
user1693593

Reputation:

There is nothing wrong with the code shown. fillRect() and clearRect() does not need offsetting to avoid being anti-aliased.

The problem indicates that there has been applied an offset earlier in the program, or an current issue with the browser(s).

Make sure the transform is reset before running the loop:

ctx.setTransform(1,0,0,1,0,0);   // identity matrix
// start loop

If you still get issues then you should report this as a bug to Chromium/Mozilla, however as shown below, this is not an issue in more recent versions. You could also consider clearing bounding box +1 pixel each direction, optionally, clear whole canvas and redraw.

Here are the screen-recording results (click on image to see 100%) -

From Firefox (v47.0b9):

Firefox

From Chrome (v52 Canary):

Chrome

No trails (fiddle for test)

Upvotes: 2

6502
6502

Reputation: 114481

Unfortunately there is no portable way to turn off anti-aliasing when drawing on canvas. This can create problems for example if you want to draw two semi-transparent polygons that share an edge as boundary pixels will not be handled correctly (there is no way to do antialiasing correctly when working on a per-primitive basis... perfectly correct antialiasing requires full-scene processing in the general case).

However if you only need to draw rectangles then you can get pixel-accurate results by using coordinates that for example are an int + 0.5 when drawing with a pen of size 1px.

When drawing filled rects with fillRect coordinates don't need adjustments:

<!DOCTYPE html>
<html>

<body>
  <canvas id="canvas"></canvas>
  <script>
    var x = 0;
    setInterval(function() {
      var canvas = document.getElementById("canvas");
      var ctx = canvas.getContext("2d");
      ctx.clearRect(x, 0, 30, 30);
      x += 10;
      ctx.fillStyle = "#F00";
      ctx.fillRect(x, 0, 30, 30);
    }, 100);
  </script>
</body>

</html>

Another option is to just use multiple overlapping canvases for animation instead of drawing/erasing on a single canvas (canvas pixels are transparent by default and per-primitive antialiasing on canvas correctly updates transparency on the edges).

Upvotes: 0

Patrick Roberts
Patrick Roberts

Reputation: 51876

Here's why that's happening.

Here's how to fix it:

var canvas = document.getElementById("canvas");
canvas.width = 800;
canvas.height = 600;

var context = canvas.getContext("2d");
maxFps = 15;


function loop(x) {
  setTimeout(function() {
    undoRect(x);
    drawRect(x + 30);
    loop(x + 30);
  }, 1000 / maxFps);
};


function undoRect(x) {
  context.clearRect(x, 0, 30, 30);
};


function drawRect(x) {
  context.fillStyle = 'black';
  context.fillRect(x, 0, 30, 30);
};

loop(0.5); // boop
<canvas id="canvas"></canvas>

Offset your rectangle by 0.5px.

Upvotes: 1

Related Questions