splitting div into multiple divs in javascript - javascript

Hi I am trying to make the columns and rows in the mainContent div but the problem is the it is getting out of the mainContent after 2-3 clicks. I want it to remain inside and should create equally sized columns and rows inside of it. here is my code.
var test2 = document.getElementById('btn');
test2.addEventListener('click', function() {
console.log('clicked');
var contain = document.getElementById('contentArea'); // for selecting id
var newGriding = document.createElement('div');
newGriding.setAttribute('id', 'grid');
contain.appendChild(newGriding);
});
#contentArea {
background-color: #babab3;
height: 74vh;
margin: 0 auto;
}
#grid {
margin: 0;
padding: 0;
border: none;
outline: 5px dashed #aba4a4;
display: inline-block;
height: 100%;
width: 50%;
}
<div id="contentArea">
</div>
<button id="btn">
create
</button>

Because you are using fixed height for the appending element.
You should resize the element after every click using some logic or you can use the display of your parent as flex and flex wrap true.
var test2 = document.getElementById('btn');
test2.addEventListener('click', function() {
var contain = document.getElementById('contentArea'); // for selecting id
var newGriding = document.createElement('div');
newGriding.setAttribute('id', 'grid');
contain.appendChild(newGriding);
});
#contentArea {
background-color: #babab3;
height: 74vh;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
}
#grid {
margin: 0;
padding: 0;
border: none;
outline: 5px dashed #aba4a4;
display: inline-block;
width: 50%;
}
<div id="contentArea">
</div>
<button id="btn">create</button>
or
var test2 = document.getElementById('btn');
test2.addEventListener('click', function() {
var contain = document.getElementById('contentArea'); // for selecting id
var newGriding = document.createElement('div');
newGriding.setAttribute('id', 'grid');
contain.appendChild(newGriding);
resizeDiv();
});
var maxInRow = 2;
function resizeDiv() {
var allGrids = document.querySelectorAll("#contentArea > #grid");
var width = 100 / maxInRow;
var len = allGrids.length;
var colNo = Math.floor(len / maxInRow);
colNo = colNo - (len / maxInRow) == 0 ? colNo : colNo + 1;
var height = 100 / colNo;
for (var i = 0; i < len; i++) {
allGrids[i].style.width = width + "%";
//"calc(" + width + "% - 10px)"; --- if doesn't want box-sizing to be borderbox
allGrids[i].style.height = height + "%";
//"calc(" + height + "% - 10px)"; --- if doesn't want box-sizing to be borderbox
//reduce the size of box which increased due to outline
}
}
#contentArea {
background-color: #babab3;
height: 74vh;
margin: 0 auto;
position: relative;
}
#grid {
margin: 0;
padding: 0;
border: 5px dashed #aba4a4;
display: inline-block;
height: 100%;
width: 50%;
position: relative;
box-sizing: border-box;
}
<div id="contentArea">
</div>
<button id="btn">
create
</button>

Related

Optimized solution for filling entire page with DIVs

