Move element in a grid layout with arrow keys - javascript

I'm in the process of creating a turn-based game. For the moment I have a 16*16 grid. I have an event listener for all four arrow keys. I have placed a circle in the first grid item.
I want to move circle with arrow key one grid cell at a time.
I can't get my head around how can I do this. I think I should have a variable that will keep track of the circle. But how to move it to another cell on key-down?
const container = document.querySelector(".grid");
const gridNodes = document.querySelectorAll(".grid-item");
const gridArray = Array.from(gridNodes);
let circle = document.createElement("div");
function makeGrid(rows, cols) {
container.style.setProperty("--grid-rows", rows);
container.style.setProperty("--grid-cols", cols);
for (let c = 0; c < rows * cols; c++) {
let cell = document.createElement("div");
container.appendChild(cell).className = "grid-item";
}
}
const keys = {
left: 37,
up: 38,
right: 39,
down: 40
};
makeGrid(16, 16);
circle.style.width = "20px";
circle.style.height = "20px";
circle.style.backgroundColor = "#000";
let firstGridItem = document.querySelector(".grid-item");
firstGridItem.appendChild(circle);
function moveRight(e) {
console.log(gridArray);
}
function handleKey(e) {
switch (e.keyCode) {
case keys.left:
console.log("left ");
break;
case keys.up:
console.log("up ");
break;
case keys.right:
moveRight(e);
break;
case keys.down:
console.log("down ");
break;
}
}
window.addEventListener("keydown", handleKey);
:root {
--grid-cols: 1;
--grid-rows: 1;
}
.container {
display: grid;
grid-template-rows: repeat(var(--grid-rows), 1fr);
grid-template-columns: repeat(var(--grid-cols), 1fr);
}
.grid-item {
padding: 1em;
border: 1px solid #ddd;
text-align: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Turn Base Game</title>
<link rel="stylesheet" href="bundle.css" />
</head>
<body>
<h1 class="text-center text-white">Turn Based Board Game</h1>
<main class="map">
<div class="container grid"></div>
</main>
<script src="bundle.js"></script>
</body>
</html>

Nice problem.
First assigned co-ordinates to each box.
Added class based on the co-ordinates (e.g. grid-item-01, grid-item-02 etc)
Maintained position of current cursor (initially {x: 0, y: 0})
For each key press, handled position object and rendered the circle.
const container = document.querySelector(".grid");
const gridNodes = document.querySelectorAll(".grid-item");
const gridArray = Array.from(gridNodes);
let circle = document.createElement("div");
let position = {x: 0, y: 0};
function makeGrid(rows, cols) {
container.style.setProperty("--grid-rows", rows);
container.style.setProperty("--grid-cols", cols);
let x = 0;
let y = 0;
for (let c = 0; c < rows * cols; c++) {
let cell = document.createElement("div");
y = c%cols;
if (y === (rows - 1)) {
x++;
}
container.appendChild(cell).className = "grid-item grid-item-" + x + '' + y;
}
}
const keys = {
left: 37,
up: 38,
right: 39,
down: 40
};
makeGrid(16, 16);
circle.style.width = "20px";
circle.style.height = "20px";
circle.style.backgroundColor = "#000";
let firstGridItem = document.querySelector(".grid-item");
firstGridItem.appendChild(circle);
function handleKey(e) {
switch (e.keyCode) {
case keys.left:
position.y--;
break;
case keys.up:
position.x--;
break;
case keys.right:
position.y++;
break;
case keys.down:
position.x++;
break;
}
let gridItem = document.querySelector(".grid-item-" + position.x + '' + position.y);
gridItem.appendChild(circle);
}
window.addEventListener("keydown", handleKey);
:root {
--grid-cols: 1;
--grid-rows: 1;
}
.container {
display: grid;
grid-template-rows: repeat(var(--grid-rows), 1fr);
grid-template-columns: repeat(var(--grid-cols), 1fr);
}
.grid-item {
padding: 1em;
border: 1px solid #ddd;
text-align: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Turn Base Game</title>
<link rel="stylesheet" href="bundle.css" />
</head>
<body>
<h1 class="text-center text-white">Turn Based Board Game</h1>
<main class="map">
<div class="container grid"></div>
</main>
<script src="bundle.js"></script>
</body>
</html>

Related

Is there a way to make the cells of a grid fill in the space when the grid's size changes?

I'm making a grid and I'm not sure how to make the cells fill the space between them when the grid size changes.
I have a function that generates a grid and receives size as a parameter.
What should be added to the grid-square class to make the cells fill the entire space?
//get the grid div
const container = document.querySelector("#container");
function changeColor(e) {
const hoverColor = Math.floor(Math.random() * 16777215).toString(16);
e.target.style.backgroundColor = "#" + hoverColor;
}
function createDivs(size) {
//generate grid elements
for (let i = 0; i < size * size; i++) {
const newDiv = document.createElement("div");
newDiv.classList.add("grid-square");
newDiv.addEventListener("mouseover", changeColor);
container.appendChild(newDiv);
}
}
createDivs(2);
* {
box-sizing: border-box;
}
#container {
display: flex;
background-color: rgba(49, 49, 49, 0.281);
width: 50vw;
height: 50vh;
flex-wrap: wrap;
}
.grid-square {
background-color: white;
width: 50%;
aspect-ratio: 1/1;
}
.grid-square:hover {
cursor: pointer;
}
<!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" />
<title>Etch a Sketck</title>
<link rel="stylesheet" href="style.css" />
<script src="script.js" defer></script>
</head>
<body>
<div id="container"></div>
</body>
</html>
So this is the way I did it. I changed from flex box to grid. Grid has a property called grid-template-columns that defines how many columns you have and how wide each one is. The syntax here is grid-template-columns: repeat(n, 1fr) where n is the number of columns you want.
In order to set the column numbers in javascript, I've used a css custom property (also called a css variable) to define the column numbers. To set the custom property itself I've set the element's style attribute to define that property on load.
Have a look below:
//get the grid div
const container = document.querySelector("#container");
function changeColor(e) {
const hoverColor = Math.floor(Math.random() * 16777215).toString(16);
e.target.style.backgroundColor = "#" + hoverColor;
}
function createDivs(size) {
//generate grid elements
for (let i = 0; i < size * size; i++) {
const newDiv = document.createElement("div");
newDiv.classList.add("grid-square");
newDiv.addEventListener("mouseover", changeColor);
container.appendChild(newDiv);
}
// Added this
container.style.cssText="--cols: "+size;
}
createDivs(5);
* {
box-sizing: border-box;
}
#container {
/* added this */
display: grid;
grid-template-columns: repeat(var(--cols), 1fr);
/* end of added css */
background-color: rgba(49, 49, 49, 0.281);
width: 50vw;
height: 50vh;
flex-wrap: wrap;
}
.grid-square {
background-color: white;
aspect-ratio: 1/1;
}
.grid-square:hover {
cursor: pointer;
}
<div id="container"></div>
The solution was to set the width when creating the cells.
//get the grid div
const container = document.querySelector("#container");
function changeColor(e) {
const hoverColor = Math.floor(Math.random() * 16777215).toString(16);
e.target.style.backgroundColor = "#" + hoverColor;
}
function createDivs(size) {
//generate grid elements
for (let i = 0; i < size * size; i++) {
const newDiv = document.createElement("div");
newDiv.classList.add("grid-square");
newDiv.addEventListener("mouseover", changeColor);
//Setting the width
newDiv.style.width = 100 / size + "%";
container.appendChild(newDiv);
}
}
createDivs(6);
* {
box-sizing: border-box;
}
#container {
display: flex;
background-color: rgba(49, 49, 49, 0.281);
width: 50vw;
height: 50vh;
flex-wrap: wrap;
}
.grid-square {
background-color: white;
width: 50%;
aspect-ratio: 1/1;
}
.grid-square:hover {
cursor: pointer;
}
<!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" />
<title>Etch a Sketck</title>
<link rel="stylesheet" href="style.css" />
<script src="script.js" defer></script>
</head>
<body>
<div id="container"></div>
</body>
</html>

