Set container size width and height with one function argument - javascript

I have a container grid, that I'm trying to set the width and height of proportionally by passing that one number as an argument tiles in my createSketchGrid function. I'm using the variable gridSize to take the arguments tiles and multiply it by itself. The result is a container that is quite a bit wider than its height.
I'm not quite sure how to set this evenly and multiplying it doesn't make it proportional, either. Is there a way to set the width and height to be the same if I use this one argument? I also think that setting the container's display property to flex may be part of the problem as well.
const grid = document.querySelector('#grid');
const userInput = document.querySelector('#user-input');
grid.style.fontSize = '1em';
// Set pixel width and height
let wdt = '1.25em';
let hgt = '1.25em';
// Ask the user for the number of tiles for the sketch grid
function getUserInput() {
let input = parseInt(prompt(`Please enter the grid size you'd like`));
input <= 100 || !isNaN(input)
? createSketchGrid(input)
: alert('Please enter a valid number less than or equal to 100.');
}
// Event listener to create tiles in mouseover
function setTiles(e) {
e.target.classList.add('fill');
}
function deleteTiles(e) {
e.target.classList.toggle('fill');
}
// Create the grid
function createSketchGrid(tiles) {
let gridSize = tiles * tiles;
for (let i = 0; i < gridSize; i++) {
let tile = document.createElement('div');
tile.style.width = wdt;
tile.style.height = hgt;
grid.appendChild(tile);
tile.addEventListener('mouseover', setTiles);
}
}
userInput.addEventListener('click', getUserInput);
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 10px;
}
h1 {
font-size: 3rem;
}
.grid {
display: flex;
flex-wrap: wrap;
gap: 0.1em;
background-color: lightgrey;
flex: 0 0 32em;
}
.fill {
flex-wrap: wrap;
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>Etch A Sketch</title>
<link rel="stylesheet" type="text/css" href="styles/style.css">
<script type="text/javascript" src="js/main.js" defer></script>
</head>
<body>
<h1 class="title">Etch A Sketch</h1>
<div id="container" class="container">
<button id="user-input" class="btn user-input" value="Grid Size">Grid Size</button>
<div id="grid" class="grid">
</div>
</div>
</body>
</html>

Using CSS grid, we can define how many columns we want (here I have just used the regular repeat(..., ...) method), and we can also change the width of the grid to match.
const grid = document.querySelector('#grid');
const userInput = document.querySelector('#user-input');
grid.style.fontSize = '1em';
// Set pixel width and height
let wdt = '1.25em';
let hgt = '1.25em';
// Ask the user for the number of tiles for the sketch grid
function getUserInput() {
let input = parseInt(prompt(`Please enter the grid size you'd like`));
input <= 100 || !isNaN(input)
? createSketchGrid(input)
: alert('Please enter a valid number less than or equal to 100.');
}
// Event listener to create tiles in mouseover
function setTiles(e) {
e.target.classList.add('fill');
}
function deleteTiles(e) {
e.target.classList.toggle('fill');
}
// Create the grid
function createSketchGrid(tiles) {
let gridSize = tiles * tiles;
for (let i = 0; i < gridSize; i++) {
let tile = document.createElement('div');
tile.style.width = wdt;
tile.style.height = hgt;
grid.appendChild(tile);
tile.addEventListener('mouseover', setTiles);
}
// change style
grid.style.gridTemplateColumns = `repeat(${tiles}, 1fr)`;
// calculate new width
grid.style.width = `calc(${wdt} * ${tiles} + 0.1em * ${tiles - 1})`;
}
userInput.addEventListener('click', getUserInput);
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 10px;
}
h1 {
font-size: 3rem;
}
.grid {
display: grid;
grid-template-columns: repeat(0, 1em);
gap: 0.1em;
background-color: lightgrey;
}
.fill {
flex-wrap: wrap;
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>Etch A Sketch</title>
<link rel="stylesheet" type="text/css" href="styles/style.css">
<script type="text/javascript" src="js/main.js" defer></script>
</head>
<body>
<h1 class="title">Etch A Sketch</h1>
<div id="container" class="container">
<button id="user-input" class="btn user-input" value="Grid Size">Grid Size</button>
<div id="grid" class="grid">
</div>
</div>
</body>
</html>

Related

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

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

Continuous call on EventListener on mousedown

I'm working on an Etch A Sketch app for The Odin Project and I want to adjust one of the requirements where all I need to do is move the mouse on screen as a continuous stroke where each pixel touched on mouseover is filled, which is what's happening right now with my code.
What I want to change is the mouseover on my tile EventListener where it's really a continuous stroke on mousedown. I did try changing the e.target command in the setTiles function to toggle after changing the tile.addEventListener to mousedown, but it only works on each press of the left mouse button.
I'm trying to figure out a way to make this continuous on mousedown instead of using mouseover. I've included the code I have so far in the question.
const container = document.querySelector('#container');
const grid = document.querySelector('#grid');
const userInput = document.querySelector('#user-input');
let penDown = false;
grid.style.fontSize = '1em';
// Set pixel width and height
let wdt = '1em';
let hgt = '1em';
// Ask the user for the number of tiles for the sketch grid
function getUserInput() {
let input = parseInt(prompt(`Please enter the grid size you'd like`));
input <= 100 || !isNaN(input)
? createSketchGrid(input)
: alert('Please enter a valid number less than or equal to 100.');
}
// Event listener to create tiles in mouseover
function setTiles(e) {
e.target.classList.add('fill');
}
// function deleteTiles(e) {
// e.target.classList.toggle('fill');
// }
container.addEventListener('mousedown', function () {
penDown = true;
});
container.addEventListener('mouseup', function () {
penDown = false;
});
// Create the grid
function createSketchGrid(tiles) {
let gridSize = tiles * tiles;
for (let i = 0; i < gridSize; i++) {
let tile = document.createElement('div');
tile.style.width = wdt;
tile.style.height = hgt;
grid.appendChild(tile);
// tile.addEventListener('mouseover', setTiles, false);
if ((penDown === true)) {
tile.addEventListener('mousemove', setTiles);
}
}
}
userInput.addEventListener('click', getUserInput);
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 10px;
}
h1 {
font-size: 3rem;
}
.grid {
/* font-size: 1.6rem; */
display: flex;
flex-wrap: wrap;
gap: 0.1em;
border: 2px solid black;
background-color: lightgrey;
flex: 0 0 32em;
}
.fill {
flex-wrap: wrap;
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>Etch A Sketch</title>
<link rel="stylesheet" type="text/css" href="styles/style.css">
<script type="text/javascript" src="js/main.js" defer></script>
</head>
<body>
<h1 class="title">Etch A Sketch</h1>
<div id="container" class="container">
<button id="user-input" class="btn user-input" value="Grid Size">Grid Size</button>
<div id="grid" class="grid">
</div>
</div>
</body>
</html>

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>

image slider with javascript with next previous button

The general appearance of the program is as follows:
enter image description here
the details
In this exercise, we complete a simple slider. You must add the previous and next button in this event. The next or previous image should be displayed when the next or previous button is clicked. You can use the functions defined in the initial project.
When the slider is on the last image and the next button is clicked, the first image should be displayed and also when the first image of the previous button is clicked, the last image should be displayed.
Note: When an image is displayed, its opacity must be 1 and the rest of the images must be 0.
Notes
You are only allowed to make changes to the main.js file.
html code :
const sliderImages = [
"./images/image1.jpg",
"./images/image2.jpg",
"./images/image3.jpg",
"./images/image4.jpg",
];
const sliderDom = document.getElementById("slider");
let currentImage = 0;
function renderImages() {
sliderImages.forEach((image) => {
sliderDom.innerHTML += "<img src='" + image + "' />";
});
}
function clearImages() {
const images = document.getElementsByTagName("img");
for (let i = 0; i < images.length; i++) {
images[i].style.opacity = 0;
}
}
function showImage(image) {
clearImages();
document.getElementsByTagName("img")[image].style.opacity = 1;
}
function init() {
renderImages();
showImage(currentImage);
}
init();
let myBtn = document.querySelector("#prevButton");
myBtn.onclick = function() {
const newImage = (currentImage + 1) % sliderImages.length;
showImage(newImage);
}
let myBtn2 = document.querySelector("#nextButton");
myBtn2.onclick = function() {
const newImage = (currentImage + 1) % sliderImages.length;
showImage(newImage);
}
* {
margin: 0;
padding: 0;
}
button {
padding: 8px;
}
.container {
width: 500px;
margin: 20px auto;
}
#slider {
position: relative;
height: 400px;
margin-bottom: 20px;
}
#slider img {
width: 500px;
height: 400px;
position: absolute;
transition: all .5s;
}
.buttons {
display: flex;
justify-content: space-between;
}
<!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>Slider</title>
</head>
<body>
<div class="container">
<div id="slider"></div>
<div class="buttons">
<button id="prevButton"><</button>
<button id="nextButton">></button>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
var photos = ["images/img1.png", "images/img2.png", "images/img3.png", "images/img4.png"]
var imgTag = document.querySelector("img");
var count = 0;
function next(){
count++;
if(count >= photos.length){
count = 0;
imgTag.src = photos[count];
}else{
imgTag.src = photos[count];
}
}
function prev(){
count--;
if(count < 0){
count = photos.length -1;
imgTag.src = photos[count];
}else{
imgTag.src = photos[count];
}
}
<!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>Image Slider</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<button onclick="prev()">prev</button>
<img src="images/img1.png" alt="" style="width:500px; height: 400px;">
<button onclick="next()">Next</button>
<script src="script.js"></script>
</body>
</html>

