Find which tile was clicked in an isometric, staggered column system

My grid

tileWidth = 64px
tileHeight = 128px

      

(the image itself is 128px, although the actual diamond is 32px high and 64px wide)

enter image description here

As you can see, I have a chess grid system; However, I've spent the last two hours trying to think about a system where I can take the mouse coordinates relative to the canvas and figure out which tile was clicked (obviously in the diamond area).

For example, if I clicked tile 21, 26

- how would I figure it out in the program?

Any pointers to work in the right direction are greatly appreciated. Thank!

+3


source to share


1 answer


If you know the center position of a cell, which of course you are doing from the time they are rendered, you simply normalize the coordinate against the cell to see if it is inside:

var dx = Math.abs(x - cellCenterX),
    dy = Math.abs(y - cellCenterY);

if (dx / (cellWidth * 0.5) + dy / (cellHeight * 0.5) <= 1) { /* is inside */ };

      

Here's the complete demo:



var cw = 64,
    ch = 32,
    cells = [],
    maxH = 10,
    maxV = 5,
    toggle = true,
    
    canvas = document.getElementById("canvas"),
    ctx = canvas.getContext('2d');

// Using a cell object for convenience here:
function Cell(posX, posY, x, y, w, h) {
  this.posX = posX;            // some id....
  this.posY = posY;            // some id....
  this.x = x;                  // cells top position
  this.y = y;
  this.w = w;                  // width and height of cell
  this.h = h;
  this.centerX = x + w * 0.5;  // abs. center of cell
  this.centerY = y + h * 0.5;
}

// draw this cell:
Cell.prototype.render = function(ctx, color) {
  ctx.beginPath();
  ctx.moveTo(this.centerX, this.y);
  ctx.lineTo(this.x + this.w, this.centerY);
  ctx.lineTo(this.centerX, this.y+this.h);
  ctx.lineTo(this.x, this.centerY);
  ctx.closePath();
  ctx.fillStyle = color;
  ctx.fill();
  ctx.strokeStyle = "#000";
  ctx.stroke();
};

// check if x/y is inside this cell
Cell.prototype.isInCell = function(x, y) {

  var dx = Math.abs(x - this.centerX),
      dy = Math.abs(y - this.centerY);

  return (dx / (this.w * 0.5) + dy / (this.h * 0.5) <= 1);
};

// generate cell map
for(var y = 0; y < maxV; y++) {
  var dltX = toggle ? 0 : -cw * 0.5,
      dltY = -ch * 0.5 * y;
  
  toggle = !toggle;
  
  for(var x = 0; x < maxH; x++) {
      var c = new Cell(x, y, x * cw + dltX, y * ch + dltY, cw, ch);
      cells.push(c);
      c.render(ctx, "#9f0"); // green bg
  }
}

// test by clicking in cell
canvas.onclick = function(e) {
  
  var r = canvas.getBoundingClientRect(),
      x = e.clientX - r.left,
      y = e.clientY - r.top,
      i = 0, cell;
  
  for(; cell = cells[i]; i++) {
    if (cell.isInCell(x, y)) {
      cell.render(ctx, "#f00"); // red bg if inside
      out.innerHTML = "Cell pos: (" + cell.posX + "," + cell.posY + ") X: " + cell.x + " Y: " + cell.y;
      break;
    }
  }
};
      

<canvas id=canvas width=500 height=100></canvas><br>
<output id=out></output>
      

Run codeHide result


+7


source







All Articles