A long time since this question was asked, but it was not answered. So I'll try to bring a possible solution to it.
I know that you are not working with JavaScript
, but in this case, your question is related to the maths needed to make that calculation, and due that SO provides good JavaScript
snippets, this language is perfect to see the results of the calculations.
Check this snippet, it is a basic tile-grid, and the tiles are selected depending on the mouse coordinates (I'll use this snippet as a base to show you the final calculations):
const floor = Math.floor;
const divs = document.querySelectorAll('.container div');
const tileSize = 40;
const tiles = Array.prototype.reduce.call(divs, (a, t, i) => {
const ai = floor(i / 3);
return ((a[ai] = a[ai] || []), (a[ai][i % 3] = t), a);
}, []);
const unselect = () => divs.forEach(d => d.style.background = '');
const select = (r, c) => tiles[r] && tiles[r][c] && (tiles[r][c].style.background = 'red');
document.addEventListener('mousemove', (e) => {
const row = floor(e.pageY / tileSize);
const col = floor(e.pageX / tileSize);
unselect();
select(row, col);
});
body {
margin: 0;
padding: 0;
}
.container {
border: 1px solid black;
display: flex;
flex-wrap: wrap;
height: 120px;
width: 120px;
}
.container * {
background: white;
border: 1px solid black;
box-sizing: border-box;
height: 40px;
width: 40px;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
Before starting with the calculations, take a look at this post that I wrote some time ago, so you will be able to check all the maths involved in an isometric projection. As you can see, in an isometric projection, taking a
as the width and height of the tiles before projection, the width of the isometric tile is equal to √3 * a
, and the height is equal to a
.
Having said that, first of all, let's try to do the opposite of what you want to: giving an isometric point, let's try to convert it to the real x
and y
coordinates on the screen. Take a look at the next image:

It is possible to assure several things:
- In the isometric coordinates (
Ix
and Iy
), the point a{1, 1}
and the point b{2, 2}
have the same y
position on the screen. So, with equal Ix
and Iy
, the y
coordinates on the screen remain invariable.
Ix
coordinates decrease the y
coordinates and Iy
coordinates increase them.
- The
x
position of the point b{2, 2}
is two times the x
position of the point a{1, 1}
.
Ix
and Iy
coordinates always increase the x
coordinates.
So, with all this information, let's try to create a conversion formula from {Ix, Iy}
to {x, y}
:
x = (Ix + Iy) * √3 / 2
y = (Ix - Iy) / 2
So, taking this formula as a starting point, we can try to calculate the isometric coordinates (Ix
and Iy
) from the x
and a y
coordinates:
x = (Ix + Iy) * √3 / 2
2 * x = (Ix + Iy) * √3
2 * x / √3 = Ix + Iy
Ix = 2 * x / √3 - Iy
And on the other hand:
y = (Ix - Iy) / 2
2 * y = Ix - Iy
Iy = Ix - 2 * y
So, it is possible to say:
Ix = 2 * x / √3 - Iy
Ix = 2 * x / √3 - (Ix - 2 * y)
Ix = 2 * x / √3 - Ix + 2 * y
2 * Ix = 2 * x / √3 + 2 * y
Ix = x / √3 + y
So, let's see these calculations in live using the same base snippet, but this time with the tiles in isometric mode:
In the next snippet, the isometric coordinates are moved 60px
down in the y
coordinates to make the entire graphics visible on the screen, so, it is needed to subtract that amount from the result.
const floor = Math.floor;
const divs = document.querySelectorAll('.container div');
const tileSize = 40;
const tiles = Array.prototype.reduce.call(divs, (a, t, i) => {
const ai = floor(i / 3);
return ((a[ai] = a[ai] || []), (a[ai][i % 3] = t), a);
}, []);
const unselect = () => divs.forEach(d => d.style.background = '');
const select = (r, c) => tiles[r] && tiles[r][c] && (tiles[r][c].style.background = 'red');
document.addEventListener('mousemove', (e) => {
const x = e.pageX;
const y = e.pageY;
const Ix = x / Math.sqrt(3) + y - 60;
const Iy = Ix - 2 * (y - 60);
const row = floor(Ix / tileSize);
const col = floor(Iy / tileSize);
unselect();
select(row, col);
});
body {
margin: 0;
padding: 0;
}
.container {
border: 1px solid black;
display: flex;
flex-wrap: wrap;
height: 120px;
transform: translateY(60px) rotate(-60deg) skewY(30deg) scaleX(.866025);
transform-origin: top left;
width: 120px;
}
.container * {
background: white;
border: 1px solid black;
box-sizing: border-box;
height: 40px;
width: 40px;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>