2

When you move the unit (blue div) around; I want the rectangle over which the unit hovers to be highlighted, with the middle point of that unit as the indicator if it's hovering over a certain rectangle or not. With highlighted I mean, f.e.: Change the color of that specific rectangle.

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;

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
        for (let boxcount = 0; boxcount < amountOfHorBoxes; boxcount++) {
            ctxB.beginPath();
            ctxB.rect(addHorBox, addVertBox, boxsize, boxsize);
            ctxB.fill();
            ctxB.closePath();
            ctxB.stroke();
            addHorBox+=boxsize;
        }
        addHorBox=0;
        addVertBox+=boxsize;
    }
}
function loop(timestamp){    
    
    //var winw = window.innerWidth; 
    //var winh = window.innerHeight;
    
    // draw once
    if(Grid==false) drawGrid();
   
    requestAnimationFrame(loop);
}
loop();

// Make the UNIT draggable:
dragElement(document.getElementById("unit"));

function dragElement(unit) {
    var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
    unit.onmousedown = dragMouseDown;
  
    function dragMouseDown(e) {
        e = e || window.event;
        e.preventDefault();
        // get the mouse cursor position at startup:
        pos3 = e.clientX;
        pos4 = e.clientY;
        document.onmouseup = closeDragElement;
        // call a function whenever the cursor moves:
        document.onmousemove = elementDrag;
    }
    function elementDrag(e) {
        e = e || window.event;
        e.preventDefault();
        // calculate the new cursor position:
        pos1 = pos3 - e.clientX;
        pos2 = pos4 - e.clientY;
        pos3 = e.clientX;
        pos4 = e.clientY;
        // set the element's new position:
        unit.style.top = (unit.offsetTop - pos2) + "px";
        unit.style.left = (unit.offsetLeft - pos1) + "px";
    }
    function closeDragElement() {
        // stop moving when mouse button is released:
        document.onmouseup = null;
        document.onmousemove = null;
    }
}
#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: 50px;
    height: 50px;
}
<!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="gridbattler.css"/>
    <title>Gridding</title>
</head>
<body>
    <div id="unit"></div>
    <canvas id="board"></canvas></div>
    <script src="gridbattler.js"></script>
</body>
</html>

How can I best do this?

I can make a lot of if-loops to check if the x/y points of the unit are greater and or lesser than the position of a rectangle (which I first would need to create) to check if the middle of the unit hovers over it or not to satisfy the condition of being highlighted. But this seems like a lot of ifs and I'm sure there is a better, simpler way to do this.

  • Is there a reason you're using canvas as opposed to CSS Grid? – Zach Jensz Jun 01 '22 at 13:59
  • @ZachJensz I'm not sure to be honest. I'd like to make a boardgame and everything uses and tells you to use canvas. I'd like to place units on the board, and those in turn will need to do some animations. For the animations it's recommended to use a canvas. But I guess it's better to not use canvas. Or even make the div a canvas element instead. – Justafknquestion Jun 01 '22 at 14:08
  • https://www.youtube.com/watch?v=kBMnD_aElCQ yes it's a minesweeper clone but I think most of the grid stuff will set you up well for a board game with modern javascript/css – Zach Jensz Jun 01 '22 at 14:10
  • You’ll know where the central point of the unit is so you can calculate which rectangle it is in. I can’t see how you would use ifs (I’m assuming your rectangles are in a uniform grid as shown, or is the layout different). – A Haworth Jun 01 '22 at 14:28
  • @AHaworth The rectangles don't have a position value so I'd need to create these myself. Than I will need to check if the central point of the unit is somewhere in the rectangle position with an if loop. I'm currently thinking of doing this, which you might mean. Check centre pos. of unit/boxsize (floor). But the problem lies in what Zach said as well, the canvas and the div are disconnected. – Justafknquestion Jun 01 '22 at 14:36
  • Sorry I don’t understand. If it’s a regular grid then arithmetic will tell you which rectangle it is in. Is it not a regular grid? Actually the rectangles don’t exist do they other than as drawn on a canvas? – A Haworth Jun 01 '22 at 14:40
  • @AHaworth the grid/board itself is just outer lines of rectangles which hold no value. I see where the issue lies at least and I don't think this is really doable, so I'll change my approach. – Justafknquestion Jun 01 '22 at 14:46
  • 1
    When you know where the center of the unit is you can calculate which rectangle it is in, that is you can find its 4 corners. Then you just clear the canvas and redraw the grid and draw a rectangle of highlight color in that place. You don’t have to remember any positions of rectangles explicitly. Arithmetic will also tell you which rectangle has been highlighted, in terms of row and column. – A Haworth Jun 01 '22 at 14:51
  • 1
    maybe this can send you on the right path: https://stackoverflow.com/questions/72247956/how-to-assign-each-block-an-id-to-differentiate-between-blocks-inside-a-canvas-a/72251377#72251377 start with something simple like that, just 'highlight' the object under the mouse then move into more complex problems – Helder Sepulveda Jun 01 '22 at 14:59

