Bind a block to cells in a table - javascript

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;
}

Related

why grid cells wont go below 32px width and height?

im trying to make static grid with a button that can change number of boxes in it (from 16x16 to 64x64 and anything between). Grid is 40rem x 40rem, when i try to change manually number of boxes in makeGrid() function it works fine up to 20 (boxes change size accordingly), but anything above 20 stays the same size and gets cutoff from my grid. If there is no grid css overflow property stated, grid width change depending on number of boxes but boxes themself won't shrink
my code:
size button is not working yet, grid size need to be changed mannualy in makeGrid function
const grid = document.getElementById('grid');
const size = document.getElementById('size');
const eraser = document.getElementById('eraser');
const color = document.getElementById('color');
const gridBorder = document.getElementById('grid-borders');
const clear = document.getElementById('clear');
// grid
function makeGrid(number) {
number = number || 16;
let cellWidth = 40 / number + 'rem';
let cellHeight = 40 / number + 'rem';
grid.style.gridTemplateColumns = `repeat( ${number}, 1fr)`;
grid.style.gridTemplateRows = `repeat(${number}, 1fr)`;
for (let i = 0; i < number * number; i++) {
let cell = document.createElement('div');
grid.appendChild(cell).id = 'box';
cell.classList.add('border');
cell.classList.add('box');
cell.style.backgroundColor = 'white';
cell.style.width = cellWidth;
cell.style.height = cellHeight;
}
size.textContent = `${number} x ${number}`;
}
makeGrid();
// drawing on hover
color.addEventListener('click', function () {
grid.addEventListener('mouseover', function (e) {
e.target !== grid ? (e.target.style.backgroundColor = 'black') : null;
});
});
function changeColor(event) {
event.target.style.backgroundColor = 'black';
}
// erase functionality
eraser.addEventListener('click', function () {
grid.addEventListener('mouseover', function (e) {
e.target !== grid ? (e.target.style.backgroundColor = 'white') : null;
});
});
// grid borders
const allBoxes = document.querySelectorAll('.box');
gridBorder.addEventListener('click', function () {
allBoxes.forEach((box) => {
box.classList.toggle('no-border');
box.classList.toggle('border');
});
});
// clear button
clear.addEventListener('click', function () {
allBoxes.forEach((box) => {
box.style.backgroundColor = 'white';
});
});
// size button
// size.addEventListener('click', function () {
// let number = prompt(`Enter grid size less or equal to 100`);
// if (number !== Number.isInteger()) {
// return;
// } else if (number > 100) {
// number = prompt(`Enter grid size greater or equal to 100`);
// }
// });
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 100vh;
background-color: aquamarine;
}
#grid {
display: grid;
justify-content: center;
border: 1px solid #ccc;
width: 40rem;
height: 40rem;
min-width: 0;
min-height: 0;
overflow: hidden;
}
.box {
padding: 1em;
}
#title {
display: flex;
align-items: flex-end;
justify-content: center;
height: 180px;
}
#container {
display: flex;
height: 60%;
width: 1259px;
align-items: flex-start;
justify-content: flex-end;
gap: 20px;
padding-top: 20px;
}
#menu {
display: flex;
flex-direction: column;
gap: 10px;
}
.border {
outline: 1px solid black;
}
.no-border {
outline: none;
}
.black-bg {
background: black;
}
.white-bg {
background: white;
}
<!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>
<link rel="stylesheet" href="style.css" />
<script src="script.js" defer></script>
</head>
<body>
<div id="title">
<h1>Etch-a-Sketch</h1>
</div>
<main id="container">
<div id="menu">
<button id="size"></button>
<button id="color">Color</button>
<button id="eraser">Eraser</button>
<button id="clear">Clear</button>
<button id="grid-borders">Grid Borders</button>
</div>
<div id="grid"></div>
</main>
</body>
</html>
"Why won't my grid cells go below 32px?" - have you checked your padding (hint: 32px is exactly equal to 2 * 16px which in turn is exactly equal to your padding of 1em with most browsers implementing a default font-size of 16px). –
David Thomas
box padding was set to 1em which caused my problem, after deleting it my grid worked as intended

