Quan Vu
Quan Vu

Reputation: 67

How can I make "REAL" infinite grid with canvas?

So i need to create an infite grid and can draw image per tile with mouse click like this page, what is the idea here to make it? https://playgameoflife.com/

i tried the answer in the How can I make infinite grid with canvas? but it just a fake grid with limited wide and high

const init_infgrid = () => {
  canvas_infgrid = $c('canvas');
  canvas_infgrid.width = window.innerWidth;
  canvas_infgrid.height = window.innerHeight;
  c_infgrid = canvas_infgrid.getContext('2d');

  canvas_infgrid.addEventListener("mousedown", e => {
    reset();
    start_infgrid = getPos_Infgrid(e)
  });
  canvas_infgrid.addEventListener("mouseup", reset);
  canvas_infgrid.addEventListener("mouseleave", reset);

  canvas_infgrid.addEventListener("mousemove", e => {
      if (!start_infgrid) return;
      let pos = getPos_Infgrid(e);
      c_infgrid.translate(pos.x - start_infgrid.x, pos.y - start_infgrid.y);
      draw();
      start_infgrid = pos;
  });
  $('#canvasarea').appendChild(canvas_infgrid)
  draw()
}
function draw() {
    let step = 50;
    let left = 0.5 - Math.ceil(canvas_infgrid.width / step) * step;
    let top = 0.5 - Math.ceil(canvas_infgrid.height / step) * step;
    let right = 2 * canvas_infgrid.width;
    let bottom = 2 * canvas_infgrid.height;
    c_infgrid.clearRect(left, top, right - left, bottom - top);
    c_infgrid.beginPath();
    for (let x = left; x < right; x += step) {
        c_infgrid.moveTo(x, top);
        c_infgrid.lineTo(x, bottom);
    }
    for (let y = top; y < bottom; y += step) {
        c_infgrid.moveTo(left, y);
        c_infgrid.lineTo(right, y);
    }
    c_infgrid.strokeStyle = "#888";
    c_infgrid.stroke();
}

// Mouse event handling:
let start_infgrid;
const getPos_Infgrid = (e) => ({
    x: e.clientX - canvas_infgrid.offsetLeft,
    y: e.clientY - canvas_infgrid.offsetTop
});

const reset = () => {
    start_infgrid = null;
    //no want to reset translation
    //c_infgrid.setTransform(1, 0, 0, 1, 0, 0); // reset translation
    draw();
}

Upvotes: 0

Views: 561

Answers (1)

user3297291
user3297291

Reputation: 23372

Here's what you can do:

  • Whenever a drag ends, keep track of the current offset of your grid
  • On click, determine what grid cell was targeted using your offset and mouse coordinate
  • Keep a set of blocks by their grid coordinates. On click, add a block.
  • In every drawing loop, draw all of your blocks.

Note: I copied over the snippet from the previous answer to modify. Credits to trincot.

let canvas = document.querySelector('.field');
let ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

let offset = { x: 0, y: 0 }

const step = 10;
const blocks = [ [ 0, 0 ], [10, 20] ];

function draw() {
    let left = 0.5 - Math.ceil(canvas.width / step) * step;
    let top = 0.5 - Math.ceil(canvas.height / step) * step;
    let right = 2*canvas.width;
    let bottom = 2*canvas.height;
    ctx.clearRect(left, top, right - left, bottom - top);
    ctx.beginPath();
    for (let x = left; x < right; x += step) {
        ctx.moveTo(x, top);
        ctx.lineTo(x, bottom);
    }
    for (let y = top; y < bottom; y += step) {
        ctx.moveTo(left, y);
        ctx.lineTo(right, y);
    }
    ctx.strokeStyle = "#888";
    ctx.stroke();
    
    // Draw blocks
    for (const [ x, y ] of blocks) {
      ctx.fillRect(
        x * step + offset.x,
        y * step + offset.y,
        step,
        step
      );
    }
}


// Mouse event handling:
let start;
const getPos = (e) => ({
    x: e.clientX - canvas.offsetLeft,
    y: e.clientY - canvas.offsetTop 
});

const reset = () => {
    start = null;
    ctx.setTransform(1, 0, 0, 1, 0, 0); // reset translation
    draw();
}

canvas.addEventListener("mousedown", e => {
    reset();
    start = getPos(e)
});

canvas.addEventListener("mouseup", e => {
  let pos = getPos(e);
  
  const t = ctx.getTransform();
  if (t.e === 0 & t.f === 0) {
    const block = [
      Math.floor((pos.x - offset.x) / step),
      Math.floor((pos.y - offset.y) / step)
    ];
    
    blocks.push(block);
  } else {
    offset.x += Math.floor(t.e / step) * step;
    offset.y += Math.floor(t.f / step) * step;
  }
  
  reset();
});
canvas.addEventListener("mouseleave", reset);

canvas.addEventListener("mousemove", e => {
    // Only move the grid when we registered a mousedown event
    if (!start) return;
    let pos = getPos(e);
    // Move coordinate system in the same way as the cursor
    ctx.translate(pos.x - start.x, pos.y - start.y);
    draw();
    start = pos;
});

draw(); // on page load
body, html {
    width: 100%;
    height: 100%;
    margin: 0;
    padding:0;
    overflow:hidden;
}

canvas { background: silver; }
<canvas class="field"></canvas>

Upvotes: 1

Related Questions