Reputation: 142
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
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):
From Chrome (v52 Canary):
No trails (fiddle for test)
Upvotes: 2
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
Reputation: 51876
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