NickersF
NickersF

Reputation: 371

HTML 5 Canvas - Rotate multiple objects around own origin

I'm trying to create a JavaScript object that has a method which allows a rectangle to rotate around its own origin during a rAF callback.

Things I have done:

When I use the save() and restore() methods to push and pop the saved states within method calls for different objects it either doesn't change anything, or stops the entire animation.

The rotation in my example appears to be applied globally to the canvas (which is how the functionality is specified on MDN). I'm trying to translate around origin around multiple instances. I've spent hours on this.

Is there something going on with the inheritance mechanism in JavaScript that's not resetting my transforms for different instances of the rectangle objects in the code example?

// author: Nicholas Fazzolari

var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var xCenterCanvas = innerWidth/2;
var yCenterCanvas = innerHeight/2;

// custom rectangle object
function RectangleCustom(x, y, w, h, color) {
    this.w = w;
    this.h = h;
    this.x = x;
    this.y = y;
    this.color = color;
    this.radians = (Math.PI/180) * 2; // change the last value to change speed
 
    // draws a rectangle at given coordinates
    this.draw = function() {
        ctx.save();
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.w, this.h);
        ctx.restore();
    }
    
    // rotates the rectangle around it's center relative to a given xy position
    this.rotateRect = function() {
        ctx.save();
        ctx.translate(this.x + this.w * 0.5, this.y + this.h * 0.5);
        ctx.rotate(this.radians);
        ctx.translate(-this.x -this.w * 0.5, -this.y - this.h * 0.5);
        //ctx.restore()
    }
}

// singleton rectangles
var bkgRectangle = new RectangleCustom(0, 0, innerWidth, innerHeight, "#212121");
var redRectangle = new RectangleCustom(xCenterCanvas - 64, yCenterCanvas - 64, 128, 128, "#F44336");

// main animation loop
function mainAnimationLoop() {
    // runs animation and clears the canvas each call
    requestAnimationFrame(mainAnimationLoop);
    ctx.clearRect(0, 0, innerWidth, innerHeight);
    
    bkgRectangle.draw();
    redRectangle.draw();
    redRectangle.rotateRect();
}

mainAnimationLoop();

I have tried rotating multiple rectangles around their own origin at different positions without animation using save() and restore() - which worked.

Additionally, I have tried moving the rotate method inside of the draw method and the results were the same. My rationale was that the rotation would be applied as a function call within draw() - the rationale was clearly wrong.

Any insight towards a solution would be greatly helpful. I have included a link to the pen on codepen to see the concept in motion.

Upvotes: 2

Views: 1308

Answers (1)

enxaneta
enxaneta

Reputation: 33044

Instead of drawing the rects at (this.x, this.y) you may draw them at 0,0 and translate them to (this.x, this.y);

// author: Nicholas Fazzolari

var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var xCenterCanvas = innerWidth/2;
var yCenterCanvas = innerHeight/2;

// custom rectangle object
function RectangleCustom(x, y, w, h, color) {
    this.w = w;
    this.h = h;
    this.x = x;
    this.y = y;
    this.color = color;
    this.radians = (Math.PI/180) * 2; // change the last value to change speed
    this.rotation = 0;
 
    // draws a rectangle at given coordinates
    this.draw = function() {
        this.rotation += this.radians;
        ctx.save();
        ctx.fillStyle = this.color;
        ctx.translate(this.x, this.y);
        ctx.rotate(this.rotation);
        ctx.fillRect(0,0, this.w, this.h);
        ctx.restore();
    }
    
    
    this.update = function() {
         // animation updates
     }
}

// singleton rectangles
var bkgRectangle = new RectangleCustom(0, 0, innerWidth, innerHeight, "#212121");
var redRectangle = new RectangleCustom(xCenterCanvas - 64, yCenterCanvas - 64, 128, 128, "#F44336");

// main animation loop
function mainAnimationLoop() {
    // runs animation and clears the canvas each call
    requestAnimationFrame(mainAnimationLoop);
    ctx.clearRect(0, 0, innerWidth, innerHeight);
    
    bkgRectangle.draw();
    redRectangle.draw();
    
}

mainAnimationLoop();
<canvas></canvas>

Upvotes: 4

Related Questions