Search code examples
javascriptdom-eventsmousedown

Adding 'mousedown' event listener in a grid which will trigger all cells unless 'mouseup' event occurs


I was still working on my Graph Visualizer project and I am unable to figure out how to add mousedown event listener to all the cells. I am trying to draw a wall-like structure. Let me explain when mousedown event occurs that cell will become a wall (I'll add some color) and unless the mouseup event occurs all the cells through where the cursor will pass will also become a wall. I am facing two issues here: I was able to add an event listener to each cell but I am unable to identify which cell was it. Also, I would like to know how to create continuous walls upon mousedown.

Any suggestions or advice is highly appreciated.

var gridCols = 60;
var gridRows = Math.floor(screen.height / 25) - 2;
gridContainer.style.left = (screen.width-25*gridCols)/screen.width * 50+"%";
var matrix = [];
var found = false;


function sleep(ms) 
{
	return new Promise(resolve => setTimeout(resolve, ms));
}

function getCell(row, col)
{
	return document.querySelector(".row:nth-child("+(row+1)+") .gridsquare:nth-child("+(col+1)+")");
}

for(var i=0; i<20; i++) 
{
    matrix[i] = [];
    for(var j=0; j<60; j++) 
        matrix[i][j] = false;
}

function addWall()
{
	console.log('called');
}

function genDivs(rows, cols)
{ 
	var e = document.getElementById("gridContainer");
	for(var r = 0; r < rows; r++)
	{ 
		var row = document.createElement("div"); 
		row.className = "row";
		for(var c = 0; c < cols; c++)
		{ 
			var cell = document.createElement("div"); 
			if(r == 10 && c == 20)
				cell.className = "gridsquare begin";
			else if(r == 10 && c == 40)
				cell.className = "gridsquare end";
		    else
		    	cell.className = "gridsquare"; 
		    row.appendChild(cell); 
		    row.addEventListener("mousedown", addWall)
		} 
		e.appendChild(row); 
	}
}

async function dfs(i, j)
{
	if(found || i >= 20 || j >= 60 || i < 0 || j < 0 || matrix[i][j])
		return;
	if(i == 10 && j == 40)
	{
		found = true;
		return;
	}
	matrix[i][j] = true;
	getCell(i, j).style.background = "magenta";
	await sleep(5);
	await dfs(i+1, j);
	await dfs(i, j+1);
	await dfs(i-1, j);
	await dfs(i, j-1);
}

genDivs(20, gridCols);
//dfs(10, 10);
<!DOCTYPE html>
<html>
<head>
	<style>
		#gridContainer
		{
			outline: 1px solid rgb(175, 216, 248);
			font-size: 0;
			position: absolute;
		}
		.row
		{
			
		}
		.gridsquare
		{
			width: 25px;
			height: 25px;
			box-shadow: 0 1px 0 rgb(175, 216, 248) inset, 1px 0px 0px rgb(175, 216, 248) inset;
			display: inline-block;
		}
		.begin
		{
			background-color: purple;
		}
		.end
		{
			background-color: magenta;
		}
	</style>
</head>
<body>
	<div id="gridContainer"></div>
	<script type="text/javascript" src="HomeScript.js"></script>
</body>
</html>


Solution

  • You can use bind to bind the context.

    row.addEventListener("mousedown", addWall.bind(null, r, c));
    

    Then you can get row and col:

    function addWall(row, cell) {
      console.log("called:" + [row, cell]);
    }
    

    Same time, I think you need to bind method on cell not the row. Coz cell you can get the row and cell id both.

    Updated code:

    function addWallCell(row, cell) {
      console.log("called:" + [row, cell]);
    }
    

    Bind cell:

    // rest of code
    else cell.className = "gridsquare";
    cell.addEventListener("mousedown", addWallCell.bind(null, r, c));
    row.appendChild(cell);
    

    Working sample:

    var gridCols = 60;
    var gridRows = Math.floor(screen.height / 25) - 2;
    gridContainer.style.left =
      ((screen.width - 25 * gridCols) / screen.width) * 50 + "%";
    var matrix = [];
    var found = false;
    
    function sleep(ms) {
      return new Promise((resolve) => setTimeout(resolve, ms));
    }
    
    function getCell(row, col) {
      return document.querySelector(
        ".row:nth-child(" + (row + 1) + ") .gridsquare:nth-child(" + (col + 1) + ")"
      );
    }
    
    for (var i = 0; i < 20; i++) {
      matrix[i] = [];
      for (var j = 0; j < 60; j++) matrix[i][j] = false;
    }
    
    function addWall(row, cell) {
      console.log("called:" + [row, cell]);
    }
    function addWallCell(row, cell) {
      console.log("called:" + [row, cell]);
    }
    
    function genDivs(rows, cols) {
      var e = document.getElementById("gridContainer");
      for (var r = 0; r < rows; r++) {
        var row = document.createElement("div");
        row.className = "row";
        for (var c = 0; c < cols; c++) {
          var cell = document.createElement("div");
          if (r == 10 && c == 20) cell.className = "gridsquare begin";
          else if (r == 10 && c == 40) cell.className = "gridsquare end";
          else cell.className = "gridsquare";
          cell.addEventListener("mousedown", addWallCell.bind(null, r, c));
          row.appendChild(cell);
        //   row.addEventListener("mousedown", addWall.bind(null, r, c));
        }
        e.appendChild(row);
      }
    }
    
    async function dfs(i, j) {
      if (found || i >= 20 || j >= 60 || i < 0 || j < 0 || matrix[i][j]) return;
      if (i == 10 && j == 40) {
        found = true;
        return;
      }
      matrix[i][j] = true;
      getCell(i, j).style.background = "magenta";
      await sleep(5);
      await dfs(i + 1, j);
      await dfs(i, j + 1);
      await dfs(i - 1, j);
      await dfs(i, j - 1);
    }
    
    genDivs(20, gridCols);
    #gridContainer {
      outline: 1px solid rgb(175, 216, 248);
      font-size: 0;
      position: absolute;
    }
    
    .row {}
    
    .gridsquare {
      width: 25px;
      height: 25px;
      box-shadow: 0 1px 0 rgb(175, 216, 248) inset, 1px 0px 0px rgb(175, 216, 248) inset;
      display: inline-block;
    }
    
    .begin {
      background-color: purple;
    }
    
    .end {
      background-color: magenta;
    }
    <div id="gridContainer"></div>