1 Answers1

2

Here is one potential way of doing it:

  1. Use new Path2D() objects for drawing the rectangles and store them in a dedicated array to use the object later on
  2. While in the event listener handler for dragging the box, search for all boxes that are on said coordinates using isPointInPath().
  3. For the found box(es?) change the background color to "highlight" for all other items restore the original "normal" background color.

I also think having to iterate all items seems bad performance wise but seem to be the only way for what I found.

Credit to this answer, which helped me:

const board = document.getElementById('board')
const ctxB = board.getContext('2d')
let Grid = false
const boxsize = 64

const amountOfrows = 8
const amountOfHorBoxes = 7
const totalAmountOfBoxes = amountOfrows * amountOfHorBoxes
board.width = boxsize * 7.5
board.height = boxsize * 8
let addHorBox = 0
let addVertBox = 0
let boxes = []

function drawGrid () {
    Grid = true
    // for the amout of rows
    for (let rowcount = 0; rowcount < amountOfrows; rowcount++) {
        for (let boxcount = 0; boxcount < amountOfHorBoxes; boxcount++) {
            let box = new Path2D()
            box.rect(addHorBox, addVertBox, boxsize, boxsize)
            ctxB.stroke(box)
            boxes.push(box)
            addHorBox += boxsize
        }
        addHorBox = 0
        addVertBox += boxsize
    }
}

function loop (timestamp) {

    // draw once
    if (Grid == false) drawGrid()

    requestAnimationFrame(loop)
}

loop()

// Make the UNIT draggable:
dragElement(document.getElementById('unit'))

function dragElement (unit) {
    let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0
    unit.onmousedown = dragMouseDown

    function dragMouseDown (e) {
        e = e || window.event
        e.preventDefault()
        // get the mouse cursor position at startup:
        pos3 = e.clientX
        pos4 = e.clientY
        document.onmouseup = closeDragElement
        // call a function whenever the cursor moves:
        document.onmousemove = elementDrag
    }

    function elementDrag (evt) {
    
        const rect = board.getBoundingClientRect()
        const x = evt.clientX - rect.left
        const y = evt.clientY - rect.top
  
        // set the element's new position:
        unit.style.top = (y) + 'px'
        unit.style.left = (x) + 'px'

        for (let box of boxes) {
            if (ctxB.isPointInPath(box, x, y)) {
                ctxB.fillStyle = 'green'
                ctxB.fill(box)
                ctxB.stroke(box)
            } else {
                ctxB.fillStyle = '#999'
                ctxB.fill(box)
                ctxB.stroke(box)
            }
        }
    }

    function closeDragElement () {
        // stop moving when mouse button is released:
        document.onmouseup = null
        document.onmousemove = null
    }
}
#board {
  background-color: #999;
}

#unit {
  background-color: rgb(134, 162, 224);
  position: absolute;
  cursor: pointer;
  z-index: 1;
  width: 50px;
  height: 50px;
}
<!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="gridbattler.css" />
  <title>Gridding</title>
</head>

<body>
  <div id="unit"></div>
  <canvas id="board"></canvas></div>
  <script src="gridbattler.js"></script>
</body>

</html>
Nico O
  • 13,762
  • 9
  • 54
  • 69