Etch a sketch game, js file does not connect

Although I have no errors and the code seems fine the game etc a sketch does not even appear when I open in browser he index1 html, I double checked whether the connection with my js file is the issue. Why it does not appear in browser?
HTML
<!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="styles1.css">
<title>Etch-a-sketch game</title>
</head>
<body>
<div id="buttonDIV"></div>
<div id="container"></div>
</body>
<script src="main1.js" defer></script>
</html>
CSS
:root {
--grid-cols: 1;
--grid-rows: 1;
}
#container {
display: grid;
grid-template-rows: repeat(var(--grid-rows), 1fr);
grid-template-columns: repeat(var(--grid-cols), 1fr);
}
.grid-item {
padding: 1em;
border: 1px solid #ddd;
text-align: center;
}
JavaScript
const container = document.getElementById("container");
function makeGrid(rows, cols) {
while(document.querySelector("button") !== null) {
document.querySelector("button").remove();
}
container.style.setProperty('--grid-rows', rows);
container.style.setProperty('--grid-cols', cols);
container.style.width = "960px";
container.style.overflow = "hidden";
// console.log(container);
// console.log(rows);
// console.log(cols);
for (c = 0; c < (rows * cols); c++) {
let cell = document.createElement("div");
cell.style.minHeight ="0";
cell.style.minWidth = "0";
cell.style.overflow = "hidden";
container.appendChild(cell).className = "grid-item";
cell.addEventListener("mouseover",()=> {
cell.style.backgroundColor = "black";
})// makes thins black
createButton();
};
function createButton() {
const butonDiv = document.querySelector("#buttonDIV");
const resetButton = document.createElement("button");
resetButton.textContent = "reset grid!";
resetButton.style.margin = "20px";
butonDiv.appendChild(resetButton);
resetButton.addEventListener('click',()=>{
document.querySelectorAll(".grid-item".forEach(e => {e.remove()}))
let userGridinput = prompt("Please enter the number of grid squares(Max 100)");
if(userGridinput > 100){
alert("ERROR!Your grid size cannot be bigger han 100!");
return
};
rows = userGridinput;
cols = userGridinput;
makeGrid(rows,cols);
});
};
}
please help me as I have gowned frustrated with this,

