1

I'm developing a game using HTML5 canvas element and native javascript. I have different sprites for game objects. Is it possible to rotate sprites using native javascript?

For example, I have a sprite image like this:

enter image description here

I use Image for this sprite:

var image = new Image(...);

image.src = "...";

After loading I want to rotate this image and save different projections in local variables:

var sprite_left = rotate(image, 0),
    sprite_top = rotate(image, 90),
    sprite_right = rotate(image, 180),
    sprite_right = rotate(image, 270);

The rotate function should look like this:

function rotate(sourceImage, angle){
...
}

Could anybody help me to write the rotate function?

EDIT:

I have decided to share my code, which I used to test my sprites:

    var wait = function (image, completed, count) {
        if (count == null) count = 0;
        if (!image.complete && count < 1000) {
            count++;
            window.setTimeout(function () {
                wait(image, completed, count);
                console.log('waiting...');
            }, 10);
        }
        else {
            completed();
        }
    },

    rotateW = function (image) {
        var canvas = document.createElement("canvas");
        canvas.width = image.width;
        canvas.height = image.height;

        var p = document.createElement("p");
        p.innerText = "W: ";
        p.appendChild(canvas);
        document.body.appendChild(p);

        var context = canvas.getContext("2d");
        context.translate(canvas.width / 2, canvas.height / 2);
        context.rotate(Math.PI);
        context.translate(-canvas.width / 2, -canvas.height / 2);
        context.drawImage(image, 0, 0);

        var newImage = new Image();
        newImage.src = canvas.toDataURL("image/png");
        return newImage;
    },

    rotateE = function (image) {
        var canvas = document.createElement("canvas");
        canvas.width = image.width;
        canvas.height = image.height;

        var p = document.createElement("p");
        p.innerText = "E: ";
        p.appendChild(canvas);
        document.body.appendChild(p);

        var context = canvas.getContext("2d");
        context.drawImage(image, 0, 0);

        var newImage = new Image();
        newImage.src = canvas.toDataURL("image/png");
        return newImage;
    },
    rotateS = function (image, frameCount) {
        var canvas = document.createElement("canvas");
        canvas.width = image.height * frameCount;
        canvas.height = image.width / frameCount;

        var p = document.createElement("p");
        p.innerText = "S: ";
        p.appendChild(canvas);
        document.body.appendChild(p);

        var context = canvas.getContext("2d");
        context.translate(image.height / 2, image.width / (2 * frameCount));
        context.rotate(Math.PI / 2);
        var i = frameCount;
        while (i--> 0) {
            context.drawImage(image, - image.width / 2 , - ( 0.5 + i ) * image.height);
        }
        var newImage = new Image();
        newImage.src = canvas.toDataURL("image/png");
        return newImage;
    },
    rotateN = function (image, frameCount) {
        var canvas = document.createElement("canvas");
        canvas.width = image.height * frameCount;
        canvas.height = image.width / frameCount;

        var p = document.createElement("p");
        p.innerText = "N: ";
        p.appendChild(canvas);
        document.body.appendChild(p);

        var context = canvas.getContext("2d");
        context.translate(image.height / 2, image.width / (2 * frameCount));
        context.rotate( 3 * Math.PI / 2);
        var i = frameCount;
        while (i-- > 0) {
            context.drawImage(image, -image.width / 2, (frameCount - i - 1.5) * image.height);
        }
        var newImage = new Image();
        newImage.src = canvas.toDataURL("image/png");
        return newImage;
    };
/*
        N
        |
   W----O----E
        |
        S
*/
getSprites = function (image, frameCount) {
    var sprite = {
        N: rotateN(image, frameCount),
        S: rotateS(image, frameCount),
        W: rotateW(image, frameCount),
        E: rotateE(image, frameCount)
    };
    return [      
        sprite.W, // left
        sprite.N, // up
        sprite.E, // right
        sprite.S] // down
};

$.sprite = {
    register: function (options) {
        var image = new Image();
        image.src = options.src;

        wait(image, function () {
            var sprites = getSprites(image, options.frameCount);
        });
    }
};

The final result is:

enter image description here

3
  • 2
    Either use CSS or instead of <img>, use a <canvas>. Commented Aug 3, 2013 at 14:24
  • Using of CSS or <canvas> could lead to performance issues :( Commented Aug 3, 2013 at 14:26
  • 1
    How about using a <canvas> to pre-render the different rotations, then storing these in memory using toBlob, converting these blobs to URLs with window.URL.createObjectURL and then swap urls as desired. (see developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement for canvas options) Commented Aug 3, 2013 at 14:29

4 Answers 4

3

the following function will create a new Canvas out of img (which might be an image or a canvas). Give it an angle in radian, or 'N', 'S', 'W' for the corresponding rotation.

function createRotatedImage(img, angle) {
     angle = (angle == 'N') ?  -Math.PI/2 :
             (angle == 'S') ?   Math.PI/2 :
             (angle == 'W') ?   Math.PI   :
              angle ;    
     var newCanvas = document.createElement('canvas');
     newCanvas.width  = img.width  ;
     newCanvas.height = img.height ;
     var newCtx = newCanvas.getContext('2d') ;
     newCtx.save      () ;
     newCtx.translate ( img.width / 2, img.height / 2) ;
     newCtx.rotate  (angle);
     newCtx.drawImage ( img, - img.width / 2, - img.height / 2) ; 
     newCtx.restore   () ;
}
Sign up to request clarification or add additional context in comments.

Comments

2
  1. Use a <canvas> to pre-render the different rotations
  2. Store these in memory using via toBlob, optionally converting these blobs to URLs with window.URL.createObjectURL
  3. Swap URLs as desired.

See this MDN page for canvas options

Comments

2

Absolutely! It's not as simple as rotating the image, though. You need to rotate the context from the canvas, and draw that image on the rotated context, and then restore it.

context.save();
context.rotate(angle);

//DRAW IT!

context.restore();

1 Comment

I think the OP wants each part of the image to be rotated & saved before rendering it on canvas...
1

How about having a function like :

Image.prototype.rotate = function(angle) {
    var c = document.createElement("canvas");
    c.width = this.width;
    c.height = this.height;    
    var ctx = c.getContext("2d");    
    ctx.rotate(angle);
    var imgData = ctx.createImageData(this.width, this.height);
    ctx.putImageData(imgData);
    return new Image(imgData);
}

var img1 = new Image();
var img2 = img1.rotate(90);

Ofcourse it's just a quick sample to give you an idea.

2 Comments

i think you meant ctx.putImageData(this), and only after you retrieve the imageData. But in fact just returning the canvas is ok, since putImage works even faster with a canvas than with an image.
How to perform rotation without showing the img in the dom or rendering it ? I want to get the base64 of the final rotated image only

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.