How can you force nested flexboxes to fill a desired space?

var tag = document.createElement("div");
var element = document.getElementById("container");
for(let i = 1; i<17; i++){
var tag = document.createElement("div");
tag.setAttribute('id', `row`)
tag.setAttribute('tag', `parent`)
element.appendChild(tag);
var elements = document.getElementById(`row`)
for(let j = 1; j<17; j++){
var tags = document.createElement("div");
tags.setAttribute('id', `${j}`)
tags.setAttribute('cell', `yes`)
tags.setAttribute('parent', `${i}`)
elements.appendChild(tags)
elements.removeAttribute("id")
//console.log(elements)
}
}
var cells = document.querySelectorAll('parent')
addEventListener('mouseover', function(e) {
const selectedCell = e.path[0]
//console.log(selectedCell.getAttribute('parent'))
//console.log(typeof selectedCell.getAttribute('parent'))
if(typeof selectedCell.getAttribute('parent') === 'string'){
selectedCell.setAttribute('selected', 'true')
//console.log(selectedCell)
}
})
#container {
display: flex;
flex-wrap: wrap;
align-items: baseline;
align-content: stretch;
height: 960px;
width: 960px;
}
div[tag]{
display: flex;
flex-direction: row;
height: 60px;
width: 100%;
flex-grow: 1;
}
[tag] > [id]{
display: flex;
height: 60px;
flex-direction: row;
flex-grow: 1;
}
div[selected]{
background-color: black;
}
<!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>Document</title>
<link rel="stylesheet" href="stylesheet.css">
</head>
<body>
<div id="container">
</div>
<script src = "app.js"></script>
</body>
</html>
I am currently on the tail end of the introductory front-end course from OdinProject, however, I am stuck on the etch-a-sketch assignment. The CSS (located below) will only fill out properly if I set a fixed height in pixels.
div#container {
border-color: red;
height: 960px;
width: 960px;
flex-direction: row;
}
div[tag*="parent"]{
display: flex;
flex-direction: row;
height: auto;
width: 100%;
flex-grow: 1;
}
div[cell*="yes"]{
display: flex;
height: auto;
flex-direction: row;
flex-grow: 1;
}
div[selected]{
background-color: black;
}
If I set the height to auto (as present in the current styling), the width is fine, which is 960 pixels, but the height of the rows and the cells will be 0 pixels. Setting the height as a fixed height is okay in this scenario which is a 16x16 etch-a-sketch, however, I am planning to allow the user to select the number of cells, which would require the height to be dynamic. I have tried everything and nothing seems to work. This is my first question here, so I don't know if you will require the other code, so I will just paste it below.
var tag = document.createElement("div");
var element = document.getElementById("container");
for(let i = 1; i<17; i++){
var tag = document.createElement("div");
tag.setAttribute('id', `row`)
tag.setAttribute('tag', `parent`)
element.appendChild(tag);
var elements = document.getElementById(`row`)
for(let j = 1; j<17; j++){
var tags = document.createElement("div");
tags.setAttribute('id', `${j}`)
tags.setAttribute('cell', `yes`)
tags.setAttribute('parent', `${i}`)
elements.appendChild(tags)
elements.removeAttribute("id")
console.log(elements)
}
}
var cells = document.querySelectorAll('parent')
addEventListener('mouseover', function(e) {
const selectedCell = e.path[0]
//console.log(selectedCell.getAttribute('parent'))
console.log(typeof selectedCell.getAttribute('parent'))
if(typeof selectedCell.getAttribute('parent') === 'string'){
selectedCell.setAttribute('selected', 'true')
console.log(selectedCell)
}
})
<!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>Document</title>
<link rel="stylesheet" href="stylesheet.css">
</head>
<body>
<div id="container">
</div>
<script src = "app.js"></script>
</body>
</html>
I changed the height and width on div#container to 100vh and 100vw. This is so that the container fills the whole viewport, which is what you want as I understand.
I removed the height:auto on the parent and cell classes and I also removed width:100%
I created a variable called gridSize with let. I replaced the 17 with this variable gridSize in the two loops and I added the following to calculate the height of the cell:
let cellHeight = Math.floor((100 / gridSize) * 1000) / 1000 + "vh";
And, then I set the height of the cell dynamically with:
tags.style.height = gridSize
which effectively is the same as:
tags.style.height = "10vh" // if gridSize is 10
tags.style.height = "5vh" // if gridSize is 20
You should be able to implement the functionality to allow the user to dynamically select the grid size. This demo should show you the way forward.
var tag = document.createElement("div");
var element = document.getElementById("container");
let gridSize = 17;
let cellHeight = Math.floor((100 / gridSize) * 1000) / 1000 + "vh";
for (let i = 1; i < gridSize; i++) {
var tag = document.createElement("div");
tag.setAttribute('id', `row`)
tag.setAttribute('tag', `parent`)
element.appendChild(tag);
var elements = document.getElementById(`row`)
for (let j = 1; j < gridSize; j++) {
var tags = document.createElement("div");
tags.setAttribute('id', `${j}`)
tags.setAttribute('cell', `yes`)
tags.setAttribute('parent', `${i}`)
tags.style.height = cellHeight;
elements.appendChild(tags)
elements.removeAttribute("id")
}
}
var cells = document.querySelectorAll('parent')
addEventListener('mouseover', function(e) {
const selectedCell = e.path[0]
if (typeof selectedCell.getAttribute('parent') === 'string') {
selectedCell.setAttribute('selected', 'true')
}
})
div#container {
border-color: red;
height: 100vh;
width: 100vw;
flex-direction: row;
}
div[tag*="parent"] {
display: flex;
flex-direction: row;
flex-grow: 1;
}
div[cell*="yes"] {
display: flex;
flex-direction: row;
flex-grow: 1;
}
div[selected] {
background-color: black;
}
<div id="container"></div>