How to make the button to clear up the sketch?

I'm doing a project to make an etch-a-sketch every time I hover on the grid. What I'm trying to do is to make a button to clear up all the colors made.
The sketch picture.
I guess what I need to do is to remove the style elements while clicking the button. But I'm just note sure how to link the button with the style elements.
const container = document.querySelector(".container");
// const table = document.createElement('div');
// table.classList.add('grid-square');
// table.textContent = 'hello';
// container.appendChild(table);
function makeTable(rows, cols) {
container.style.setProperty('--grid-rows', rows);
container.style.setProperty('--grid-cols', cols);
for (i = 0; i < (rows * cols); i++){
const cell = document.createElement('div');
// cell.innerText = (i + 1);
container.appendChild(cell).className = "table";
};
};
makeTable(16, 16);
// const container = document.querySelector('.container')
const grids = document.querySelectorAll('.table')
grids.forEach(element => {
element.addEventListener('mouseover', (e) => {
e.target.style.backgroundColor = randomColor();
console.log(e)
})
});
function randomColor() {
var generateColor = '#' + Math.floor(Math.random()*16777215).toString(16);
return generateColor;
}
function resizeGrid() {
sketchSize = prompt("Enter 1 to 100 to resize sketch");
return sketchSize;
}
// const button = document.querySelector('button')
// button.addEventListener('click', (e) => {
// });
:root {
--grid-rows: 1;
--grid-cols: 1;
}
.container {
display: grid;
/* grid-gap: 1em; */
grid-template-rows: repeat(var(--grid-rows), 1fr);
grid-template-columns: repeat(var(--grid-cols), 1fr);
/* border: 1px solid black; */
width: 50%;
size: 960px;
}
.table {
padding: 1em;
border: 1px solid coral;
text-align: center;
/* border: none; */
}
header {
display: flex;
justify-content: center;
margin: 20px;
gap: 10px;
}
<!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">
<title>Etch-A-Sketch</title>
<script src="index.js" defer></script>
<link rel="stylesheet" href="index.css">
</head>
<body>
<header>
<button class="clear-button">Clear</button>
<button class="resize">Resize</button>
</header>
<div class="container"></div>
</body>
</html>
Cheers!!
To answer my own question, I figured how to do it.
const clear = document.querySelector('.clear-button')
clear.addEventListener('click', () => {
grids.forEach(element => {
element.style.backgroundColor = null;
})
})
I was struggling earlier because I'm not sure how to put other elements (e.g. grids) to the new eventListener.

Bind a block to cells in a table

