I'm trying to create what is essentially a 7x3 grid from an array of letters. I want to be able to manipulate the opacity of the letters in each cell of the grid. I have attached a diagram at the bottom better illustrate this. Currently I'm having a problem appending the letters to any of the rows after the first row, knowing how to rectify this problem would also give me the knowledge to create a random selector but I can't work out what is wrong. I'm a novice at Javascript so any pointers would be greatly appreciated.
edit: jsfiddle
JS
var $grid = $('#grid-cnt'),
rows = 3,
gridH = $grid.height(),
cellH = gridH/rows;
var gridArray = [
['C'],
['O'],
['M'],
['P'],
['A'],
['C'],
['T'],
];
for (var col = 0; col < gridArray.length; ++col){
var $column = $('<div class="column">');
$column.attr('col', col)
for (var row = 0; row < rows; ++row){
var $cell = $('<div class="cell">');
$cell.attr('row', row);
// $cell.css('width', cellW);
$cell.css('height', cellH);
$column.append($cell);
$cell.append(gridArray[col][row]);
}
$grid.append($column)
};
$(document).on("click", function() {
var columnselector = Math.floor((Math.random() * gridArray.length));
// Random row selector
var rowselector = Math.floor((Math.random() * gridArray[0].length));
//hide random letter from 2D array
//select random cell from column and addClass hidden
}
CSS
#grid {
height: 100%;
width: 100%;
display: flex;
}
.cell {
margin: 0;
box-sizing: border-box;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
}
.hidden {
opacity: 0;
}
Related
I am looking for hints on how to tackle the visualisation of a storage container and its content.
The box has to have a fixed number of cells (9x9) which are permanently displayed
I retrieve the count of items from a SQL database (currently via SUM(item_count) )
Each item should be represented by a fixed image in a cell of the box, i.e. if the SQL query returns 15 items, the first 15 cells of my grid/table should each display my image
Should I use a html table or a CSS grid to visualize my box?
An entirely different solution?
What is the best way to iterate through the cells to append the image?
Amongst other things I have unsuccessfully tried to iterate through a css grid via:
// numberOfItems comes from SQL query and is defined previously
function generateItems() {
for(i=0; i < numberOfItems; i++) {
var addItemsHere = document.getElementById("id_" + i);
var items = document.createElement("img");
items.src = "item.png";
addTubesHere.appendChild(items);
}
}
If you couldn't tell I am very new to the topic and happy to read through documentation but I hope to get some pointers into the right direction.
Thanks!
It doesn't sound as though your data has the semantics of a table but it does sound like a grid.
This snippet uses Javascript to create a 9x9 grid, putting cells in as div elements.
Rather than add a further (img) element the images in the first n cells are set by using background-image on the cell-divs. You could change this to actually create another element (an img) and set the src but from what is in the question as it stands this doesn't seem necessary.
//SET UP THE GRID
const box = document.querySelector('.box');
const numberOfItems = 15; //set just for this demo
for (let row = 0; row < 9; row++) {
for (let col = 0; col < 9; col++) {
let cell = document.createElement('div');
cell.classList.add('cell');
box.appendChild(cell);
}
}
//NOW PUT THE IMAGES INTO THE FIRST N CELLS
const cells = box.querySelectorAll('.cell');
for (let i = 0; i < numberOfItems; i++) {
cells[i].style.setProperty('--bg', 'url(https://picsum.photos/id/1015/200/200)');
}
.box {
width: 100vmin;
height: 100vmin;
display: grid;
grid-template-columns: repeat(9, 1fr);
grid-template-rows: repeat(9, 1fr);
gap: 1vmin;
}
.box>* {
border: 0.1vmin solid;
background-image: var(--bg);
background-size: cover;
background-position center center;
}
<div class="box"></div>
You can use background repeat, like this:
<style>
div {
background-image: url("https://www.i2clipart.com/cliparts/7/5/7/8/clipart-rick-astley-64x64-7578.png");
background-size: 64px 64px;
width: 64px;
height: 64px;
}
</style>
<div id="ricks"></div>
<script>
let ricks = document.getElementById('ricks');
ricks.style.width = (4 * 64) + 'px';
ricks.style.height = (3 * 64) + 'px';
</script>
jsfiddle example
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I have a 16x16 grid whereby I want to add an event listener to every div in this grid. First, I selected all divs in the container using document.querySelectorAll(). Then I looped over this list using forEach(). This did not work so I tried container.childNodes.forEach(), but still faced the same issue. Would appreciate any help.
Here's my code:
const container = document.querySelector(".container");
const gridItem = document.querySelectorAll(".grid-item").forEach(gridItem => gridItem.addEventListener("click", myFunc));
function makeGrid(rows,cols) {
container.style.setProperty("--grid-rows",rows);
container.style.setProperty("--grid-cols",cols);
for (let i = 0; i < (rows*cols); i++) {
let gridItem = document.createElement("div");
container.appendChild(gridItem).classList.add("grid-item");
}
}
makeGrid(16,16);
function myFunc() {
console.log("hello");
}
Look at your logic.
Select an element
Find all the .grid-item elements
Define a function that creates grid-item
Call the function that creates grid-item
So with that logic, you are clearly not going to find any elements. You need to create the grid-item elements before you select them. You also are not adding the class to the element correctly
So changing the order:
function myFunc() {
console.log("hello", this);
}
const container = document.querySelector(".container");
makeGrid(16, 16);
const gridItem = document.querySelectorAll(".grid-item").forEach(gridItem => gridItem.addEventListener("click", myFunc));
function makeGrid(rows, cols) {
container.style.setProperty("--grid-rows", rows);
container.style.setProperty("--grid-cols", cols);
for (let i = 0; i < (rows * cols); i++) {
const gridItem = document.createElement("div");
gridItem.classList.add("grid-item");
gridItem.textContent = i + 1;
container.appendChild(gridItem)
}
}
.container {
--grid-cols: 2;
display: grid;
grid-template-columns: repeat(var(--grid-cols), 1fr);
gap: .1em;
}
.grid-item {
border: 1px solid #CCC;
padding: .2em;
text-align: center;
}
<div class="container"></div>
But why not bind the events when you create the element?
function myFunc() {
console.log("hello", this);
}
const container = document.querySelector(".container");
function makeGrid(rows, cols) {
container.style.setProperty("--grid-rows", rows);
container.style.setProperty("--grid-cols", cols);
for (let i = 0; i < (rows * cols); i++) {
const gridItem = document.createElement("div");
gridItem.classList.add("grid-item");
gridItem.addEventListener("click", myFunc);
gridItem.textContent = i + 1;
container.appendChild(gridItem)
}
}
makeGrid(16, 16);
.container {
--grid-cols: 2;
display: grid;
grid-template-columns: repeat(var(--grid-cols), 1fr);
gap: .1em;
}
.grid-item {
border: 1px solid #CCC;
padding: .2em;
text-align: center;
}
<div class="container"></div>
or just use event delegation
function myFunc(event) {
console.log("hello", event.target.closest('.grid-item'));
}
const container = document.querySelector(".container");
container.addEventListener("click", myFunc);
function makeGrid(rows, cols) {
container.style.setProperty("--grid-rows", rows);
container.style.setProperty("--grid-cols", cols);
for (let i = 0; i < (rows * cols); i++) {
const gridItem = document.createElement("div");
gridItem.classList.add("grid-item");
gridItem.textContent = i + 1;
container.appendChild(gridItem)
}
}
makeGrid(16, 16);
.container {
--grid-cols: 2;
display: grid;
grid-template-columns: repeat(var(--grid-cols), 1fr);
gap: .1em;
}
.grid-item {
border: 1px solid #CCC;
padding: .2em;
text-align: center;
}
<div class="container"></div>
You just have things out of order. Create your grid first, then apply the event listeners. As it is, it's looping through an empty array trying to apply listeners.
const container = document.querySelector(".container");
function makeGrid(rows, cols) {
container.style.setProperty("--grid-rows", rows);
container.style.setProperty("--grid-cols", cols);
for (let i = 0; i < (rows * cols); i++) {
let gridItem = document.createElement("div");
gridItem.innerHTML = "grid item";
container.appendChild(gridItem).classList.add("grid-item");
}
}
makeGrid(16, 16);
document.querySelectorAll(".grid-item").forEach(gridItem => gridItem.addEventListener("click", myFunc));
function myFunc() {
console.log("hello");
}
<div class='container'>
</div>
You don't need to create a listener for each element. You can just create one listener on the parent element and conditionally call your code in the function:
const container = document.querySelector(".container");
// add a single listener to the parent element of the grid items
container.addEventListener("click", myFunc);
// -- snip --
function myFunc(event) {
// only run the code if the clicked element matches the selector
if (event.target.matches(".grid-item")) {
console.log("hello");
}
}
See also: Element.matches() - Web APIs | MDN
I am trying to append a to the center of a 3x3 grid. Right now the tile is the last grid-item.
The divs are created using an event listener that triggers a function with a for loop.
function displayDino(){
for (var i = 0; i < dinoData.length; i++) {
const dinoDiv = document.createElement('div');
dinoDiv.className = 'grid-item';
dinoDiv.innerHTML = `<h3>${dinoData[i]["species"]}<h3><img src="images/${(dinoData[i]["species"].toLowerCase())}.png"><p>${dinoData[i]["fact"]}</p>`;
document.getElementById('grid').appendChild(dinoDiv);
}
}
I have another function that appends the div I want centered to the grid:
function displayHuman(){
const humanDiv = document.createElement('div');
humanDiv.className = 'grid-item';
humanDiv.innerHTML = `<h3>${human.name()}<h3><img src="images/human.png">`;
document.getElementById('grid').appendChild(humanDiv);
}
How can I generate this grid while making sure a specific div appears at the center of the grid every time?
Any help would be much appreciated. Thank you!
If the grid is always 3x3 and you want to center the human entry horizontally and vertically, just wait until you are at index 5, add the human, remember that you added him and continue iterating through the array.
function displayElements(){
var humanAdded = false;
for (var i = 0; i < dinoData.length; i++) {
const elemDiv = document.createElement('div');
elemDiv .className = 'grid-item';
if(humanAdded == false && i == 5){
elemDiv .innerHTML = `<h3>${human.name()}<h3><img src="images/human.png">`;
humanAdded = true;
i--;
}else{
elemDiv .innerHTML = `<h3>${dinoData[i]["species"]}<h3><img src="images/${(dinoData[i]["species"].toLowerCase())}.png"><p>${dinoData[i]["fact"]}</p>`;
}
document.getElementById('grid').appendChild(elemDiv);
}
}
My thoughts::: If you know where to put your single data in a grid.. just use grid-row, grid-column css for that grid-child... Just ignore the other grid-childs and just style that particular child... you can have more than one humans which you can put whereever you like this way...
var dinoData = ["Plateosaurus","Abelisaurus","Barsboldia","Litosoraus","Platicore","Manticore","Trynasoraus","Sicocoreus"];
var human = { name: "MEEEEEEEE"};
function displayDino() {
for (var i = 0; i < dinoData.length; i++) {
const dinoDiv = document.createElement('div');
dinoDiv.className = 'grid-item';
dinoDiv.innerHTML = `<h3>${dinoData[i]}<h3>`;
document.getElementById('grid').appendChild(dinoDiv);
}
}
function displayHuman() {
const humanDiv = document.createElement('div');
humanDiv.className = 'grid-item human';
humanDiv.innerHTML = `<h3>${human.name}`;
document.getElementById('grid').appendChild(humanDiv);
}
displayDino();displayHuman();
#grid{
display: grid;
grid-template-columns: auto auto auto;
}
.grid-item{
display: flex;
padding: 50px;
justify-content: center;
align-items: center;
}
.human{
grid-row: 2/3;
grid-column: 2/3;
}
<div id="grid">
</div>
I am working on an Etch-A-Scetch project. I created grid which contains a certain amount of squares of the same size (the user is able to type in the amount of squares which should be displayed). To create the squares I used CSS grid and a Javascript for loop. Now I want to add event listeners, which change the background of each Square when moving over it. Unfortunately, it always shows errors when I try to add some. The current code doesn't show an error, it just doesn't do anything.
The method createSquares() should just create and add the amount of squares to the DOM. The user types in an amount, for example 10, and the displayed squares are 10 in x-direction and 10 in y-direction --> makes 100 squares in total. After that I want to add an event listener, which changes the background color of the square the user hovers over (the background color should stay changed). I am thankful for any help, because I'm really clueless :D
let squareDiv = document.querySelector('.squareDiv');
let squares = document.getElementById('#squares')
let squareAmount = 10;
function blackColor() {
this.style.backgroundColor = '#000';
this.style.border = '0px';
}
function createSquares() {
for (i = 0; i < squareAmount * squareAmount; i++) {
squares = document.createElement('div');
squares.setAttribute("id", "squares");
// squares.setAttribute("onmouseover", "addEventListener")
squares.style.display = 'grid';
squareDiv.style.setProperty('--columns-amount', squareAmount);
squareDiv.style.setProperty('--rows-amount', squareAmount);
squareDiv.appendChild(squares);
}
}
createSquares();
if (squares) {
squares.addEventListener('mouseover', _ => {
squares.style.backgroundColor = blackColor;
});
}
<div class="squareDiv"></div>
<div id="squares"></div>
You likely need something like this
I fixed the script, now fix the CSS
let container = document.getElementById("container")
let squareAmount = 5;
function getRandom() {
return '#'+Math.floor(Math.random()*16777215).toString(16);
}
function colorIt(sq) {
sq.style.backgroundColor = document.getElementById("random").checked? getRandom() : '#000';
sq.style.border = '0px';
}
function createSquares() {
let grid = document.createElement('div');
grid.setAttribute("id","squares")
grid.classList.add("grid");
for (i = 0; i < squareAmount * squareAmount; i++) {
square = document.createElement('div');
square.classList.add("square");
grid.appendChild(square);
}
container.innerHTML="";
container.appendChild(grid)
}
createSquares();
container.addEventListener('mouseover',
e => {
const target = e.target;
if (target.matches(".square")) colorIt(target)
}
);
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
grid-auto-rows: 1fr;
}
.grid::before {
content: '';
width: 0;
padding-bottom: 100%;
grid-row: 1 / 1;
grid-column: 1 / 1;
}
.grid > *:first-child {
grid-row: 1 / 1;
grid-column: 1 / 1;
}
/* Just to make the grid visible */
.grid > * {
background: rgba(0,0,0,0.1);
border: 1px white solid;
}
<label><input type="checkbox" id="random" />Random</label>
<div id="container"></div>
You have already created the element in DOM, please remove this.
while creating the element using function createSquares assign class instead of ID. Since, you should have only element with one ID.
Move the addEventListener inside the function after you have created the element.
When creating similar html elements with same properties it is better to group them together with class and not id. This is good because it becomes simple to loop these html elements with forEach or other looping methods you may prefer.
let squareDiv = document.querySelector('.squareDiv');
let squares = document.getElementById('#squares')
let squareAmount = 10;
function blackColor() {
this.style.backgroundColor = '#000';
this.style.border = '0px';
}
function createSquares() {
for (i = 0; i < squareAmount * squareAmount; i++) {
squares = document.createElement('div');
squares.setAttribute("class", "squares");
squares.setAttribute("style", "width: 100px; height: 100px; background: #090; margin-bottom: .3rem;");
// squares.setAttribute("onmouseover", "addEventListener")
squares.style.display = 'grid';
squareDiv.style.setProperty('--columns-amount', squareAmount);
squareDiv.style.setProperty('--rows-amount', squareAmount);
squareDiv.appendChild(squares);
}
}
createSquares();
if (squares) {
squares.addEventListener('mouseover', _ => {
squares.style.backgroundColor = blackColor;
});
}
<div class="squareDiv"></div>
<div id="squares"></div>
This question already has answers here:
Image inside div has extra space below the image
(10 answers)
Why does my image have space underneath?
(3 answers)
Align inline-block DIVs to top of container element
(5 answers)
Closed 3 years ago.
I am trying to create a chess board.I am using nested loops to do that. The problem is that there is a gap between two horizontal rows of the block. Below I have create a snippet for 3x3 board.
const board = document.querySelector('#board');
const colors = ["black","gray"]
function start(){
for(let i = 0;i<3;i++){
let br = document.createElement('br')
for(let j = 0;j<3;j++){
let block = document.createElement('div');
block.classList.add('block');
let id = (i * 8) + j
block.id = id;
block.style.backgroundColor = colors[(id+i) % 2]
board.appendChild(block)
}
board.appendChild(br)
}
}
start()
.block{
height: 70px;
width: 70px;
display:inline-block;
}
<div id="board"></div>
I already head about solution using float:left instead of display:inline-block. How could I remove the gap?
I would also like to see if there is better code for creating chessboard?
The gap is there because the <br>. #board { font-size: 0; } will remove it.
You seem to be trying to create a table with divs. It's perfectly fine, apart from the fact that you'll need to manage spaces between the blocks with margins, if you ever need them.
You could create a table and use border-collapse: collapse
const board = document.querySelector('#board');
const colors = ["black", "gray"]
function start() {
for (let i = 0; i < 3; i++) {
let tr = document.createElement('tr')
for (let j = 0; j < 3; j++) {
let block = document.createElement('td');
block.classList.add('block');
let id = (i * 8) + j
block.id = id;
block.style.backgroundColor = colors[(id + i) % 2]
tr.appendChild(block)
}
board.appendChild(tr)
}
}
start()
.block {
height: 70px;
width: 70px;
}
#board {
border-collapse: collapse;
}
<table id="board"></table>
try to use flex
function start(n){
let s='';
for(let i = 0;i<n;i++){
s+='<div class="row">'
for(let j = 0;j<n;j++){
s+=`<div class="block ${(i+j)%2?'white':''}"></div>`
}
s+='</div>'
}
board.innerHTML=s;
}
start(3)
.block{ height: 70px; width: 70px; background: black }
.white { background: gray }
.row { display: flex }
<input type="range" min="1" max="8" oninput="start(this.value)" value=3 /><br>
<div id="board"></div>
I'd recommend using canvas. You can fill the screen with rectangles, each with sidelength width ,and starting position (i*width,j*width). Each rect can be filled with a colour, by specifying the fill colour before drawing. Look into a good HTML Canvas tutorial.