Having problems to generate a random array and visualize it using <div> elements in VS Code?

I am a beginner at web dev and am trying to build a sorting visualizer.
I am unable to get the output for generating a visualization of a random array by using the (div)
element of html.
This is the code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>sorting visualizer</title>
<style>
/* *{
margin: 0;
padding: 0;
} */
#array_container{
position: absolute;
left: 100px;
right: 100px;
bottom: 100px;
height: 100%;
width: 100%;
/* margin-left: 50px;
margin-right: 50px; */
background-color: turquoise;
}
</style>
</head>
<body>
<script>
function random_array(min, max){
return Math.floor(Math.random() * (max - min)) + min;
function generate_array(){
var cont = document.getElementById("array_container");
var bar;
var arr = [];
for ( var i = 0; i < 100; i++){
arr.push(random_array(5, 1000));
bar = document.createElement("div");
bar.style = "height:"+arr[i]+";width:2px;margin:0 1px;background-color:pink;display:inline-block;";
cont.appendChild(bar);
}
}
}
</script>
<div id="array_container">
</div>
<button id="btn1" onclick="generate_array">generate</button>
</body>
</html>
please help me by finding the ERROR and also suggest me some other methods for visualizing array in a bar graph format.
A couple minor syntax bugs I found:
You're missing the parenthesis () at the end of your function name when you pass it to the generate button's onclick
The brackets around your functions were offset, which was causing errors
Your code isn't broken beyond those minor syntax bugs, the problem you're facing is that your generated divs aren't respecting the height you're passing them, because you didn't give them a height unit.
You need to specify a unit like px, otherwise the height will get thrown out and ignored.
Working example (You'll want to adjust some other styles if you want them to fit in your box):
function random_array(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
function generate_array() {
var cont = document.getElementById("array_container");
var bar;
var arr = [];
for (var i = 0; i < 100; i++) {
arr.push(random_array(5, 1000));
bar = document.createElement("div");
bar.style = "height:" + arr[i] + "px;width:2px;margin:0 1px;background-color:pink;display:inline-block;";
cont.appendChild(bar);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>sorting visualizer</title>
<style>
#array_container {
position: absolute;
left: 100px;
right: 100px;
bottom: 100px;
height: 100%;
width: 100%;
background-color: turquoise;
}
</style>
</head>
<body>
<div id="array_container"></div>
<button id="btn1" onclick="generate_array()">generate</button>
</body>
</html>

Categories

Resources