spengos
spengos

Reputation: 133

How to rotate elements in canvas

I have the following code, which is drawing out a repeated pattern of small squares to fill the canvas size(like a background). What I want to do next is slowly rotate the squares(in a continuous loop) but I can't seem to get it working. It just rotates the entire canvas. I've read that I need to do something with context saving and restoring but I don't fully understand how this works. I've commented out the bits I'm not sure about, just so it's working. Edit: Here's a codepen of the below

var mainCanvas = document.getElementById("myCanvas");
var mainContext = mainCanvas.getContext('2d');

var canvasWidth = mainCanvas.width;
var canvasHeight = mainCanvas.height;

var requestAnimationFrame = window.requestAnimationFrame || 
                            window.mozRequestAnimationFrame || 
                            window.webkitRequestAnimationFrame || 
                            window.msRequestAnimationFrame;
var rotate = 1;

var elementWidth = 40;
var elementHeight = 40;
var canvasWidthGrid = canvasWidth / elementWidth;
var canvasHeightGrid = canvasHeight / elementHeight;

function drawShape() {
    mainContext.clearRect(0, 0, canvasWidth, canvasHeight);
    mainContext.fillStyle = "#EEEEEE";
    mainContext.fillRect(0, 0, canvasWidth, canvasHeight);

    mainContext.fillStyle = "#66d";
    mainContext.beginPath();
    //mainContext.save();

    for (var x = 0, i = 0; i < canvasWidthGrid; x+=90, i++) {
        for (var y = 0, j=0; j < canvasHeightGrid; y+=90, j++) {
            //mainContext.rotate( rotate );
            mainContext.fillRect (x, y, 45, 40);
            //mainContext.restore();
        }
    }

    requestAnimationFrame(drawShape);

    rotate++;
}

drawShape();

Upvotes: 0

Views: 114

Answers (1)

markE
markE

Reputation: 105015

You have a couple of issues with your rotation code:

  • The rotation angle in context.rotate is expressed in radians, not degrees.
  • Rotation always takes place around the origin point. The default origin point is [0,0]. That's why your rects are spinning as they are -- with all the rects spinning around the top-left of the canvas.

So, if you want your rects to rotate around their center points you can do this:

  • Set the rotation point to the rects centerpoint with context.translate( rect.centerX, rect.centerY )
  • Rotate by an angle expressed in radians. This code converts 30 degrees into radians: context.rotate(30*Math.PI/180)
  • Drawing the rect is a bit tricky. context.translate causes new drawings to originate at [centerX,centerY] so you must offset the drawing command to pull the drawing from center rect back to the top-left rect: context.fillRect(-45/2,-40/2,45,50)
  • When your done with transformations (translate+rotate) you can reset to the default orientation with context.setTransform(1,0,0,1,0,0)

Here's your code refactored to use these new tips:

var mainCanvas = document.getElementById("myCanvas");
var mainContext = mainCanvas.getContext('2d');

var canvasWidth = mainCanvas.width;
var canvasHeight = mainCanvas.height;

var rotate = 0;

var elementWidth = 40;
var elementHeight = 40;
var canvasWidthGrid = canvasWidth / elementWidth;
var canvasHeightGrid = canvasHeight / elementHeight;

drawShape();


function drawShape() {
    mainContext.clearRect(0, 0, canvasWidth, canvasHeight);
    mainContext.fillStyle = "#EEEEEE";
    mainContext.fillRect(0, 0, canvasWidth, canvasHeight);

    mainContext.fillStyle = "#66d";
    mainContext.beginPath();

    for (var x = 0; x<canvasWidth; x+=90) {
        for (var y = 0; y<canvasHeight; y+=90) {
            // set origin to center rect
            mainContext.translate(x+45/2,y+40/2);
            // rotate
            mainContext.rotate( rotate );
            mainContext.fillRect (-45/2, -40/2, 45, 40);
            // reset
            mainContext.setTransform(1,0,0,1,0,0);
        }
    }

    requestAnimationFrame(drawShape);

    rotate+=Math.PI/90;
}
body{ background-color: ivory; }
canvas{border:1px solid red; margin:0 auto; }
<canvas id="myCanvas" width=360 height=360></canvas>

Upvotes: 1

Related Questions