Перемещение по сетке

Как можно реализовать перемешенные по сетке? Что бы квадрат перемещался строго по сетке и не смог остановиться посередине клеточки

Код

const canvas = document.querySelector("#canvas");
    const ctx = canvas.getContext("2d");

    const gridSettings = {
        squareWidth: 30,
        squareHeight: 30,
    }


    function renderGrid() {
        ctx.beginPath()
        const w = canvas.width
        const h = canvas.height
        const squareWidth = w / gridSettings.squareWidth
        const squareHeight = h / gridSettings.squareHeight
        ctx.strokeStyle = '#bdbdbd'
        ctx.lineWidth = 0.4
        for (let x = squareWidth; x < w; x += squareWidth) ctx.strokeRect(x, 0, 0.1, h)
        for (let y = squareHeight; y < h; y += squareHeight) ctx.strokeRect(0, y, w, 0.1)
        ctx.fill()
        ctx.closePath()
    }

    const drawRect = (offsetX = 0, offsetY = 0) => {
        ctx.fillStyle = "black";
        ctx.clearRect(0, 0, 500, 600)
        ctx.fillRect(offsetX, offsetY, 34, 40)
        renderGrid()
    }

    drawRect(0, 0)

    const rectPos = { x: 0, y: 0 }
    const edge = (c, min, max) => Math.max(min, Math.min(max, c));

    canvas.onmousedown = (e) => {

        const start = { x: e.offsetX, y: e.offsetY };

        canvas.onmousemove = (e) => {
            drawRect(
                edge(rectPos.x + e.offsetX - start.x, 0, 600 - 25),
                edge(rectPos.y + e.offsetY - start.y, 0, 500 - 25)
            );
        }

        canvas.onmouseup = (e) => {
            rectPos.x = edge(rectPos.x + e.offsetX - start.x, 0, 600 - 25);
            rectPos.y = edge(rectPos.y + e.offsetY - start.y, 0, 500 - 25);
            canvas.onmousemove = null
        }
    }
<canvas id="canvas" style="border: 1px solid black;" width=500 height=600></canvas>


Ответы (1 шт):

Автор решения: Vladimir T

Необходимо выровнять координаты по ближайшим координатам сетки (добавил в onmouseup и вынес некоторые переменные в общий доступ):

https://codepen.io/vladimir_nt/pen/pobjYKx

const canvas = document.querySelector("#canvas");
    const ctx = canvas.getContext("2d");
    const gridSettings = {
        squaresHorizontal: 30,
        squaresVertical: 30,
    }
    const w = canvas.width
    const h = canvas.height
    const squareWidth = w / gridSettings.squaresHorizontal
    const squareHeight = h / gridSettings.squaresVertical

    function renderGrid() {
        ctx.beginPath()
        ctx.strokeStyle = '#bdbdbd'
        ctx.lineWidth = 0.4
        for (let x = squareWidth; x < w; x += squareWidth) ctx.strokeRect(x, 0, 0.1, h)
        for (let y = squareHeight; y < h; y += squareHeight) ctx.strokeRect(0, y, w, 0.1)
        ctx.fill()
        ctx.closePath()
    }

    const drawRect = (offsetX = 0, offsetY = 0) => {
        ctx.fillStyle = "black";
        ctx.clearRect(0, 0, 500, 600)
        ctx.fillRect(offsetX, offsetY, 34, 40)
        renderGrid()
    }

    drawRect(0, 0)
    const rectPos = { x: 0, y: 0 }
    const edge = (c, min, max) => Math.max(min, Math.min(max, c));
    canvas.onmousedown = (e) => {
        const start = { x: e.offsetX, y: e.offsetY };
        canvas.onmousemove = (e) => {
            drawRect(
                edge(rectPos.x + e.offsetX - start.x, 0, 500 - 34),
                edge(rectPos.y + e.offsetY - start.y, 0, 600 - 40)
            );
        }
        canvas.onmouseup = (e) => {
            var new_x = squareWidth * Math.round((rectPos.x + e.offsetX - start.x) / squareWidth);
            var new_y = squareHeight * Math.round((rectPos.y + e.offsetY - start.y) / squareHeight);
            rectPos.x = edge(new_x, 0, 500 - 34);
            rectPos.y = edge(new_y, 0, 600 - 40);
            drawRect(
                edge(rectPos.x, 0, 500 - 34),
                edge(rectPos.y, 0, 600 - 40)
            );
            canvas.onmousemove = null
        }
    }

<canvas id="canvas" width="500" height="600" style="border: 1px solid black;"></canvas>
→ Ссылка