When using .rotate() it leaves 1px Lines behind

91WalcNosmirc :

I'm currently learning about the html5 canvas, and I was making a program that rotates a square around the center of the page using the .rotate() function, but it was leaving behind 1px lines from where the square used to be even though I was filling the canvas after every turn and nothing in the code was 1px. so can someone please explain why this is happening and how to stop it from happening

thanks!

const canvas = document.getElementById("canvas")
const ctx = canvas.getContext("2d")

canvas.width = 300;
canvas.height = 300;

//debugger;
/*
canvas.addEventListener("mousedown", mouseDown, false)
canvas.addEventListener("mouseup", mouseUp, false)
canvas.addEventListener("mousemove", mouseMove, false)
*/

ctx.fillStyle = "#303030";
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.translate(150, 150)

let turnSquare = setInterval(() =>{
	ctx.fillStyle = "#303030"
	ctx.fillRect(0, 0, canvas.width, canvas.height)

	ctx.rotate(degree(10))

	ctx.beginPath()
	ctx.fillStyle = "lime"
	ctx.fillRect(0, 0, 100, 100)

}, 1000 / 20)

function degree(input){
	return 2 * Math.PI / 360 * input
}
<canvas id="canvas">

Blindman67 :

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 using ctx.translate and ctx.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 than setInterval 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">

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=12245&siteId=1