when scrolling a table, the blue block in it does not move along with the cells, can this be somehow fixed?
ignore this text, I just don’t know what else to write -> It looks like your post is mostly code; please add some more details.It looks like your post is mostly code; please add some more details.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
overflow: auto;
width: 75%;
}
td {
border: 1px solid #000;
width: 40px;
height: 20px;
color: #fff;
}
.cell {
background-color: blue;
position: absolute;
z-index: 2;
}
</style>
</head>
<body>
<div class="container"></div>
<script>
function getPosition(el) {
let rect = el.getBoundingClientRect(),
scrollLeft = window.pageYOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop
return {
top: rect.top + scrollTop,
left: rect.left + scrollLeft
}
}
function tableInit(parent, row, cols) {
const table = document.createElement('table')
let counter = 0
for (let i = 0; i < row; i++) {
let tr = document.createElement('tr')
for (let j = 0; j < cols; j++, counter++) {
let td = document.createElement('td')
td.textContent = counter
td.classList.add(counter)
tr.appendChild(td)
}
table.appendChild(tr)
}
parent.appendChild(table)
}
let container = document.querySelector('.container')
tableInit(container, 7, 100)
let table = document.querySelector('table')
let td = document.getElementsByClassName('104')[0]
let cell = document.createElement('div')
cell.classList.add('cell')
cell.setAttribute('style',
`top: ${getPosition(td).top}px;
left: ${getPosition(td).left}px;
height: ${td.clientHeight + 2}px;
width: ${td.clientWidth * 2}px;`)
table.appendChild(cell)
</script>
</body>
</html>
You need to give your table or your container a position, so that your browser knows how it flows in the DOM. Without this, your .cell is absolute to the container not the scrolling children.
Watch out for the second line in tableInit(). That's one possible solution.
function getPosition(el) {
let rect = el.getBoundingClientRect(),
scrollLeft = window.pageYOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop
return {
top: rect.top + scrollTop,
left: rect.left + scrollLeft
}
}
function tableInit(parent, row, cols) {
const table = document.createElement('table')
table.setAttribute('style', `position: relative`) // Give the table a position
let counter = 0
for (let i = 0; i < row; i++) {
let tr = document.createElement('tr')
for (let j = 0; j < cols; j++, counter++) {
let td = document.createElement('td')
td.textContent = counter
td.classList.add(counter)
tr.appendChild(td)
}
table.appendChild(tr)
}
parent.appendChild(table)
}
let container = document.querySelector('.container')
tableInit(container, 7, 100)
let table = document.querySelector('table')
let td = document.getElementsByClassName('104')[0]
let cell = document.createElement('div')
cell.classList.add('cell')
cell.setAttribute('style',
`top: ${getPosition(td).top}px;
left: ${getPosition(td).left}px;
height: ${td.clientHeight + 2}px;
width: ${td.clientWidth * 2}px;`)
table.appendChild(cell)
.container {
overflow: auto;
width: 75%;
}
td {
border: 1px solid #000;
width: 40px;
height: 20px;
color: #fff;
}
.cell {
background-color: blue;
position: absolute;
z-index: 2;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="container"></div>
</body>
</html>
If you want the blue block to stay put in its position alongside the empty blocks, you need to make the container relative.
.container {
position: relative;
}

How to create a dynamic grid with even number of rows and columns?

I am trying to create a grid which takes a user input and uses that as its number of rows and columns. In other words, if the user inputs X, I want the grid to have X rows and X columns, and be square, meaning the boxes are as high as they are wide.
I have gotten it to work with JavaScript and CSS grid, but only if I already know the number of rows/columns, in that case 10. Please see below.
How can I create a grid that does the same but with any number of rows and columns?
#container {
display: grid;
grid-template-columns: repeat(10, 1fr);
width: 500px;
height: 500px;
}
div {
width: 100%;
height: 100%;
outline: 1px solid;
float: left;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<title>Etch-a-sketch</title>
</head>
<body>
<h1>Etch-a-sketch</h1>
<button id="start">Start</button>
<div id="container"></div>
</body>
<script>
let btn = document.getElementById("start")
btn.addEventListener("click", createGrid)
function createGrid() {
let numberOfRows = prompt("How many rows do you want?");
let i = 0;
let x = numberOfRows ** 2;
for (i; i < x; i++) {
var div = document.createElement("div");
document.getElementById("container").appendChild(div);
div.addEventListener("mouseenter", function() {
this.style.backgroundColor = "red";
});
}
}
</script>
</html>
You can use CSS variable for that. and change the variable value using javascript.
let btn = document.getElementById("start")
btn.addEventListener("click", createGrid)
function createGrid() {
var Container = document.getElementById("container");
Container.innerHTML = '';
let numberOfRows = prompt("How many rows do you want?");
let i = 0;
let x = numberOfRows * numberOfRows;
document.documentElement.style.setProperty("--columns-row", numberOfRows);
for (i = 0; i < x ; i++) {
var div = document.createElement("div");
document.getElementById("container").appendChild(div);
div.addEventListener("mouseenter", function () {
this.style.backgroundColor = "red";
});
}
}
:root {
--columns-row: 2;
}
#container {
display: grid;
grid-template-columns: repeat(var(--columns-row), 1fr);
grid-template-rows: repeat(var(--columns-row), 1fr);
width: 500px;
height: 500px;
}
div {
border: 1px solid #000;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<title>Etch-a-sketch</title>
</head>
<body>
<h1>Etch-a-sketch</h1>
<button id="start">Start</button>
<div id="container">
</div>
</body>
</html>
Change your css as per your need. jsfiddle.net/926pd5oh/9
<h1>Etch-a-sketch</h1>
<button id="start">Start</button>
<div id="container"></div>
<style>
#container>div {
width: 100%;
height: 10px;
margin: 2px;
}
#container>div>div {
float: left;
height: 10px;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
width: 25px;
}
</style>
<script>
let btn = document.getElementById("start")
btn.addEventListener("click", createGrid);
function createGrid() {
let numberOfRows = prompt("How many rows do you want?");
document.getElementById("container").innerHTML = "";
console.log(numberOfRows);
for (let i = 0; i < numberOfRows; i++) {
var divRow = document.createElement("div");
document.getElementById("container").appendChild(divRow);
for (let y = 0; y < numberOfRows; y++) {
let divCol = document.createElement("div");
divCol.addEventListener("mouseenter", function () {
this.style.backgroundColor = "red";
});
divRow.appendChild(divCol);
}
}
}
</script>
I've ended up using a different tool: container.style.gridTemplateColumns and container.style.gridTemplateRows to affect the number of rows and columns of the container. This allows me not to use the :root function above. See JavaScript Syntax at https://www.w3schools.com/cssref/pr_grid-template-columns.asp
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<title>Etch-a-sketch</title>
</head>
<body>
<h1>Etch-a-sketch</h1>
<button id="start">Start</button>
<div id="container"></div>
</body>
<script>
//randomColor function is taken from http://www.devcurry.com/2010/08/generate-random-colors-using-javascript.html //
function randomRgb(value) {
col = "rgb("
+ randomColor(255) * value + ","
+ randomColor(255) * value + ","
+ randomColor(255) * value + ")";
}
function randomColor(num) {
return Math.floor(Math.random() * num);
}
function resetColorOfBoxes() {
boxes = document.querySelectorAll('div');
boxes.forEach(box => box.style.backgroundColor = "white");
}
function promptEntry() {
let userInput = prompt("How many rows would you like?", "Enter a number");
if (isNaN(userInput)) {
alert("That's not a valid entry. Try again");
promptEntry();
}
else {
createGrid(userInput);
}
}
function createGrid(numberOfRows) {
resetColorOfBoxes()
let gridTemplateColumns = 'repeat('+numberOfRows+', 1fr)'
var container = document.getElementById("container");
container.style.gridTemplateColumns = gridTemplateColumns;
container.style.gridTemplateRows = gridTemplateColumns;
let brightness = [];
let i = 0;
let numberOfBoxes = numberOfRows**2;
/*Create boxes*/
for (i; i < numberOfBoxes ; i++) {
brightness[i+1] = 1;
console.log(brightness);
var div = document.createElement("div");
div.classList.add(i+1);
document.getElementById("container").appendChild(div);
div.addEventListener("mouseenter", function () {
var className = this.className;
brightness[className] = brightness[className] - 0.1;
console.log(brightness[className]);
randomRgb(brightness[className]);
this.style.backgroundColor = col;
});
}
}
let btn = document.getElementById("start")
btn.addEventListener("click", promptEntry)
</script>
</html>

Categories

Resources