Space between rows in a grid [duplicate]

This question already has answers here:
Align inline-block DIVs to top of container element
(5 answers)
Vertical space between two inline-block and a block element
(5 answers)
Image inside div has extra space below the image
(10 answers)
Closed 1 year ago.
I am trying to create a 16x16 grid.
Everything works perfectly except that I have some space between my rows, I can't figure out why.
The spacing between the columns is perfect but the rows have some gap between them.
Here's my code:
const container = document.getElementById("drawingGrid");
let rows = document.getElementsByClassName("gridRow");
let cells = document.getElementsByClassName("cell");
function createGrid() {
makeRows(16);
makeColumns(16);
}
// create rows
function makeRows(rowNum) {
for (r = 0; r < rowNum; r++) {
let row = document.createElement("div");
container.appendChild(row).className = "gridRow";
}
}
// create columns
function makeColumns(cellNum) {
for (i = 0; i < rows.length; i++) {
for (j = 0; j < cellNum; j++) {
let newCell = document.createElement("div");
rows[j].appendChild(newCell).className = "cell";
}
}
}
createGrid();
.cell {
border: 1px solid gray;
min-width: 10px;
min-height: 10px;
display: inline-block;
margin: 0;
padding: 0;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>EtchASketch</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="drawingGrid">
</div>
<script src="app.js"></script>
</body>
</html>
And here's what it looks like on chrome:
You can turn the gridRow into a flexbox container. You can read the reason behind the space: Why does my image have space underneath? here.
const container = document.getElementById("drawingGrid");
let rows = document.getElementsByClassName("gridRow");
let cells = document.getElementsByClassName("cell");
function createGrid() {
makeRows(16);
makeColumns(16);
}
// create rows
function makeRows(rowNum) {
for (r = 0; r < rowNum; r++) {
let row = document.createElement("div");
container.appendChild(row).className = "gridRow";
}
}
// create columns
function makeColumns(cellNum) {
for (i = 0; i < rows.length; i++) {
for (j = 0; j < cellNum; j++) {
let newCell = document.createElement("div");
rows[j].appendChild(newCell).className = "cell";
}
}
}
createGrid();
.cell {
border: 1px solid gray;
min-width: 10px;
min-height: 10px;
display: inline-block;
margin: 0;
padding: 0;
}
.gridRow {
display: flex;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>EtchASketch</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="drawingGrid">
</div>
<script src="app.js"></script>
</body>
</html>
You should define the height of your row:
.gridRow{
max-height:10px;
}
or setting the line-height of your row:
.gridRow{
line-height:10px;
}
or using flexbox as defined by m4n0.

How to set the window's Y middle to element's Y middle?

I have created a button which should shift the window's Y to "BOX - 5" div's Y middle through onclick. So in other words I want to set the "Box - 5" div in the middle of the window. I have tried many methods using window.scrollTo and using elements.innerHeight/2, but I still cannot center the element to the middle of the window/screen. Please Help.
I wish to only use Javascript, but if its not possible with it then I would accept jQuery script.
index.html:
window.onbeforeunload = function () {
this.scrollTo(0, 0);
}
var content = document.getElementById("content"),
current = 0;
for (var y=0;y<10;y++) {
var box = document.createElement("div");
box.id = "box";
box.innerHTML = "Box - " + (y+1);
content.appendChild(box);
}
document.querySelector("BUTTON").onclick = function() {
var box_5 = document.querySelectorAll("#box")[4];
/*
NEED HELP HERE
*/
}
body {
margin: 0;
}
#box {
position: relative;
height: 500px;
width: 100%;
margin: 5% auto 5% auto;
color: black;
background-color: skyblue;
border: black 1px solid;
font-size: 50px;
text-align: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<button>CLICK TO SET THE WINDOW'S Y MIDDLE TO (BOX 5)'s Y MIDDLE</button>
<div id="content"></div>
</body>
</html>
Updated your snippet as below. You can use DOM element property offsetTop to check its Y position and use window.scroll to scroll the view to that element. Another sidenote, it's better to not assign the same id to multiple elements, so I change the id property to class and added identifier _{index} for the class name.
window.onbeforeunload = function () {
this.scrollTo(0, 0);
}
var content = document.getElementById("content"),
current = 0;
for (var y=0;y<10;y++) {
var box = document.createElement("div");
box.className += "box _" + (y+1);
box.innerHTML = "Box - " + (y+1);
content.appendChild(box);
}
document.querySelector("BUTTON").onclick = function() {
var box_5 = document.querySelectorAll(".box._5")[0];
if (box_5) {
// scroll the window view to the element
window.scroll({
top: box_5.offsetTop,
behavior: 'smooth',
})
}
}
body {
margin: 0;
}
.box {
height: 500px;
width: 100%;
margin: 5% auto 5% auto;
color: black;
background-color: skyblue;
border: black 1px solid;
font-size: 50px;
text-align: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<button>CLICK TO SET THE WINDOW'S Y MIDDLE TO (BOX 5)'s Y MIDDLE</button>
<div id="content"></div>
</body>
</html>

JavaScript itareate over divs and create a new one if doesn't fits

Hello guys I hope you can help me with JavaScript, I'm trying to itarate over some divs, the issue is that when I iterate sometimes a div never change to the other divs, it suppose to be infinite, I will recive thousands of different divs with different height and it should create an other div container in the case it does not fits but I can not achieve it work's, I'm using Vanilla JavaScript because I'm lerning JavaScript Regards.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.big_container{
height: 600px;
width: 150px;
background-color: #f1f1f1;
float: left;
}
.items{
background-color: gray;
height: 50px;
}
.new_container{
margin-bottom: 10px;
height: 300px;
width: 150px;
background-color: red;
float: left;
margin-left: 5px;
}
</style>
</head>
<body>
<div class="big_container">
<div class="items">1</div>
<div class="items">2</div>
<div class="items">3</div>
<div class="items">4</div>
<div class="items">5</div>
<div class="items">6</div>
<div class="items">7</div>
<div class="items">8</div>
<div class="items">9</div>
<div class="items">10</div>
<div class="items">11</div>
<div class="items">12</div>
<div class="items">13</div>
</div>
<div class="new_container">
</div>
</body>
<script>
number = 0
sum = 0
new_container = document.getElementsByClassName('new_container')[number].offsetHeight
divs = document.getElementsByClassName('items')
for ( var i = 0; i < divs.length; i++ ){
sum += this.document.getElementsByClassName( 'items' )[0].offsetHeight
if ( sum <= new_container ){
console.log(sum, "yes")
document.getElementsByClassName("new_container")[number].appendChild( this.document.getElementsByClassName( 'items' )[0] )
} else {
sum = 0
console.log(sum, "NO entra")
nuevo_contenedor = document.createElement('div'); // Creo un contenedor
nuevo_contenedor.className = "new_container";
nuevo_contenedor.setAttribute("style", "background-color: red;");
document.body.appendChild(nuevo_contenedor)
number += + 1
}
}
</script>
</html>
I really apreciate a hand.
I know that I'm late, but there is my approach how this can be done.
// generate items with different height
function generateItems(count) {
const arr = [];
for (let i = 0; i < count; i++) {
const div = document.createElement("DIV");
const height = Math.floor((Math.random() * 100) + 10);
div.setAttribute("style", `height: ${height}px`);
div.setAttribute("class", "items");
const t = document.createTextNode(i + 1);
div.appendChild(t);
arr.push(div);
}
return arr;
}
function createNewContainer(height) {
const new_container = document.createElement("DIV")
new_container.setAttribute("class", "new_container");
new_container.setAttribute("style", `height: ${height}px`)
document.body.appendChild(new_container);
return new_container;
}
function breakFrom(sourceContainerId, newContainerHeight) {
const srcContainer = document.getElementById(sourceContainerId);
const items = srcContainer.childNodes;
let new_container = createNewContainer(newContainerHeight);
let sumHeight = 0;
for (let i = 0; i < items.length; i++) {
let item = items[i];
if (item.offsetHeight > newContainerHeight) {
// stop!!! this item too big to fill into new container
throw new Error("Item too big.");
}
if (sumHeight + item.offsetHeight < newContainerHeight) {
// add item to new container
sumHeight += item.offsetHeight;
new_container.appendChild(item.cloneNode(true));
} else {
// create new container
new_container = createNewContainer(newContainerHeight);
new_container.appendChild(item.cloneNode(true));
// don't forget to set sumHeight)
sumHeight = item.offsetHeight;
}
}
// if you want to remove items from big_container
// for (let i = items.length - 1; i >= 0; i--) {
// srcContainer.removeChild(items[i]);
// }
}
// create big container with divs
const big_container = document.getElementById("big_container");
const items = generateItems(13);
items.forEach((div, index) => {
big_container.appendChild(div);
});
breakFrom("big_container", 300);
#big_container {
width: 150px;
background-color: #f1f1f1;
float: left;
}
.items {
background-color: gray;
border: 1px solid #000000;
text-align: center;
}
.new_container {
margin-bottom: 10px;
height: 300px;
width: 150px;
background-color: red;
border: 1px solid red;
float: left;
margin-left: 5px;
}
<div id="big_container"></div>
This example gives you the ability to play with divs of random height. Hope, this will help you.

Categories

Resources