Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript: Checking Surrounding Table Cells

Im making the game called Dots and Boxes.

There are a bunch of dots on a grid:

enter image description here

<table>
    <tr>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
    </tr>
    <tr>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
    </tr>
</table>

When you click on one side of the box, it turns black:

enter image description hereenter image description here

function addLine(obj) {
            console.log("Called")

            if (obj.style.backgroundColor != "black") {
                obj.style.backgroundColor = "black";
                changeTurn()
            }

Once you click on the fourth side, closing the box, the box turns the color of the player who clicked the fourth side:

enter image description here

Currently, the players have to manually click the box to change its color. However, I would like it to automatically fill the box with the color when all four sides are black around the box.

How can I use a function in Javascript to check if a the line above, below, left, and right of a box is filled in black?

var playerTurn = "Blue";
            changeTurn();
            var number = 0;

            function addLine(obj) {
                console.log("Called")

                if (obj.style.backgroundColor != "black") {
                    obj.style.backgroundColor = "black";
                    changeTurn()
                }
            }
            
            function fillBox(obj) {
                if (playerTurn == "Blue") {
                    obj.style.backgroundColor = "red";
                }
                else if ( playerTurn == "Red") {
                    obj.style.backgroundColor = "blue";
                }
            }

            function changeTurn() {
                if (playerTurn == "Red") {
                    playerTurn = "Blue";
                    document.getElementById('turn').style.color = "blue";

                }
                else if (playerTurn == "Blue") {
                    playerTurn = "Red";
                    document.getElementById('turn').style.color = "red";
                };
                console.log(playerTurn);
                document.getElementById('turn').innerHTML = playerTurn + "'s Turn";
            }
h3 {
    font-family: Arial;
}
table {
    border-collapse: collapse;
}
.vLine {
    width: 10px;
    height: 60px;
}
.box {
    width: 60px;
    height: 60px;
}
.hLine {
    width: 60px;
    height: 10px;
}
.gap {
    width: 10px;
    height: 12px;
    background-color: black;
}
.vLine:hover, .hLine:hover {
    background-color: black;
}
<h3 id="turn"></h3>

<table>
    <tr>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
    </tr>
    <tr>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
    </tr>
    <tr>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
    </tr>
    <tr>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
    </tr>
    <tr>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
    </tr>
    <tr>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
    </tr>
    <tr>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
    </tr>
    <tr>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
    </tr>
    <tr>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
    </tr>
    <tr>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
    </tr>
    <tr>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
    </tr>
    <tr>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
        <td class="box" onclick="fillBox(this)"></td>
        <td class="vLine" onclick="addLine(this)"></td>
    </tr>
    <tr>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
        <td class="hLine" onclick="addLine(this)"></td>
        <td class="gap"></td>
    </tr>
</table>
like image 307
JoshK Avatar asked Jul 01 '15 01:07

JoshK


2 Answers

This is fairly simple, though it requires some good use of DOM traversal.

When you click on a line there are only ever, at most, two possible boxes that could be filled in. For horizontal lines, those are the boxes above and below, which requires jumping rows. For vertical lines, left and right.

For each of these boxes, there are four lines we need to confirm. Again, we have to jump rows for the lines above and below.

I've actually recreated the game, for the most part, because it's a fun one and there's a lot to be learned here. So let's go through the important bits. We'll avoid bad form in this code, like inline handlers and setting styles directly on elements, and we'll let CSS classes act as controls, though a more complete option would be data-attributes.

Let's start with two essential helper functions.

The first is used to turn array-like objects into actually arrays, so we can use Array.prototype methods on them. We chiefly use this on nodeList objects.

function toArray (o) {
  return Array.prototype.slice.call(o);
}

The second utilizes the first, and gives us the position of an element in its parentNode.

function nodeIndex (node) {
  return toArray(node.parentNode.children).indexOf(node);
}

Next, our event handlers. They're fairly similar to each other. When we click on a line, we fill in that line with another helper function, fill, which adds a new class to the line called .filled. We then check the boxes that could be filled. For horizontal lines that's the vertical boxes, above and below; for vertical lines that's the horizontal boxes, left and right. We remove the event listener so lines can only be clicked once.

function addHLine (e) {
  fill(this);
  this.removeEventListener(e.type, addHLine);
  checkVerticalBoxes(this);
  updateGame();
}

function addVLine (e) {
  fill(this);
  this.removeEventListener(e.type, addVLine);
  checkHorizontalBoxes(this);
  updateGame();
}

Now let's look at checkHorizontalBoxes and checkVerticalBoxes. The horizontal boxes are in the same row, indexed +/-1 from our starting line. The vertical boxes are in rows indexed +/-1 from our starting row, and share the same index as the line. We have some if statements, because sometimes a possible row or box will be out-of-bounds.

function checkHorizontalBoxes (line) {
  var left = line.previousElementSibling,
      right = line.nextElementSibling;

  if (left) checkSurroundingLines(left);
  if (right) checkSurroundingLines(right);
}

function checkVerticalBoxes (line) {
  var index = nodeIndex(line),
      up = line.parentNode.previousElementSibling,
      down = line.parentNode.nextElementSibling;

  if (up) checkSurroundingLines(up.children[index]);
  if (down) checkSurroundingLines(down.children[index]);
}

Both those functions call checkSurroundingLines on the potential boxes. This function calls two more functions - checkVerticalLines and checkHorizontalLines. Starting to see the pattern? isFilled is similar to fill, it's a helper function we defined to test if a line has the class .filled.

function checkHorizontalLines (node, idx) {
  var left = node.previousElementSibling,
      right = node.nextElementSibling;

  return isFilled(left) && isFilled(right);
}

function checkVerticalLines (node, idx) {
  var row = node.parentNode,
      up = row.previousElementSibling.children[idx],
      down = row.nextElementSibling.children[idx];

  return isFilled(up) && isFilled(down);
}

If both those return true we fill in our box.


That's a basic run down of the logic for this kind of DOM traversal. There's some extra stuff going on with the actual code, so read all the parts.

Here's the working game:

DEMO

// Player objects

function Player (name, className, scoreBox) {
  this.name = name;
  this.className = className;
  this.scoreBox = scoreBox;
  this.score = 0;
}

// State

var players = [new Player('Blue', 'blue-mark', 'p1'),
            new Player('Red', 'red-mark', 'p2')],
    currentPlayerIdx = 0,
    currentPlayer = players[currentPlayerIdx],
    turnBox = document.getElementById('turn');

// Helpers

function toArray (o) {
  return Array.prototype.slice.call(o);
}

function nodeIndex (node) {
  return toArray(node.parentNode.children).indexOf(node);
}

function fill (el) {
  el.classList.add('filled');
}

function isFilled (el) {
  return el.classList.contains('filled');
}

// Checks

function checkHorizontalLines (node, idx) {
  var left = node.previousElementSibling,
      right = node.nextElementSibling;
  
  return isFilled(left) && isFilled(right);
}

function checkVerticalLines (node, idx) {
  var row = node.parentNode,
      up = row.previousElementSibling.children[idx],
      down = row.nextElementSibling.children[idx];
      
  return isFilled(up) && isFilled(down);
}

function checkSurroundingLines (node) {
  var idx = nodeIndex(node),
      surrounded = checkVerticalLines (node, idx) && checkHorizontalLines(node, idx);
  
  if (surrounded) {
    node.classList.add('marked');
    node.classList.add(currentPlayer.className);
    return true;
  } 
}

function checkHorizontalBoxes (line) {
  var left = line.previousElementSibling,
      right = line.nextElementSibling;
  
  if (left) checkSurroundingLines(left);
  if (right) checkSurroundingLines(right);
}

function checkVerticalBoxes (line) {
  var index = nodeIndex(line),
      up = line.parentNode.previousElementSibling,
      down = line.parentNode.nextElementSibling;
  
  if (up) checkSurroundingLines(up.children[index]);
  if (down) checkSurroundingLines(down.children[index]);
}


// State sets

function setInfo () {
  turnBox.className = currentPlayer.className;
  turnBox.innerHTML = currentPlayer.name + "'s Turn";
  
  players.forEach(function (p) {
    document.getElementById(p.scoreBox).innerHTML = p.score;
  });
}

function getScores() {
  players.forEach(function (p) {
    p.score = document.querySelectorAll('.box.marked.'+p.className).length;
  });
}

function changeTurn () {
  currentPlayerIdx = 1 - currentPlayerIdx;
  currentPlayer = players[currentPlayerIdx];
  
  setInfo();
}

function updateGame() {
  getScores();
  changeTurn();
}

// Events

function addHLine (e) {
  fill(this);
  this.removeEventListener(e.type, addHLine);
  checkVerticalBoxes(this);
  updateGame();
}

function addVLine (e) {
  fill(this);
  this.removeEventListener(e.type, addVLine);
  checkHorizontalBoxes(this);
  updateGame();
}

function assignHandler (sel, ev, fn) {
  var els = document.querySelectorAll(sel);
  toArray(els).forEach(function (el) {
    el.addEventListener(ev, fn);
  });
}

assignHandler('.hLine', 'click', addHLine);
assignHandler('.vLine', 'click', addVLine);


setInfo();
h3 {
  font-family: Arial;
}
table {
  border-collapse: collapse;
}
.vLine {
  width: 10px;
  height: 60px;
}
.box {
  width: 60px;
  height: 60px;
}
.hLine {
  width: 60px;
  height: 10px;
}
.gap {
  width: 10px;
  height: 12px;
  background-color: #333;
}
.vLine:not(.filled):hover,
.hLine:not(.filled):hover {
  background-color: #333;
}

.filled {
  background-color: grey;
}

.marked {
  background-color: green;
}

.box.blue-mark {
  background-color: #3355ff;
}

.box.red-mark {
  background-color: #ff5533;
}

#turn.blue-mark,
#p1 {
  color: #3355ff;
}