I want to have a webpage whose entire viewable area is filled with divs. I am currently using the following code:
var wh= window.innerHeight;
var ww= window.innerWidth;
var area= wh * ww;
i= 1;
while(area > 0) {
document.getElementById("map").innerHTML+= "<div class='map-box' id='box" + i + "'></div>";
area-= 20 * 20;
i+=1;
}
.map-box {width: 20px; height: 20px; border-color: grey; border-width: 1px; border-style: solid; display: inline-block; margin: 0; padding: 0;}
<body>
<div id='map'></div>
</body>
If you try to use this code is your browser, you will see that there are two flaws in this:
First, it creates too many extra divs which go outside the viewable screen.
Second, this code is also somewhat slow.
Can someone here help me address both of these flaws and also optimize this code for faster performance?
1.) That <div> is not 20x20, because of the border:
let d = document.getElementById("test");
console.log(d.offsetWidth, d.offsetHeight);
.map-box {
width: 20px;
height: 20px;
border-color: grey;
border-width: 1px;
border-style: solid;
display: inline-block;
margin: 0;
padding: 0;
}
<div id="test" class="map-box"></div>
2.) There's still the default border around the entire thing, and also some spacing between the lines:
var wh = window.innerHeight;
var ww = window.innerWidth;
var area = wh * ww;
i = 1;
while (area > 0) {
document.getElementById("map").innerHTML += "<div class='map-box' id='box" + i + "'></div>";
area -= 22 * 22; // hardcoding is not that nice
i += 1;
}
.map-box {
width: 20px;
height: 20px;
border-color: grey;
border-width: 1px;
border-style: solid;
display: inline-block;
margin: 0;
padding: 0;
}
#map {
background: blue;
}
body {
background: red;
}
<div id='map'></div>
3.) Half cells are evil, so the width/height should be rounded downwards to a multiple of 22. Suddenly the grid is becoming an actual rectangle, at least in Chrome/Edge. The between-spacing is still a problem:
var wh = Math.floor(window.innerHeight / 22) * 22; // <--!!
var ww = Math.floor(window.innerWidth / 22) * 22; // <--!!
var area = wh * ww;
i = 1;
while (area > 0) {
document.getElementById("map").innerHTML += "<div class='map-box' id='box" + i + "'></div>";
area -= 22 * 22;
i += 1;
}
.map-box {
width: 20px;
height: 20px;
border-color: grey;
border-width: 1px;
border-style: solid;
display: inline-block;
margin: 0;
padding: 0;
}
#map {
background: blue;
}
body {
background: red;
margin: 0; // <--!!
padding: 0; // <--!!
}
<div id='map'></div>
I don't actually know how to use line-height properly, this one works on my machine with my scaling/DPI, in Chrome/Edge, but that's all I can say about it. The 22-s are cut back, area now simply stores the number of <div>s to generate.
var wh = Math.floor(window.innerHeight / 22);
var ww = Math.floor(window.innerWidth / 22);
var area = wh * ww;
i = 1;
while (area > 0) {
document.getElementById("map").innerHTML += "<div class='map-box' id='box" + i + "'></div>";
area--;
i += 1;
}
.map-box {
width: 20px;
height: 20px;
border-color: grey;
border-width: 1px;
border-style: solid;
display: inline-block;
margin: 0;
padding: 0;
}
#map {
line-height: 0.6;
}
body {
margin: 0;
padding: 0;
}
<div id='map'></div>
Instead of accessing dom element's inner html on each loop iteration - do it once after the loop with "prepared" data to set there
const wh = window.innerHeight;
const ww = window.innerWidth;
let area = wh * ww;
i = 1;
const ms = Date.now();
const divs = [];
while (area > 0) {
divs.push("<div class='map-box' id='box" + i + "'></div>");
area -= 20 * 20;
i += 1;
}
document.getElementById("map").innerHTML = divs.join("");
console.log("done fast", Date.now() - ms);
js fiddle with comparison https://jsfiddle.net/aL7zqwy9/
The final solution, not ideal but
<html>
<body>
<div id='map'></div>
</body>
<style>
body {
margin: 0;
padding: 0;
/* Overflow appears when last row is added and shrinks the "width" */
overflow-y: hidden;
}
#map {
/* To exclude space between rows */
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.map-box {
width: 20px;
height: 20px;
border: 1px solid grey;
display: block;
margin: 0;
padding: 0;
/* So border thickness will not affect element size */
box-sizing: border-box;
}
</style>
<script>
const cellSize = 20; // px
const wh = window.innerHeight;
const ww = window.innerWidth;
// not always divisible by cell size without a remainder
const columnsCount = Math.floor(ww / cellSize);
const rowsCount = Math.floor(wh / cellSize);
const cellsCount = columnsCount * rowsCount;
console.log(`wh: ${wh}, ww: ${ww}, cols: ${columnsCount}, rows: ${rowsCount}`);
const divs = [];
for (let i = 0; i < cellsCount; i++) {
divs.push(`<div class='map-box' id='box${i}'></div>`);
}
document.getElementById("map").innerHTML = divs.join("");
</script>
</html>

Yet again, CSS being problematic again

