I'm creating a canvas based game with an isometric playing board. I use the following transformations to get my square tiles to render on the screen:

'applyViewportTransformation' : function() {
    context.translate(this.settings.camera_x, this.settings.camera_y);
'applyIsometricTilt' : function() {
    context.scale(1, this.settings.tilt_ratio);
    // Rotating the grid around it's center.
    context.translate(this.settings.pixel_grid_width / 2, this.settings.pixel_grid_height / 2);
    context.translate(-this.settings.pixel_grid_width / 2, -this.settings.pixel_grid_height / 2);

My issue is I would now like elements rendered on specific tiles that aren't translated like this. I also need to be able to map mouse clicks to isometrically drawn elements etc.

So as far as I can tell I need a formula to go into the grid and a formula to go out of the grid.

Mathematically I'm lost and also a little stunned the 2d context doesn't have a public way of simply applying these transformations to a set of coordinates.

Help would be much appreciated.

Edit, if anyone wants a peek at the source or would like to suggest some edits you can view the source on github.


1 Answer 1


Fortunately the basics are quite easy, although there are many small bits of trickiness that may confuse anyone.

To convert from a rect to an integer-iso coordinate, use this forumala:

    r = 4;
    d = 50;

    xi = floor(px/d + r*py/d);
    yi = floor(r*py/d - px/d);

The value r controls the how much the tiles are "stretched". 1 gives a perfect square, sqrt(3) gives cells that are two equilateral triangles joined together.

The value d is the length of the horizontal diagonal. In the images below, its the length of the longest diagonal of the cells.

Below are the grids you get with r = 1, r = 2, and r = 4.

r = 1 r = 2 r = 4

  • Note that you must use a proper floor function that works correctly with negative numbers (i.e floor(-1.1) == -2). Many languages truncate results of integer division. (If you always non-negative values for x and y this won't be a problem).
  • (1) You may need to add constant values to xi and yi depending on how you want to map grid coordinates to screen.
  • (2) You may need to flip the sign of xi or yi (or both) depending on how you want to map grid coordinates to screen.

To convert iso to rect, you can use the following:

x = (xi - yi) * d / r;
y = (xi + yi) * d;
  • You must do the inverse of what you did in (1) or (2) on xi and yi first, before applying the above formula.
  • You may get a coordinate that corresponds to a corner, instead of the centre of the cell, so may need to transform x and y further if this is not what you want.

Debug tips:

  • To find problems easily, first apply the function to an image, choose colors based on the coordinates, and render this out to the screen. This will immediately help you see whether you have the right cell-shape.

  • Make it easy to find the hex coordinate of any spot you click (by printing it out). Once you have the image rendered, you can click on it and see what further transformation you need to apply.

  • \$\begingroup\$ Thanks for the guide, I will have a read and see how I go next time I have a look at this problem. I'm also rotating the canvas 45 degrees so I will probably have to account for that too. Is it just me or is it crazy that this isn't built into the canvas API? \$\endgroup\$
    – Sam Becker
    Commented Mar 25, 2013 at 1:42
  • \$\begingroup\$ Thank you for the formula and detailed explanation. Everything worked as you described. \$\endgroup\$
    – Sam Becker
    Commented Apr 28, 2013 at 9:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .