how to reset color grid? - javascript

I am creating a simple etch-a-sketch game. currently on hover it colors in black. I am trying to use a button to reset the colors back to white. However, i can't get the button to function with an event listener, if i add an alert it displays the alert but nothing else. Please guide me and supply a documentation that I can reference as I want to learn and fixing it without explaining will be counterproductive at this point.
Thank you !
const containerGrid = document.getElementById("mainGrid");
function makeGrid(col) {
for (let i = 0; i < col * col; i++) {
const gridAdd = document.createElement("div");
gridAdd.classList.add("box");
gridAdd.textContent = "";
containerGrid.appendChild(gridAdd);
}
}
makeGrid(16); // make grid 16*16
const btnClear = document.getElementById("clear");
//mouseover event black - need to link to button (well done :)
const boxes = document.querySelectorAll('.box').forEach(item => {
item.addEventListener('mouseover', event => {
item.style.backgroundColor = "black";
})
});
btnClear.addEventListener("click", () => {
boxes.style.backgroundColor = "white";
});
const changeGrid = document.getElementById(".sizechange");
/*clearBtn.forEach.addEventListener("click", function () {
clearBtn.style.color ="white";
});
*/
/*const randomBtn = document.getElementById("randomgen").addEventListener('click',(e) => {
console.log(this.classname)
console.log(e.currentTarget === this)
}) */
//change color
#mainGrid {
display: grid;
justify-content: center;
align-items: center;
grid-template-columns: repeat(16, 1fr);
grid-template-rows: auto;
margin-left: 150px;
width: 200px;
}
.box {
color: black;
border: 3px solid;
height: 10px;
width: 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>
<link type="text/css" rel="stylesheet" href="styles.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<div id="colorContainer">
<input type="radio" id="blackchoice" value="color" name="black" class="defaultbtn">
<label for="defaultcolor">black</label>
<input type="radio" id="randomgen" class="hey">
<label for="randomchoice">random</label>
</div>
<div id="changeGrid">
<button id="clear">clear</button>
</div>
<div id="mainGrid"></div>
<script src="app.js"></script>
</body>
</html>

A couple of related problems:
The variable boxes is undefined. It looks as though it was required to be the set elements with class box. When it is being defined this is indeed done, but then made undefined by the forEach attached to it. Separate out these two things and boxes will become the collection of all elements with class box.
Then when the clear is clicked you need to step through each of these boxes making their background color white, so again use a forEach.
<!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 type="text/css" rel="stylesheet" href="styles.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style>
#mainGrid {
display: grid;
justify-content: center;
align-items: center;
grid-template-columns: repeat(16, 1fr);
grid-template-rows: auto;
margin-left: 150px;
width: 200px;
}
.box {
color: black;
border: 3px solid;
height: 10px;
width: 10px;
}
</style>
</head>
<body>
<div id="colorContainer">
<input type="radio" id="blackchoice" value="color" name="black" class="defaultbtn">
<label for="defaultcolor">black</label>
<input type="radio" id="randomgen" class="hey">
<label for="randomchoice">random</label>
</div>
<div id="changeGrid">
<button id="clear">clear</button>
</div>
<div id="mainGrid"></div>
<script src="app.js"></script>
<script>
const containerGrid = document.getElementById("mainGrid");
function makeGrid(col) {
for (let i = 0; i < col * col; i++) {
const gridAdd = document.createElement("div");
gridAdd.classList.add("box");
gridAdd.textContent = "";
containerGrid.appendChild(gridAdd);
}
}
makeGrid(16); // make grid 16*16
const btnClear = document.getElementById("clear");
//mouseover event black - need to link to button (well done :)
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => {
box.addEventListener('mouseover', event => {
box.style.backgroundColor = "black";
})
});
btnClear.addEventListener("click", () => {
boxes.forEach(box => {
box.style.backgroundColor = "white";
});
});
const changeGrid = document.getElementById(".sizechange");
/*clearBtn.forEach.addEventListener("click", function () {
clearBtn.style.color ="white";
});
*/
/*const randomBtn = document.getElementById("randomgen").addEventListener('click',(e) => {
console.log(this.classname)
console.log(e.currentTarget === this)
}) */
//change color
</script>
</body>
</html>

Simplify your CSS
Use a SELECT element for your colors
Define the gridTemplateColumns in JS, not in CSS.
Use simpler functions
Use global variables to store the current grid size and color
Don't forget to clear your grid before changing the size
Assign the mouseenter Event on each cell on creation!
Add a boolean variable isPenDown for a better user experience!
const NewEL = (sel, prop) => Object.assign(document.createElement(sel), prop);
const EL_grid = document.querySelector("#grid");
const EL_clear = document.querySelector("#clear");
const EL_color = document.querySelector("[name=color]");
const EL_size = document.querySelector("[name=size]");
let size = parseInt(EL_size.value, 10);
let color = "black";
let isPenDown = false;
function makeGrid() {
EL_grid.innerHTML = ""; // Clear current grid!
for (let i = 0; i < size ** 2; i++) {
EL_grid.style.gridTemplateColumns = `repeat(${size}, 1fr)`;
EL_grid.append(NewEL("div", {
className: "box",
onmousedown() { isPenDown = true; paint(this); },
onmouseup() { isPenDown = false; },
onmouseenter() { if (isPenDown) paint(this); },
}));
}
};
function paint(EL) {
EL.style.backgroundColor = color;
}
EL_clear.addEventListener("click", () => {
const tmp_color = color; // Remember current color
color = "transparent"; // Temporarily set it to transparent
EL_grid.querySelectorAll(".box").forEach(paint); // Paint all cells as transparent
color = tmp_color; //* Reset as it was before.
});
EL_color.addEventListener("change", () => {
color = EL_color.value;
if (color === "random") color = `hsl(${~~(Math.random() * 360)}, 80%, 50%)`;
});
EL_size.addEventListener("change", () => {
size = parseInt(EL_size.value, 10);
makeGrid();
});
// INIT!
makeGrid();
#grid {
display: inline-grid;
margin: 10px 0;
}
#grid .box {
border: 1px solid;
height: 10px;
width: 10px;
margin: 0;
user-select: none;
}
<div>
<label>
Size:
<input type="number" name="size" value="16">
</label>
<label>
Color:
<select name="color">
<option value="black">black</option>
<option value="white">white</option>
<option value="red">red</option>
<option value="yellow">yellow</option>
<option value="orange">orange</option>
<option value="fuchsia">fuchsia</option>
<option value="transparent">CLEAR (transparent)</option>
<option value="random">RANDOM COLOR</option>
</select>
</label>
<button id="clear">Clear canvas</button>
</div>
<div id="grid"></div>

Related

Can a function be inside another function?

