我可以在 canvas 上突出显示的方块上捕捉这个(蓝色)div 吗?

Can I snap this (blue) div on the highlighted square on the canvas?

当您拖动蓝色 div 时,我希望它在释放鼠标按钮时 'snap' 进入突出显示的绿色方块的中间。我似乎找不到从 box[] (Path2D()) 界面读取坐标的方法。那么有没有一种简单的方法可以实现这一目标?我应该将正方形的坐标保存在 dividually 中吗?或者我还能以某种方式从 Path2D 界面中获取点数吗?

const board = document.getElementById("board");
const ctxB = board.getContext("2d");
var Grid = false;
const boxsize = 64;
const amountOfrows = 8;
const amountOfHorBoxes = 7;
const totalAmountOfBoxes = amountOfrows * amountOfHorBoxes;
board.width = boxsize * 7.5;
board.height = boxsize * 8;
var addHorBox = 0;
var addVertBox = 0;
let boxes = [];

function drawGrid(){
    Grid=true;
    // for the amout of rows
    for (let rowcount = 0; rowcount < amountOfrows; rowcount++) {
        ctxB.lineWidth = 1;
        ctxB.strokeStyle = "black";
        ctxB.fillStyle = "white";
        // filling the rows
        if(rowcount%2==0){
            for (let boxcount = 0; boxcount < amountOfHorBoxes; boxcount++) {
                let box = new Path2D();
                box.rect(addHorBox, addVertBox, boxsize, boxsize);
                boxes.push(box);
                ctxB.fill(box);
                ctxB.stroke(box);
                addHorBox+=boxsize;
            }
        }
        addHorBox=0;
        addVertBox+=boxsize;
    }
}
MoveUnit(document.getElementById("unit"));
function MoveUnit(unit){
    const rect = board.getBoundingClientRect();
    const checkX = unit.clientWidth/2 - rect.left;
    const checkY = unit.clientHeight/2 - rect.top;
    var initialX;
    var initialY;
    var tile;
    unit.onmousedown = mouseDown;
    function mouseDown(e){
        e = e || window.event;
        e.preventDefault();
        initialX = e.clientX;
        initialY = e.clientY;
        document.onmouseup = mouseUp;
        document.onmousemove = moveMouse;
    }
    function moveMouse(e){
        e = e || window.event;
        e.preventDefault();
        unit.style.top = (unit.offsetTop + e.clientY - initialY) + "px";
        unit.style.left = (unit.offsetLeft + e.clientX - initialX) + "px";

        boxes.forEach(box => {
            if (ctxB.isPointInPath(box, unit.offsetLeft + checkX, unit.offsetTop + checkY)) {
                ctxB.lineWidth = 2;
                ctxB.fillStyle = 'green';
                ctxB.fill(box);
                ctxB.stroke(box);
                tile=box;
            }else{
                ctxB.lineWidth = 1;
                ctxB.strokeStyle = "black";
                ctxB.fillStyle = 'white';
                ctxB.fill(box);
                ctxB.stroke(box);
            }
        });
        // saving new mousepos after moving the unit
        initialX = e.clientX;
        initialY = e.clientY;
    }
    function mouseUp(){
        document.onmousemove = false;
        
    }
}
function loop(timestamp){    
    // draw once
    if(Grid==false) drawGrid();
    requestAnimationFrame(loop);
}
loop();
#board{
    background-color: #999;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
#unit{
    background-color: rgb(134, 162, 224);
    position: absolute;
    cursor: pointer;
    z-index: 1;
    width: 30px;
    height: 30px;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="testing.css"/>
    <title>Gridding</title>
</head>
<body>
    <div id="unit"></div>
    <canvas id="board"></canvas></div>
    <script src="testing.js"></script>
</body>
</html>

在那些 Path2D 实例中,我们可以添加一些有用的数据来满足您的需求:

let box = new Path2D();
box.rect(...
box.data = { row, column }

然后在 function mouseUp 我们用它 'snap' 到中间

unit.style.top = ((box.data.column + 0.5) * boxsize) + "px";
unit.style.left = ((box.data.row + 0.5) * boxsize) + "px";

我在下面的示例中减少了很多你的代码,我只关注问题,你在提问时也应该这样做,这有助于其他人更快地切入重点,并让你有更好的机会快速回答。

const board = document.getElementById("board");
const ctxB = board.getContext("2d");
const unit = document.getElementById("unit");

const boxsize = 32;
board.width = board.height = boxsize * 4;

let boxes = [];
for (let r = 0; r < 4; r++) {
  for (let c = 0; c < 4; c++) {
    let box = new Path2D();
    box.rect(r * boxsize, c * boxsize, boxsize -0.5, boxsize -0.5);
    box.data = { r, c }
    boxes.push(box);
  }
}

var position = { x: -1, y: -1 }
function mouseDown(e) {
  document.onmouseup = mouseUp;
  document.onmousemove = moveMouse;
  position = { x: e.clientX, y: e.clientY}
}

function mouseUp() {
  document.onmousemove = false;
  boxes.forEach(box => {
    if (ctxB.isPointInPath(box, position.x, position.y)) {
      unit.style.top = ((box.data.c + 0.5) * boxsize) + "px";
      unit.style.left = ((box.data.r + 0.5) * boxsize) + "px";
    }
  });
}

function moveMouse(e) {
  unit.style.top = (unit.offsetTop + e.clientY - position.y) + "px";
  unit.style.left = (unit.offsetLeft + e.clientX - position.x) + "px";
  position = { x: e.clientX, y: e.clientY}
}

function loop(timestamp) {
  ctxB.clearRect(0, 0, board.width, board.height)
  boxes.forEach(box => {
    ctxB.fillStyle = ctxB.isPointInPath(box, position.x, position.y)? 'green' : 'white'
    ctxB.fill(box);
    ctxB.stroke(box);
  });
  requestAnimationFrame(loop);
}
loop();
unit.onmousedown = mouseDown;
#unit {
  background-color: blue;
  position: absolute;
  width: 20px;
  height: 20px;
}
<canvas id="board"></canvas>
<br>
<div id="unit"></div>

在我的代码中,我将鼠标事件与绘图分开,

  • 我们只在循环上绘制。
  • 事件改变状态变量。

还注意到,在某些情况下,两个框同时突出显示,将矩形的大小更改为 boxsize -0.5