Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotate canvas 90 degrees clockwise and update width height

Say we have a canvas:

<canvas id="one" width="100" height="200"></canvas>

And on a button click the canvas gets rotated 90 degrees clockwise (around the center) and the dimensions of the canvas get also updated, so in a sense it looks like this afterwards:

<canvas id="one" width="200" height="100"></canvas>

Note that the id of the canvas is the same.

Imagine simply rotating an image clockwise without it being cropped or being padded.

Any suggestions before I do it the long way of creating a new canvas and rotating and copying pixel by pixel?

UPDATE sample code with suggestion from comments still not working:

function imageRotatecw90(){

    var canvas = document.getElementById("one");
    var context = canvas.getContext("2d");

    var cw=canvas.width;
    var ch=canvas.height;

    var myImageData = context.getImageData(0,0, cw,ch);

    context.save();

    context.translate(cw / 2, ch / 2);
    context.rotate(Math.PI/2);

    context.putImageData(myImageData, 0, 0);

    context.restore();

    canvas.width=ch;
    canvas.height=cw;
}

FiddleJS

like image 261
zaf Avatar asked Dec 27 '22 03:12

zaf


2 Answers

Look at this DEMO.

To achieve the results seen in demo, I made use of canvas.toDataURL to cache the canvas into an image, then reset the canvas to their new dimensions, translate and rotate the context properly and finally draw the cached image back to modified canvas.

That way you easily rotate the canvas without need to redraw everything again. But because anti-aliasing methods used by browser, each time this operation is done you'll notice some blurriness in result. If you don't like this behavior the only solution I could figure out is to draw everything again, what is much more difficult to track.

Here follows the code:

var canvas = document.getElementById("one");
var context = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;

// Sample graphic
context.beginPath();
context.rect(10, 10, 20, 50);
context.fillStyle = 'yellow';
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();

// create button
var button = document.getElementById("rotate");
button.onclick = function () {
    // rotate the canvas 90 degrees each time the button is pressed
    rotate();
}

var myImageData, rotating = false;   

var rotate = function () {
    if (!rotating) {
        rotating = true;            
        // store current data to an image
        myImageData = new Image();
        myImageData.src = canvas.toDataURL();

       myImageData.onload = function () {
            // reset the canvas with new dimensions
            canvas.width = ch;
            canvas.height = cw;
            cw = canvas.width;
            ch = canvas.height;

            context.save();
            // translate and rotate
            context.translate(cw, ch / cw);
            context.rotate(Math.PI / 2);
            // draw the previows image, now rotated
            context.drawImage(myImageData, 0, 0);               
            context.restore();

            // clear the temporary image
            myImageData = null;

            rotating = false;               
        }
    }
}
like image 100
Gustavo Carvalho Avatar answered Feb 01 '23 23:02

Gustavo Carvalho


Rotation

Note it is not possible to rotate a single element.

ctx.save();
ctx.rotate(0.17);

// Clear the current drawings.
ctx.fillRect()

// draw your object
ctx.restore();

Width/height adjustment

The only way I ever found to properly deal with display ratios, screen sizes etc:

canvas.width = 20;// DO NOT USE PIXELS
canvas.height = 40; // AGAIN NO PIXELS

Notice I am intentionally not using canvas.style.width or canvas.style.height. Also for an adjustable canvas don't rely on CSS or media queries to do the transformations, they are a headache because of the pixel ratio differences. JavaScript automatically accounts for those.

Update

You also have to update the width and the height before you draw. Not sure what you are trying to achieve, but I guess this isn't a problem:

Demo here

var canvas = document.getElementById("one");
var context = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;

canvas.width = 200;
canvas.height = 400;

// Sample graphic
context.beginPath();
context.rect(10,10,20,50);
context.fillStyle = 'yellow';
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();


var myImageData = context.getImageData(0, 0, cw, ch);

context.save();

context.translate(cw / 2, ch / 2);
context.putImageData(myImageData, 0, 0);
context.rotate(0.20);
like image 35
flavian Avatar answered Feb 02 '23 01:02

flavian