I am trying to rotate an image on HTML canvas by 40, 1 degree at a time as part of a request animation frame loop. However, once ran, the amount the image rotates changes seemingly randomly on every refresh of the page, occasionally working exactly how I want it. Upon debugging, the 'counter' variable appears to be resetting each loop, despite being incremented. I'm at a loss as to what could cause this, new to the language, any help would be appreciated.
let counter = 0; //sets counter to 0
requestAnimationFrame(spin) //initialises the loop
function spin(){
rc.clearRect(0,0,window.innerWidth, window.innerHeight)
rc.save();
rc.translate(frameWidth/2, frameHeight/2); //translates canvas for rotation (rc is canvas context)
const angle = -1; //angle to rotate by each loop
rc.rotate(radCalc(angle)); //actual rotation (function is angle * PI/180)
counter++ //Counter should keep track of each loop, yet resets every time?
rc.translate(-frameWidth/2, -frameHeight/2) //restore canvas
rc.drawImage(dialSpinImage, column * frameWidth, row *frameHeight, frameWidth, frameHeight, 0, 0, frameWidth, frameHeight ) //draw image
rc.restore
let stop = requestAnimationFrame(spin); //get animation frame ID
if (counter < 40){ //checks canvas has not rotated over 40 degrees
requestAnimationFrame(spin)
}
else { //if it has, stop the loop
cancelAnimationFrame(stop)
}
}
}
There are a couple of smaller errors in your code. Let's get through all of 'em:
Inside the function spin()
is the following line:
const angle = -1;
This ultimately resets angle to -1 with every invocation of spin(). The variable needs to be defined outside the scope of the function and just decremented inside.
let stop = requestAnimationFrame(spin); //get animation frame ID
if (counter < 40){ //checks canvas has not rotated over 40 degrees
requestAnimationFrame(spin)
}
This doesn't work like you might expect. The first line doesn't just return a frame ID you might eventually use - no - it calls the requested function spin() right away. Like the angle variable it needs to be defined once outside the function.
With all of the above in mind, here's a working example of your code:
let canvas = document.getElementById("canvas");
let rc = canvas.getContext("2d");
let dialSpinImage = new Image();
let frameWidth = canvas.width;
let frameHeight = canvas.height;
let angle = 0;
let reqAnim;
let counter = 0;
dialSpinImage.onload = function() {
start();
}
dialSpinImage.src = "https://picsum.photos/id/237/60/60";
function start() {
reqAnim = requestAnimationFrame(spin);
}
function spin() {
rc.clearRect(0, 0, frameWidth, frameHeight);
rc.save();
rc.translate(frameWidth / 2, frameHeight / 2); //translates canvas for rotation (rc is canvas context)
angle -= 1;
rc.rotate(angle * Math.PI / 180);
counter++;
rc.translate(-frameWidth / 2, -frameHeight / 2) //restore canvas
rc.drawImage(dialSpinImage, 0, 0, frameWidth, frameHeight) //draw image
rc.restore();
if (counter < 40) { //checks canvas has not rotated over 40 degrees
reqAnim = requestAnimationFrame(spin)
} else { //if it has, stop the loop
cancelAnimationFrame(reqAnim);
}
}
<canvas id="canvas"></canvas>