Anti aliasing edge.
The reason you are getting the ~1px line is because the ctx.fillRect
you use to clear the canvas is transformed by the same transform used to draw the box.
When a shape is rendered its edges are anti-aliased, some of the edge pixels are drawn semi-transparent meaning that drawing over that same box will leave some of the original pixels behind.
To fix
-
Reset the transform to the default before you clear the canvas.
ctx.setTransform(1,0,0,1,0,0);
-
Use a variable to hold the total rotation of the box (see example)
-
Use
setTransform
to replace the current transform rather than build the transform in stages usingctx.translate
andctx.rotate
.Transform basics while help understand how
setTransform
can be used to position, scale, and rotate rendered objects in the 2D canvas API.
Other points
- Use
requestAnimationFrame
rather thansetInterval
to call the animation loop to ensure the smoothest possible animation. - Use a single object to store related data. Eg the object
box
in example holds all relevant data needed to animate the box. - Try to express animations in meaningfully ways. In the example the box rotation rate
box.rotSpeed
is set as rotations per second
Example
requestAnimationFrame(mainLoop);
const ctx = canvas.getContext("2d")
canvas.height = canvas.width = 300;
canvas.style.backgroundColor = "#303030"
const box = {
color: "lime",
cx: 0.25, // x rotation center as fraction of box size
cy: 0.25, // y rotation center as fraction of box size
x: 150,
y: 150,
size: (150 * 150 / 2) ** 0.5, // makes diagonal size of box 150
rot: 0,
rotSpeed: 0.5, // in rotations per second
};
function drawBox(box) {
box.rot += box.rotSpeed * Math.PI / 30; // 2*PI/60 is one rotation per second at 60FPS
ctx.fillStyle = box.color;
const xa = Math.cos(box.rot);
const ya = Math.sin(box.rot);
ctx.setTransform(xa, ya, -ya, xa, box.x, box.y);
ctx.fillRect(-box.cx * box.size, -box.cy * box.size, box.size, box.size);
}
function mainLoop() {
ctx.setTransform(1, 0, 0, 1, 0, 0); // set default transform
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBox(box);
requestAnimationFrame(mainLoop);
}
<canvas id="canvas">