#turn.red-mark,
#p2 {
  color: #ff5533;
}
<h3 id="turn"></h3>
<p class="counts">
  <span id="p1"></span> -
  <span id="p2"></span>
</p>

<table>
  <tr>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
  </tr>
  <tr>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
  </tr>
  <tr>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
  </tr>
  <tr>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
  </tr>
  <tr>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
  </tr>
  <tr>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
  </tr>
  <tr>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
  </tr>
  <tr>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
  </tr>
  <tr>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
  </tr>
  <tr>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
  </tr>
  <tr>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
  </tr>
  <tr>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
    <td class="box"></td>
    <td class="vLine"></td>
  </tr>
  <tr>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
    <td class="hLine"></td>
    <td class="gap"></td>
  </tr>
</table>
like image 111
Oka Avatar answered Oct 09 '22 13:10

Oka


You can use previousElementSibling and nextElementSibling for next and previous elements, and combined with the approach proposed here: Is it possible to get element's numerical index in its parent node without looping?, you can get above and below. Like this:

    var indexPos = Array.prototype.indexOf.call(obj.parentNode.children, obj);
    above = obj.parentNode.previousElementSibling.children[indexPos];
    below = obj.parentNode.nextElementSibling.children[indexPos]
    next = obj.nextElementSibling;
    previous = obj.previousElementSibling;

You can see here, click on a element to turn surrounding elements green.

https://jsfiddle.net/bvc0ta55/

It's not handling error such as if there are missings surrondings, but since your square elements are all surrounded, you shouldn't be faced with the problem.

like image 25
Julien Grégoire Avatar answered Oct 09 '22 13:10

Julien Grégoire