I am working on a library project but my function called changeColor inside the readStatus function does not appear to be working.
I've tried separating it but having two event listeners on the same button does not appear to work. My goal is for readStatus function to allow a user to update the status of a book from no to yes when finished with the book.
Likewise, I want to change the background color of the div (class: card) when yes to be green and no to be red.
Can anyone tell me what I'm doing wrong?
let myLibrary = [];
function Book(title, author, pages, read) {
this.title = title;
this.author = author;
this.pages = pages;
this.read = read;
}
function addBookToLibrary(title, author, pages, read) {
let book = new Book(title, author, pages, read);
myLibrary.push(book);
displayOnPage();
}
function displayOnPage() {
const books = document.querySelector(".books");
const removeDivs = document.querySelectorAll(".card");
for (let i = 0; i < removeDivs.length; i++) {
removeDivs[i].remove();
}
let index = 0;
myLibrary.forEach((myLibrarys) => {
let card = document.createElement("div");
card.classList.add("card");
books.appendChild(card);
for (let key in myLibrarys) {
let para = document.createElement("p");
para.textContent = `${key}: ${myLibrarys[key]}`;
card.appendChild(para);
}
let read_button = document.createElement("button");
read_button.classList.add("read_button");
read_button.textContent = "Read ";
read_button.dataset.linkedArray = index;
card.appendChild(read_button);
read_button.addEventListener("click", readStatus);
let delete_button = document.createElement("button");
delete_button.classList.add("delete_button");
delete_button.textContent = "Remove";
delete_button.dataset.linkedArray = index;
card.appendChild(delete_button);
delete_button.addEventListener("click", removeFromLibrary);
function removeFromLibrary() {
let retrieveBookToRemove = delete_button.dataset.linkedArray;
myLibrary.splice(parseInt(retrieveBookToRemove), 1);
card.remove();
displayOnPage();
}
function readStatus() {
let retrieveBookToToggle = read_button.dataset.linkedArray;
Book.prototype = Object.create(Book.prototype);
const toggleBook = new Book();
if (myLibrary[parseInt(retrieveBookToToggle)].read == "yes") {
toggleBook.read = "no";
myLibrary[parseInt(retrieveBookToToggle)].read = toggleBook.read;
} else if (myLibrary[parseInt(retrieveBookToToggle)].read == "no") {
toggleBook.read = "yes";
myLibrary[parseInt(retrieveBookToToggle)].read = toggleBook.read;
}
let colorDiv = document.querySelector(".card");
function changeColor() {
for (let i = 0; i < length.myLibrary; i++) {
if (myLibrary[i].read == "yes") {
colorDiv.style.backgroundColor = "green";
} else if (myLibrary[i].read == "no") {
colorDiv.style.backgroundColor = "red";
}
}
}
displayOnPage();
}
index++;
});
}
let add_book = document.querySelector(".add-book");
add_book.addEventListener("click", popUpForm);
function popUpForm() {
document.getElementById("data-form").style.display = "block";
}
function closeForm() {
document.getElementById("data-form").style.display = "none";
}
let close_form_button = document.querySelector("#close-form");
close_form_button.addEventListener("click", closeForm);
function intakeFormData() {
let title = document.getElementById("title").value;
let author = document.getElementById("author").value;
let pages = document.getElementById("pages").value;
let read = document.getElementById("read").value;
if (title == "" || author == "" || pages == "" || read == "") {
return;
}
addBookToLibrary(title, author, pages, read);
document.getElementById("data-form").reset();
}
let submit_form = document.querySelector("#submit-form");
submit_form.addEventListener("click", function (event) {
event.preventDefault();
intakeFormData();
});
* {
margin: 0;
padding: 0;
background-color: rgb(245, 227, 205);
}
.books {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
text-align: center;
margin: 20px;
gap: 10px;
}
.card {
border: 1px solid black;
border-radius: 15px;
padding: 10px;
}
.forms {
display: flex;
flex-direction: column;
align-items: center;
}
form {
margin-top: 20px;
}
select,
input[type="text"],
input[type="number"] {
width: 100%;
box-sizing: border-box;
}
.buttons-container {
display: flex;
margin-top: 10px;
}
.buttons-container button {
width: 100%;
margin: 2px;
}
.add-book {
margin-top: 20px;
}
#data-form {
display: none;
}
.read_button {
margin-right: 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" />
<link rel="stylesheet" href="style.css" />
<title>Document</title>
</head>
<body>
<div class="container">
<div class="forms">
<button class="add-book">Add Book To Library</button>
<div class="pop-up">
<form id="data-form">
<div class="form-container">
<label for="title">Title</label>
<input type="text" name="title" id="title" />
</div>
<div class="form-container">
<label for="author">Author</label>
<input type="text" name="author" id="author" />
</div>
<div class="form-container">
<label for="pages">Pages</label>
<input type="number" name="pages" id="pages" />
</div>
<div class="form-container">
<label for="read">Read</label>
<select name="read" id="read">
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
<div class="buttons-container">
<button type="submit" id="submit-form">Submit Form</button>
<button type="button" id="close-form">Close Form</button>
</div>
</form>
</div>
</div>
<div class="books"></div>
</div>
<script src="script.js"></script>
</body>
</html>
A couple things needed.
First, you should put the readStatus and removeFromLibrary functions outside of the foreach loop.
Then I think you are wanting changeColor to run whenever readStatus is run. Either put the changeColor code directly inside the readStatus or put changeColor() inside readStatus.
I think you want the Book to not be a function but a class.

Weird bug occurring for Event listeners( I think)

Whenever I click either 'Reset', 'Color Black', or 'Erase' randomly the entire grid will color in black. If that happens and I click Erase I can clear them off and then sometimes randomly the excess black that was randomly created will disappear. Not really sure what the issue is. I THINK it may be an issue with how the Event Listeners are set up, but this is the only configuration of them that gets the buttons to work. Any ideas what the issue might be?
let blackBtn = document.querySelector('#black');
let eraseBtn = document.querySelector('#eraser');
let resetBtn = document.querySelector('#reset');
let resize = document.querySelector('.resize');
let value = 16; // For default 16x16 grid size
//Create grid
function createGrid(size = value) {
grid.style["grid-template-rows"] = `repeat(${size}, 1fr)`;
grid.style["grid-template-columns"] = `repeat(${size}, 1fr)`;
for (let i = 0; i < size * size; i++) {
const block = document.createElement('div');
block.className = 'block';
grid.appendChild(block);
}
grid.addEventListener("mouseover", colorBlack);
resize.addEventListener("click", resizeGrid);
resetBtn.addEventListener("click", clearGrid);
eraseBtn.addEventListener("click", eraseColor);
blackBtn.addEventListener("click", blackPaint);
}
//Resize the grid
function resizeGrid() {
const newSize = parseInt(prompt("New Size: ", 16));
grid.innerHTML = '';
resize.removeEventListener("click", resizeGrid);
grid.removeEventListener("mouseover", colorBlack);
createGrid(newSize);
}
//Fill in background color of black
function colorBlack(e) {
if (e.target.className !== "block") return false;
e.target.style.backgroundColor = 'black';
}
//Clear background color from grid
function clearGrid(size, newSize) {
grid.innerHTML = '';
resize.removeEventListener("click", resizeGrid);
grid.removeEventListener("mouseover", colorBlack);
createGrid();
}
//Colors divs black after clicking 'Color Black'
function blackPaint(e) {
grid.removeEventListener("mouseover", eraseColor);
grid.addEventListener("mouseover", (e) => {
e.target.style.backgroundColor = 'black';
})
}
//Colors over black divs with white to 'erase' it
function eraseColor(e) {
grid.removeEventListener("mouseover", colorBlack);
grid.addEventListener("mouseover", (e) => {
e.target.style.backgroundColor = 'white';
})
}
createGrid();
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
#grid {
width: 20rem;
height: 20rem;
border: 1px solid #333;
display: grid;
flex-wrap: grid;
}
.block {
border: 1px solid 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>Etch-A-Sketch</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<p>Etch-A-Sketch</p>
</header>
<div class="gameBoard">
<div id="actions">
<button class="resize">Resize</button>
<button id="reset">Reset</button>
<button id="black">Color Black</button>
<button id="eraser">Eraser</button>
</div>
<div id='grid'></div>
<div class="block"></div>
</div>
<script src="script.js"></script>
</body>
</html>
When you click on Black or Erase, you add event listeners that call anonymous functions. These can't be removed with removeEventListener() when you switch modes. So these old event listeners continue to run, erasing and filling in elements.
You should have two functions, colorBlack() and colorWhite(), and switch between them in the mouseover event listener. Also, when you reset or resize, you should go back to black.
The problem with Clear is that it calls createGrid(), which adds all the event listeners again. You remove some of the old listeners before you call it, but not all, so you get duplication. You should separate creating the grid and adding the event listeners, so you don't repeat the listeners, and then you wouldn't need to remove them.
let blackBtn = document.querySelector('#black');
let eraseBtn = document.querySelector('#eraser');
let resetBtn = document.querySelector('#reset');
let resize = document.querySelector('.resize');
let value = 16; // For default 16x16 grid size
//Create grid
function createGrid(size = value) {
grid.style["grid-template-rows"] = `repeat(${size}, 1fr)`;
grid.style["grid-template-columns"] = `repeat(${size}, 1fr)`;
for (let i = 0; i < size * size; i++) {
const block = document.createElement('div');
block.className = 'block';
grid.appendChild(block);
}
}
function addListeners() {
grid.addEventListener("mouseover", colorBlack);
resize.addEventListener("click", resizeGrid);
resetBtn.addEventListener("click", clearGrid);
eraseBtn.addEventListener("click", eraseColor);
blackBtn.addEventListener("click", blackPaint);
}
//Resize the grid
function resizeGrid() {
const newSize = parseInt(prompt("New Size: ", 16));
grid.innerHTML = '';
createGrid(newSize);
blackPaint();
}
//Fill in background color of black
function colorBlack(e) {
if (e.target.className !== "block") return false;
e.target.style.backgroundColor = 'black';
}
//Fill in background color of white
function colorWhite(e) {
if (e.target.className !== "block") return false;
e.target.style.backgroundColor = 'white';
}
//Clear background color from grid
function clearGrid(size, newSize) {
grid.innerHTML = '';
createGrid();
blackPaint();
}
//Colors divs black after clicking 'Color Black'
function blackPaint(e) {
grid.removeEventListener("mouseover", colorWhite);
grid.addEventListener("mouseover", colorBlack);
}
//Colors over black divs with white to 'erase' it
function eraseColor(e) {
grid.removeEventListener("mouseover", colorBlack);
grid.addEventListener("mouseover", colorWhite);
}
createGrid();
addListeners();
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
#grid {
width: 20rem;
height: 20rem;
border: 1px solid #333;
display: grid;
flex-wrap: grid;
}
.block {
border: 1px solid 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>Etch-A-Sketch</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<p>Etch-A-Sketch</p>
</header>
<div class="gameBoard">
<div id="actions">
<button class="resize">Resize</button>
<button id="reset">Reset</button>
<button id="black">Color Black</button>
<button id="eraser">Eraser</button>
</div>
<div id='grid'></div>
<div class="block"></div>
</div>
<script src="script.js"></script>
</body>
</html>

How to allow user to change font size

I am making a google docs like app, and I want the user to be able to select the text, and then change the size to whatever they want. I tried to use variables but it didn't work so I am not sure what to do. Is there any way to allow the user to change the font size and if so how?
Here is the code for the app:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Editor</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<button class="bold" onclick="document.execCommand('bold',false,null);">
𝗕
</button>
<button class="italic" onclick="document.execCommand('italic',false,null);">
𝘐
</button>
<button
class="underline"
onclick="document.execCommand('underline',false,null);"
>
U̲
</button>
<input
type="color"
class="color-picker"
id="colorPicker"
oninput="changeColorText(this.value);"
/>
<label>Select color</label>
<button id="highlight"><mark>Highlight</mark></button>
<fieldset class="userInput" contenteditable="true"></fieldset>
<script>
var boldBtn = document.querySelector(".bold");
var italicBtn = document.querySelector(".italic");
var underlineBtn = document.querySelector(".underline");
var colorPicker = document.querySelector(".color-picker");
var highlightBtn = document.querySelector("#highlight");
boldBtn.addEventListener("click", function () {
boldBtn.classList.toggle("inUse");
});
italicBtn.addEventListener("click", function () {
italicBtn.classList.toggle("inUse");
});
underlineBtn.addEventListener("click", function () {
underlineBtn.classList.toggle("inUse");
});
highlightBtn.addEventListener("click", function () {
highlightBtn.classList.toggle("inUse");
});
const changeColorText = (color) => {
document.execCommand("styleWithCSS", false, true);
document.execCommand("foreColor", false, color);
};
document
.getElementById("highlight")
.addEventListener("click", function () {
var range = window.getSelection().getRangeAt(0),
span = document.createElement("span");
span.className = "highlight";
span.appendChild(range.extractContents());
range.insertNode(span);
});
</script>
</body>
</html>
I think this is the output you want. Also, don't use document.execCommand, it has been deprecated
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Editor</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<button class="bold" onclick="document.execCommand('bold',false,null);">
𝗕
</button>
<button class="italic" onclick="document.execCommand('italic',false,null);">
𝘐
</button>
<button
class="underline"
onclick="document.execCommand('underline',false,null);"
>
U̲
</button>
<input
type="color"
class="color-picker"
id="colorPicker"
oninput="changeColorText(this.value);"
/>
<label>Select color</label>
<button id="highlight"><mark>Highlight</mark></button>
<input
type="number"
class="font-size"
id="fontSize"
/>
<label>Select Font Size</label>
<fieldset class="userInput" contenteditable="true"></fieldset>
<script>
var boldBtn = document.querySelector(".bold");
var italicBtn = document.querySelector(".italic");
var underlineBtn = document.querySelector(".underline");
var colorPicker = document.querySelector(".color-picker");
var fontSize = document.querySelector("#fontSize");
var highlightBtn = document.querySelector("#highlight");
var userInput = document.querySelector('.userInput');
boldBtn.addEventListener("click", function () {
boldBtn.classList.toggle("inUse");
});
italicBtn.addEventListener("click", function () {
italicBtn.classList.toggle("inUse");
});
underlineBtn.addEventListener("click", function () {
underlineBtn.classList.toggle("inUse");
});
highlightBtn.addEventListener("click", function () {
highlightBtn.classList.toggle("inUse");
});
const changeColorText = (color) => {
document.execCommand("styleWithCSS", false, true);
document.execCommand("foreColor", false, color);
};
fontSize.addEventListener('input', updateValue);
function updateValue(e) {
userInput.style.fontSize = `${e.target.value}px`;
}
document
.getElementById("highlight")
.addEventListener("click", function () {
var range = window.getSelection().getRangeAt(0),
span = document.createElement("span");
span.className = "highlight";
span.appendChild(range.extractContents());
range.insertNode(span);
});
</script>
</body>
</html>
Add this to your HTML:
<button class="font-smaller">-</button>
<button class="font-bigger">+</button>
Add this to your JS:
const fontSmaller = document.querySelector(".font-smaller");
const fontBigger = document.querySelector(".font-bigger");
let fontSize = 15.5; // play with this number if needed
fontSmaller.addEventListener("click", () => {
document.querySelector(".userInput").style.fontSize = `${fontSize--}px`;
});
fontBigger.addEventListener("click", () => {
document.querySelector(".userInput").style.fontSize = `${fontSize++}px`;
});
Change as needed. This will change the size of the whole text.
You can implement it like this.
// Increase/descrease font size
$('#increasetext').click(function() {
curSize = parseInt($('#content').css('font-size')) + 2;
if (curSize <= 32)
$('#content').css('font-size', curSize);
});
$('#resettext').click(function() {
if (curSize != 18)
$('#content').css('font-size', 18);
});
$('#decreasetext').click(function() {
curSize = parseInt($('#content').css('font-size')) - 2;
if (curSize >= 14)
$('#content').css('font-size', curSize);
});
header {
text-align: center;
}
/* text-controls */
button {
vertical-align: bottom;
margin: 0 0.3125em;
padding: 0 0.3125em;
border: 1px solid #000;
background-color: #fff;
font-weight: bold;
}
button#increasetext {
font-size: 1.50em;
}
button#resettext {
font-size: 1.25em;
}
button#decreasetext {
font-size: 1.125em;
}
.textcontrols {
padding: 0.625em 0;
background: #ccc;
}
/* content */
#content {
margin: 3em 0;
text-align: left;
}
/* demo container */
#container {
width: 90%;
margin: 0 auto;
padding: 2%;
}
#description {
margin-bottom: 1.25em;
text-align: left;
}
#media all and (min-width: 700px) {
#container {
width: 700px;
}
button {
margin: 0 0.625em;
padding: 0 0.625em;
}
}
<div id="container">
<header>
<h1 id="title">
Allow Users to Change Font Size
</h1>
<p>Click the buttons to see it in action</p>
<div class="textcontrols">
<button role="button" id="decreasetext" <span>smaller</span>
</button>
<button role="button" id="resettext">
<span>normal</span>
</button>
<button role="button" id="increasetext">
<span>bigger</span>
</button>
</div>
<!--/.textcontrols-->
</header>
<main id="content" role="main">
<div id="description">
<h2>Allow users to resize text on the page via button controls.</h2>
<p>In this instance, users can decrease text, increase text, or reset it back to normal.</p>
<h2>Set default text size with CSS</h2>
<p>The default text size must be set using an internal stylesheet in the header of your page. In this case: <code>font-size: 1.125em</code> (aka, 18px).</p>
<h2>Set the controls with JavaScript</h2>
<p>Then we set the resize controls with JavaScript. In this example, we're resizing all text within the div with an id of "content".</p>
<p>The controls check the current text size, and then changes it (or not) accordingly.</p>
</div>
<!--/#description-->
</main>
<!--/#content-->
</div>
<!--/#container-->

