javascriptcanvasgridinfinitedrawimage

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();
}

Solution

  • Here's what you can do:

    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>