So basically this is Day 3 (other days, I pretty much did nothing to complete the game) of making a game from HTML5. So I'm making a moves system right now, and I guess I'm doing well? (mainly because I'm not sure if I provided the user with too many moves...) But the thing about it is that, I'm kind of having ANOTHER styling issue.
As you can see in the image: I've CLEARLY set dimensions up for the headerDisplay class/id, but NO, it goes out of the div's dimensions and even goes on the grid. I'm also aiming for the time and moves text to be stuck right on top of the grid, similarly to how the word bank is stuck to the bottom of the grid.
I was also aiming for a button that says refresh right under the word bank, however no matter what I tried, the button would just be right the score text, which looks like this:
When I am aiming for this:
Code:
<div class="content" id="content">
<div class="headerDisplay" id="headerDisplay">
</div>
<div class="gameArea" id="gameArea">
</div>
<div class="wordBank" id="wordBank">
</div>
<div class="bottomMenu" id="bottomMenu">
</div>
</div>
::before,
::after {
box-sizing: border-box;
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.content {
display: grid;
grid-template-rows: repeat(3, max-content);
margin-block: 1em;
margin-inline: auto;
width: 512px;
}
.bottomMenu {
font-size: 24px;
text-align: right;
}
.wordBank {
border: 2.5px solid #000;
border-radius: 5px;
display: flex;
font-size: 1.6em;
min-height: 3em;
justify-content: space-between;
padding: 0.25em;
}
.wordBank span:nth-child(even) {
align-self: end;
}
.gameArea {
font-size: 0;
justify-self: center;
max-width: 100%;
}
.cell {
border: 1px solid black;
width: 50px;
font-size: 1rem;
height: 50px;
display: inline-block;
}
.headerDisplay {
width: 100%;
height: 76.8px;
text-align: right;
font-size: 1.6em;
}
let score = 0;
const headerDisplay = document.getElementById("headerDisplay")
const bottomMenu = document.getElementById("bottomMenu");
const wordBank = document.getElementById("wordBank")
const gameArea = document.getElementById("gameArea")
const rows = document.getElementsByClassName("gridRow");
const cells = document.getElementsByClassName("cell");
const words = [ // snippet
"ability",
"able",
"about",
"above",
"abroad",
"absence",
"absent",
"absolute",
"accept",
"accident",
"accord",
"account",
"accuse",
"accustom",
"ache",
"across",
"act"
]
let selectedWords = [];
bottomMenu.innerHTML = "<p>Score: " + score;
bottomMenu.innerHTML += "<button>Refresh"
while (selectedWords.length < 5) {
const selectedWord = words[Math.floor(Math.random() * words.length)];
if (selectedWord.length <= 9) {
wordBank.innerHTML += "<span>" + selectedWord + "</span>"
selectedWords.push(selectedWord);
}
}
let longestWord = selectedWords.reduce((a, b) => a.length < b.length ? b : a, "")
let charCount = longestWord.length
var moves = charCount * 5
headerDisplay.innerHTML += "<p>Time: "
headerDisplay.innerHTML += "<p>Moves: " + moves
function makeRows(rowNum) {
for (let r = 0; r < rowNum; r++) {
let row = document.createElement("div");
gameArea.appendChild(row).className = "gridRow";
}
}
function makeColumns(cellNum) {
for (let i = 0; i < rows.length; i++) {
for (let j = 0; j < cellNum; j++) {
let newCell = document.createElement("div");
rows[j].appendChild(newCell).className = "cell";
}
}
}
function defaultGrid() {
makeRows(charCount);
makeColumns(charCount);
}
defaultGrid();
To fix header you need to set its height to fit content, so it will be over your grid even if you change it later:
.headerDisplay {
width: 100%;
height: content-fit; /* previous: 76.8px */
text-align: right;
font-size: 1.6em;
}
And to fix bottom menu you need to add flexbox:
.bottomMenu {
font-size: 24px;
text-align: right;
display: flex; /* new */
flex-direction: row-reverse; /* new */
justify-content: space-between; /* new */
align-items: center; /* new */
}
For the button, you could try this:
button {
position: relative;
right: 400px;
bottom: 50px;
transform: scale(2,2)
}

Covering the entire div's with HTMl divs

Supoose the screen size is 1920by1080, then I want div of user input suppose say 200by200
then these div's of this dimensions should create the entire screen. How can i do that using HMTL, CSS and javascript.
CSS CODE
div {
height: 200px;
width: 200px;
background-color: red;
padding-bottom: 20px;
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3);
border-style: solid;
display: inline-block;
}
HTML CODE
<input type="number" placeholder="enter height of div" id="div_height" />
<input type="number" placeholder="enter width of div" id="div_width" />
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
JAVASCRIPT
function myFunction() {
let height_div = document.getElementById('div_height').value;
let width_div = document.getElementById('div_width').value;
var xy = '',
i,
size = 20;
var x = screen.availHeight;
var y = screen.availWidth;
while (x > height_div) {
while (y > width_div) {
xy = xy + '<div>' + '</div>';
y = y - width_div;
}
x = x - height_div;
}
document.getElementById('demo').innerHTML = xy;
console.log(height_div + ' ' + width_div);
document.getElementsByTagName('div').style.height = height_div + 'px';
document.getElementsByTagName('div').style.width = width_div + 'px';
OUTPUT
Try using this code:
div
{
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
Then it would cover entire screen.
function myFunction(e) {
e.preventDefault()
let height_div = document.getElementById("div_height").value;
let width_div = document.getElementById("div_width").value;
var xy = "";
const xi = Math.floor(window.innerWidth / width_div);
const yi = Math.floor(window.innerHeight / height_div);
for (let i = 0; i < yi; i++) {
xy += "<div class='row'>";
for (let j = 0; j < xi; j++) {
xy += "<div></div>"
}
xy += '</div>'
}
console.log(xy)
document.getElementById("demo").innerHTML = xy;
console.log(height_div + " " + width_div);
Array.from(document.getElementsByTagName("div")).map(el => (el.style.height = height_div + "px"));
Array.from(document.getElementsByTagName("div")).map(el => (el.style.width = width_div + "px"));
}
document.querySelector("form").addEventListener('submit', myFunction);
div {
box-sizing: border-box;
height: 200px;
width: 200px;
background-color: red;
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3);
border-style: solid;
flex-grow: 0;
flex-shrink: 0;
}
.row {
display: flex;
}
p#demo {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
margin: 0;
z-index: 1;
}
.form {
background: blue;
position: relative;
z-index: 2;
}
<form class="form">
<input type="number" placeholder="enter height of div" id="div_height" />
<input type="number" placeholder="enter width of div" id="div_width" />
<button>Try it</button>
</form>
<p id="demo"></p>
Try something like this,
you can use Math.ceiling if you want to fill the white gaps and have a little hangover

DOM Element Not Rendering on Page Until After JS Transition Completion

The title says it all. To see the issue, copy this code to the following online compiler: https://www.w3schools.com/php/phptryit.asp?filename=tryphp_compiler
<!DOCTYPE HTML>
<html>
<style>
/*MAIN*/
* {
margin: 0;
padding: 0;
user-select: none;
overflow: hidden;
}
body {
background-color: #FF0000;
margin: 0;
padding: 0;
}
/*ELEMENTS*/
div {
width: 100vw;
height: 100vh;
float: left;
margin-left: 0vw;
}
h1 {
font-family: verdana;
font-size: 5vh;
text-transform: uppercase;
}
h1.white {
color: #F4F4F4;
}
</style>
<body>
<div id = "main" style = "width: auto; margin-left: 0vw;">
<div id = "home" class = "container" style = 'background-color: #000000;'>
<h1 class = "white">click arrow to see how the next page doesn't appear until after the transition is complete</h1>
<!--ARROW BUTTON-->
<p id = 'arrowButton' style = 'color: #FFFFFF; position: absolute; height: 10vh; width: auto; margin: 45vh 0 0 75vw; font-size: 3vh;' onMouseDown = 'NextButtonClick();'>--></p>
</div>
<div id = "welcome" class = "container" style = 'background-color: #FFFFFF;'>
<h1 style = 'margin: 47.5vh 0 0 50vw'>welcome to my portfolio</h1>
</div>
</div>
<script>
var mainDiv, welcomeDiv;
var transitionSeconds = 0.5;
var isTransitioning = false;
function NextButtonClick() {
if(!isTransitioning) {
isTransitioning = true;
i = 0;
thisInterval = setInterval(function() {
mainDiv.style.marginLeft = (100 / i) - 101 + "vw";
i++;
if(i == 100) {
clearInterval(thisInterval);
mainDiv.style.marginLeft = "-100vw";
isTransitioning = false;
}
}, transitionSeconds);
}
}
window.onload = function() {
mainDiv = document.getElementById("main");
welcomeDiv = document.getElementById("welcome");
var arrowButton = document.getElementById("arrowButton");
var arrowButtonX, arrowButtonY;
var arrowButtonGlowDistance = 100;
arrowButtonX = arrowButton.getBoundingClientRect().left + arrowButton.getBoundingClientRect().width/2;//center
arrowButtonY = arrowButton.getBoundingClientRect().top + arrowButton.getBoundingClientRect().height/2;//center
document.onmousemove = function(e) {
x = e.clientX; y = e.clientY;
};
};
</script>
</body>
</html>
The background is red on purpose so that you can see how, even though the "welcome" div should be rendered over top the background, it is not being rendered until the very last second after the transition is completed and 100% of the element is on the screen.
I am stumped, and I'm not sure why this is since HTML usually doesn't seem to behave this way. Even when I highlight the element in Inspect Element, the Inspector doesn't show me where the element is on the screen until the final moment when it is rendered.
Any help would be greatly appreciated, and I look forward to hearing your feedback!
The problem here is that your DIVs are placed under each other and while one is moving horizontally, the next div is still underneath of it until first one is completely out of the way (just like Jenga game in reverse).
To solve this, you can try add display: flex, to place them horizontally instead:
var mainDiv, welcomeDiv;
var transitionSeconds = 0.5;
var isTransitioning = false;
function NextButtonClick() {
if (!isTransitioning) {
isTransitioning = true;
i = 0;
thisInterval = setInterval(function() {
mainDiv.style.marginLeft = (100 / i) - 101 + "vw";
i++;
if (i == 100) {
clearInterval(thisInterval);
mainDiv.style.marginLeft = "-100vw";
isTransitioning = false;
}
}, transitionSeconds);
}
}
window.onload = function() {
mainDiv = document.getElementById("main");
welcomeDiv = document.getElementById("welcome");
var arrowButton = document.getElementById("arrowButton");
var arrowButtonX, arrowButtonY;
var arrowButtonGlowDistance = 100;
arrowButtonX = arrowButton.getBoundingClientRect().left + arrowButton.getBoundingClientRect().width / 2; //center
arrowButtonY = arrowButton.getBoundingClientRect().top + arrowButton.getBoundingClientRect().height / 2; //center
document.onmousemove = function(e) {
x = e.clientX;
y = e.clientY;
};
};
* {
margin: 0;
padding: 0;
user-select: none;
overflow: hidden;
}
body {
background-color: #FF0000;
margin: 0;
padding: 0;
}
/*ELEMENTS*/
div {
width: 100vw;
height: 100vh;
float: left;
margin-left: 0vw;
display: flex; /* added */
}
h1 {
font-family: verdana;
font-size: 5vh;
text-transform: uppercase;
}
h1.white {
color: #F4F4F4;
}
<div id="main" style="width: auto; margin-left: 0vw;">
<div id="home" class="container" style='background-color: #000000;'>
<h1 class="white">click arrow to see how the next page doesn't appear until after the transition is complete</h1>
<!--ARROW BUTTON-->
<p id='arrowButton' style='color: #FFFFFF; position: absolute; height: 10vh; width: auto; margin: 45vh 0 0 75vw; font-size: 3vh;' onMouseDown='NextButtonClick();'>--></p>
</div>
<div id="welcome" class="container" style='background-color: #FFFFFF;'>
<h1 style='margin: 47.5vh 0 0 50vw'>welcome to my portfolio</h1>
</div>
</div>

customize the look of dynamically created DIVs

The script creates a random number of divs (in range 20-40) and puts some text in every single div. The script calculates the width of divs so that they fit in a single row. The height should be equal to the width - every div must be a square. Here's the code:
var quantity = Math.floor(Math.random() * (40 - 20 + 1)) + 20;
for (var i = 0; i < quantity; i++) {
var elem = document.createElement("div");
elem.className = "part";
elem.id = 'p' + i;
document.getElementById("scale").appendChild(elem);
}
var parts = document.getElementsByClassName("part");
for (var i = 0; i < parts.length; i++) {
parts[i].style.fontSize = (500 / quantity) + 'px';
parts[i].style.lineHeight = (460 / quantity) + 'px';
parts[i].textContent = ("block #" + (i + 1));
}
for (var i = 0; i < parts.length; i++) {
parts[i].style.height = parts[i].style.width;
}
let text = document.getElementById('txt');
text.textContent = 'BLOCKS: ' + quantity;
body {
margin: 0;
}
#scale {
position: absolute;
display: table;
width: 100%;
top: 50%;
transform: translateY(-100%);
table-layout: fixed;
border-spacing: 1px;
}
.part {
display: table-cell;
background-color: #a9cce3;
padding: 3px;
box-sizing: border-box;
border: 1px solid black;
border-radius: 2px;
overflow: hidden;
}
#txt {
position: absolute;
top: 50%;
left: 50%;
margin-top: 20px;
transform: translateX(-50%);
font-size: 18px;
font-family: 'Arial', sans-serif;
}
<div id="scale"> </div>
<div id='txt'> </div>
The first problem is the divs are not always square. The second problem is I can't properly set the font size depending on a div size, so text fits a div. I think that's the worst solution
parts[i].style.fontSize = (500 / quantity) + 'px';
parts[i].style.lineHeight = (460 / quantity) + 'px';
There were two problems with the code:
To get element with use .clientWidth because style.width can be accessed when you have set that but in your code, I couldn't see you are doing so.
Second use font size in per cent, I don't think line-height is required. To make it centre use CSS as in example follows.
Use following:
var quantity = Math.floor(Math.random() * (40 - 20 + 1)) + 20;
for (var i = 0; i < quantity; i++) {
var elem = document.createElement("div");
elem.className = "part";
elem.id = 'p' + i;
document.getElementById("scale").appendChild(elem);
}
var parts = document.getElementsByClassName("part");
for (var i = 0; i < parts.length; i++) {
parts[i].style.fontSize = (500 / quantity) + '%';
parts[i].style.lineHeight = (460 / quantity) + '%';
parts[i].textContent = ("block #" + (i + 1));
}
for (var i = 0; i < parts.length; i++) {
parts[i].style.height = parts[i].clientWidth + "px";
}
let text = document.getElementById('txt');
text.textContent = 'BLOCKS: ' + quantity;
body {
margin: 0;
}
#scale {
position: absolute;
display: table;
width: 100%;
top: 50%;
transform: translateY(-100%);
table-layout: fixed;
border-spacing: 1px;
}
.part {
display: table-cell;
background-color: #a9cce3;
padding: 3px;
box-sizing: border-box;
border: 1px solid black;
border-radius: 2px;
overflow: hidden;
vertical-align: middle;
text-align: center;
}
#txt {
position: absolute;
top: 50%;
left: 50%;
margin-top: 20px;
transform: translateX(-50%);
font-size: 18px;
font-family: 'Arial', sans-serif;
}
<div id="scale"> </div>
<div id='txt'> </div>
Or if you don't want to use your text font to be reduced like this use following:
.part {
display: table-cell;
background-color: #a9cce3;
padding: 3px;
box-sizing: border-box;
border: 1px solid black;
border-radius: 2px;
overflow: hidden;
vertical-align: middle;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}

Categories