Setting strict grid size in CSS grid

I am currently trying to complete an etch-a-sketch project but am having issues with setting a grid to respect a strict size value. I want to set it so that the grid squares become smaller and the overall container remains the same however what I currently have forces the grid to go off the page.
I have tried max-height and max-width settings but these don't seem to do anything. Could someone please help me ?
Javascript Code
const button16 = document.querySelector('.smol');
const button24 = document.querySelector('.med');
const button64 = document.querySelector('.large');
const button = document.querySelector('.reset');
const container = document.querySelector('.container');
function row(num, columns){
for (let i = 0; i < num; i++){
const div = document.createElement('div')
container.appendChild(div);
for (let i = 0; i < columns; i++){
const div2 = document.createElement('div2', );
div.appendChild(div2);
}
}
}
hover(row(16, 16))
button16.addEventListener('click', () => {
clearGrid();
hover(row(16, 16))
});
button24.addEventListener('click', () => {
clearGrid();
hover(row(24, 24))
});
button64.addEventListener('click', () => {
clearGrid();
hover(row(64, 64))
});
function hover() {
const wrapper2 = container.querySelectorAll('div2');
wrapper2.forEach(wrapper2 => wrapper2.addEventListener('mouseenter', () => {
const hash = '#';
let randomColor = Math.floor(Math.random()*16777215).toString(16);
wrapper2.style.backgroundColor = hash + randomColor;
}));
wrapper2.forEach(wrapper2 => button.addEventListener("click", () => {
wrapper2.style.backgroundColor = 'white';
}));
}
function clearGrid() {
container.innerHTML = null
}
My CSS
.container {
display: grid;
grid-template-columns:repeat(64, 1fr);
width: 500px;
height: 500px;
}
div2 {
border: solid 0.1px;
color: #424242;
display: grid;
width:30px;
height: 25px;
box-sizing: border-box
}
.buttonbox {
display: flex;
width: 500px;
}
.reset, .smol, .med, .large {
padding: 5px;
}
My html
<!DOCTYPE HTML>
<html lan="en">
<head>
<meta charset = utf-8>
<link rel= 'stylesheet' href="Styles.css" ></script>
<script src = GameLogic.js defer></script>
<title>My Etch-A-Sketch Project</title>
</head>
<body>
<h1>Etch-A-Sketch</h1>
<div class = "container">
</div>
<div class = 'buttonbox'>
<button class="reset">
Clear Grid
</button>
<button class="smol">
16 x 16
</button>
<button class="med">
24 x 24
</button>
<button class="large">
64 x 64
</button>
</div>
</body>
</html>

Time for populating a UI dynamically increases linearly, with each try?

Requirement:
User will enter "Number of Containers" and "Number of Controls"
Random input elements (numeric, checkbox, etc) will be created and equally distributed among the containers.
When user clicks on "Create" again, the input elements shown in the UI will be deleted and new set of random input elements will be populated again.
Issue:
Every time I create new set of input elements, the time taken for creating increases linearly up to a point then decreases little and increases again
I use the below code to empty the div that accommodates the containers and create input elements
Emptying the overall div
node.innerHTML = ""
Creating a numeric control with label
function createNumber(display) {
let controlWrap = document.createElement("div");
let label = document.createElement("label")
let control = document.createElement("input")
control.type = "number";
label.append("Numeric Input");
label.append(control);
controlWrap.append(label);
controlWrap.style.display = display;
controlWrap.classList.add("ctrl");
return controlWrap;
}
Find the entire code below,
//Constands
const CTRL_DISPLAY_TYPE = "block"
//Selection
const numOfContainers = document.querySelector("#numOfContainers");
const numOfControls = document.querySelector("#numOfControls");
const createContainersBtn = document.querySelector("#create");
const containerWrapper = document.querySelector(".containerWrapper");
const controlHeading = document.querySelectorAll(".ctrlHeading");
//Event Listeners
createContainersBtn.addEventListener("click",createContainers);
controlHeading.forEach(element => element.addEventListener("click"),expandControl);
//Support-functions
function createControl(newControlContainer){
let newControlWrapper = document.createElement("div")
newControlWrapper.classList.add("ctrlWrapper");
let newControl = createNumber(CTRL_DISPLAY_TYPE);
newControlWrapper.appendChild(newControl);
newControlContainer.appendChild(newControlWrapper);
}
function createNumber(display){
let controlWrap = document.createElement("div");
let label = document.createElement("label")
let control = document.createElement("input")
control.type = "number";
label.append("Numeric Input");
label.append(control);
controlWrap.append(label);
controlWrap.style.display = display;
controlWrap.classList.add("ctrl");
return controlWrap;
}
function calculateControlPerContainer(numOfContainers,numOfControls,maxLimit){
let controlsPerContainer = []
let pendingControls = numOfControls%numOfContainers
let controlPerContainerNum = Math.floor(numOfControls/numOfContainers)
for (let i=0;i<numOfContainers;i++){
if (pendingControls>0){
newControlsPerContainer=controlPerContainerNum+1;
controlsPerContainer.push(newControlsPerContainer);
--pendingControls;
}
else{
controlsPerContainer.push(controlPerContainerNum);
}
}
return controlsPerContainer
}
function expandControl(event){
const control = event.currentTarget.nextElementSibling;
if (control.style.display === "none"){
control.style.display = "block";
}
else {
control.style.display = "none"
}
}
//utility-functions
function removeChild(node){
while(node.firstChild){
node.removeChild(node.firstChild);
}
}
function clearNodeData(node){
node.innerHTML = ""
}
//main-Functions
function createContainers(event){
console.time("Deleting controls");
const controlsPerContainer = calculateControlPerContainer(parseInt(numOfContainers.value),parseInt(numOfControls.value));
clearNodeData(containerWrapper);
//removeChild(containerWrapper);
console.timeEnd("Deleting controls");
console.time("populating controls");
controlsPerContainer.forEach(num=>{
let newControlContainer = document.createElement("div")
newControlContainer.classList.add("ctrlContainer");
for(let j=0;j<num;j++){
createControl(newControlContainer);
}
containerWrapper.appendChild(newControlContainer);
})
console.timeEnd("populating controls");
}
* {
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
border: 0;
height:100%
}
.containerWrapper{
display:flex;
flex-direction: row;
height: 90%;
}
.ctrlContainer{
/* flex-grow:1; */
flex-shrink: 0;
border-style: solid;
border-width: 0.5px;
margin:0 2px;
flex-basis: calc(25% - 4px);
align-items: stretch;
display:flex;
flex-direction: column;
overflow: auto;
}
.ctrlWrapper{
border-style: solid;
border-width: .5px;
margin:2px
}
.ctrlHeading{
display:block;
width: 100%;
text-align: left;
border: 0;
}
.ctrl{
display:none;
}
<!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>Dynamic Controls</title>
<link rel="stylesheet" href="style/main.css">
</head>
<body>
<label for="numOfContainers">Number of Containers</label>
<input type="number" id="numOfContainers" name="numOfContainers" min="1" max="500" value="100">
<label for="numOfControls">Number of Controls</label>
<input type="number" id="numOfControls" name="numOfControls" min="1" max="1500" value="1500"><br>
<button id="create">Create</button>
<div class="containerWrapper">
<!-- <div class="ctrlContainer">
<div class="ctrlWrapper">
<button class="ctrlHeading">Checkbox</button>
<input class="ctrl" type="checkbox">
</div>
<div class="ctrlWrapper">
<button class="ctrlHeading">Checkbox</button>
<input class="ctrl" type="checkbox">
</div>
</div>
<div class="ctrlContainer">2</div>
<div class="ctrlContainer">3</div> -->
</div>
<script type="module" src="scripts/MainBackup.js"></script>
</body>
</html>
I tried analyzing using chrome developer tools and could see "append" function is taking more total time. Please let me know if I am doing something wrong in deleting or adding controls and how to avoid this time build up with every run.
More Information after some more exploration:
I am seeing this behavior only in chrome. In firefox and edge, there is no time buildup.
Firefox:
This occurs only in my system. Others are not able to replicate.
The time build-up occurs in portion of code in which I append inputs to the label to assign it to the input without using id. If I directly append the input to container, the time buildup doesn't happen

Categories