This is my first time posting and I'm also very new to javascript. I've had this problem for days and have tried various solutions but none have worked.
I have two buttons - one etch, and one for draw - where I want the etch button to apply a mouseover event to boxes in a div. I want to the draw button to apply a click event in the boxes in the div.
I also have a black button, a color button, and a rainbow button.
I have my code working to where the active class gets added when a button is clicked. Both sets of buttons are in their own containers so that I can have two active classes at the same time.
What I'm struggling to make happen, is when etch is active and black is active, it runs a mouseover event that changes the background of the div boxes to black. Or, when etch is active and color is active, the background color is changed to whatever the value is in the color picker, etc. When draw is active, it has a click event that hold black, color, or whatever is on the active class draw buttons.
I already have functions that hold the colors to change the background, I just can't seem to implement everything else.
I only have access to JavaScript, not jQuery. Any advice would b greatly appreciated.
const grid = document.getElementById('grid');
const slider = document.getElementById('sizeSlider');
let gridValue = document.getElementById('slider-value');
let gridSize = document.querySelector('input');
const container = document.getElementById('container');
let colorPicker = document.getElementById('color-picker');
const toggleBtn = document.getElementById('toggle');
const applyGridSize = document.getElementById('apply');
const resetBtn = document.getElementById('reset');
const etchBtn = document.getElementById('etch');
const drawBtn = document.getElementById('draw');
const eraserBtn = document.getElementById('eraser');
const resetGridBtn = document.getElementById('reset-grid');
const blackBtn = document.getElementById('black-btn');
const colorBtn = document.getElementById('color-btn');
const rainbowBtn = document.getElementById('rainbow-btn');
const drawModeBtns = document.querySelectorAll('.draw-mode-btn');
const colorModeBtns = document.querySelectorAll('.color-mode-btn');
//function to get slider value
function showValue(x) {
document.getElementById('slider-value').textContent = `Grid Size: ${x} x ${x}`;
}
gridSize.addEventListener('input', function (e) {
squareSize = e.target.value;
gridValue.textContent = `Grid Size: ${squareSize}x${squareSize}`;
});
// function to create grid
function createGrid(col, rows) {
for (let i = 0; i < (col * rows); i++) {
const div = document.createElement('div');
grid.style.gridTemplateColumns = `repeat(${col}, 1fr)`;
grid.style.gridTemplateRows = `repeat(${rows}, 1fr)`;
grid.appendChild(div).classList.add('box');
}
}
// make 16x16 grid when window loads
window.onload = createGrid(slider.value, slider.value);
// modify grid size
function modifyGridSize() {
let boxes = grid.querySelectorAll(".box");
boxes.forEach(box => box.remove());
createGrid(slider.value, slider.value);
}
// change grid size with slider and apply button
applyGridSize.addEventListener('click', modifyGridSize);
// reset and clear grid to 16x16 when reset button is clicked
resetBtn.addEventListener('click', () => {
let boxes = grid.querySelectorAll(".box");
boxes.forEach(box => box.remove());
createGrid(16, 16);
slider.value = 16;
gridValue.textContent = `Grid Size: 16 x 16`;
})
// clear grid only when button is clicked
resetGridBtn.addEventListener('click', () => {
let boxes = grid.querySelectorAll('.box');
boxes.forEach(box => box.style.backgroundColor = 'white');
})
// function to toggle lines on and off with button
toggleBtn.addEventListener('click', () => {
let boxes = grid.querySelectorAll('.box');
boxes.forEach(box => box.classList.toggle('toggle-lines'));
})
// add active class when a draw button is clicked
drawModeBtns.forEach(btn => {
btn.addEventListener('click', (e) => {
drawModeBtns.forEach(f => f.classList.remove('active'));
e.target.classList.toggle('active');
});
});
colorModeBtns.forEach(btn => {
btn.addEventListener('click', (e) => {
colorModeBtns.forEach(f => f.classList.remove('active'));
e.target.classList.toggle('active');
});
});
// background color change function for box divs in grid
function blackBackground() {
this.style.backgroundColor = 'black';
}
// background color erase function
function eraseBackground() {
this.style.backgroundColor = 'white';
}
eraserBtn.addEventListener('click', eraseBackground);
// random rainbow color background color function
function rainbowColor() {
const randomR = Math.floor(Math.random() * 256);
const randomG = Math.floor(Math.random() * 256);
const randomB = Math.floor(Math.random() * 256);
this.style.backgroundColor = `rgb(${randomR}, ${randomG}, ${randomB})`;
// return `rgb(${randomR}, ${randomG}, ${randomB})`;
}
// random color background color function
function colorBackground() {
this.style.backgroundColor = changeColor();
}
// function to change background color to color picker input
function changeColor() {
colorPicker.addEventListener('change', (e) => {
let color = e.target.value;
let boxes = grid.querySelectorAll('.box');
boxes.forEach(box => {
box.removeEventListener('mouseover', blackBackground);
box.addEventListener('click', () => {
box.style.backgroundColor = color;
})
})
})
}
And here's the HTML that goes with it:
<h1>Etch-a-Sketch</h1>
<button id="reset">Reset All</button>
<button id="reset-grid">Reset Grid</button>
<br><br>
<div id="container"></div>
<div id="gridSize"></div>
<div class="slider">
<label for="range"></label>
<span id="slider-value" style="color: black;">Grid Size: 16 x 16</span>
<br>
2 <input type="range" name="range" id="sizeSlider" step="1" value="16" min="2" max="100"
onchange="showValue(this.value);"> 100
<button id="apply">Apply</button>
</div>
<br>
<form name="draw-mode" class="draw-mode">
<input type="button" value="Etch-a-Sketch Mode" id="etch" class="draw-mode-btn">
<input type="button" value="Pixel Drawing Mode" id="draw" class="draw-mode-btn">
</form>
<br>
<form name="color-mode" class="color-mode">
<input type="button" value="Black" id="black-btn" class="color-mode-btn">
<input type="button" value="Color" id="color-btn" class="color-mode-btn">
<input type="button" value="Rainbow" id="rainbow-btn" class="color-mode-btn">
</form>
<br>
<div>
<input type="color" id="color-picker" name="color" value="" data-name="color-picker">
</div>
<br>
<div>
<button id="eraser" class="btn">Eraser</button>
</div>
<br>
<div class="toggle-lines">
<button id="toggle">Toggle Lines On/Off</button>
</div>
<br>
<div id="grid" class="toggle-lines"></div>
<br><br>
<script src="./javascript.js"></script>
Screenshot of my page:
Create a state object that holds the interesting values - and gives back what you want:
drawState
is the state object _mode
: "click" or "mouseover" (click or etch)_colorMode
_colorMode
it has a ruleset to always give back a color that you want ( get color()
gives back either a color from the color picker, a random color, white (for eraser) or blackThis way you can get rid of a lot of unnecessary functions.
(The data-drawval
custom attributes on the HTML elements are also used!)
const grid = document.getElementById('grid'); const slider = document.getElementById('sizeSlider'); let gridValue = document.getElementById('slider-value'); let gridSize = document.querySelector('input'); const container = document.getElementById('container'); let colorPicker = document.getElementById('color-picker'); const toggleBtn = document.getElementById('toggle'); const applyGridSize = document.getElementById('apply'); const resetBtn = document.getElementById('reset'); const etchBtn = document.getElementById('etch'); const drawBtn = document.getElementById('draw'); const eraserBtn = document.getElementById('eraser'); const resetGridBtn = document.getElementById('reset-grid'); const blackBtn = document.getElementById('black-btn'); const colorBtn = document.getElementById('color-btn'); const rainbowBtn = document.getElementById('rainbow-btn'); const drawModeBtns = document.querySelectorAll('.draw-mode-btn'); const colorModeBtns = document.querySelectorAll('.color-mode-btn'); const BOX_DIMENSION = 10 const initDrawState = () => { let _mode = "mouseover" let _colorMode = "black" return { get mode() { return _mode }, set mode(value) { _mode = value }, get color() { if (this.colorMode === "rainbow") { return rainbowColor() } else if (this.colorMode === "color") { return colorPicker.value } else if (this.colorMode === "eraser") { return "white" } else { return "black" } }, get colorMode() { return _colorMode }, set colorMode(value) { _colorMode = value } } } const drawState = initDrawState() //function to get slider value function showValue(x) { document.getElementById('slider-value').textContent = `Grid Size: ${x} x ${x}`; } gridSize.addEventListener('input', function(e) { squareSize = e.target.value; gridValue.textContent = `Grid Size: ${squareSize}x${squareSize}`; }); // function to create grid function createGrid(col, rows) { grid.style.height = rows * BOX_DIMENSION + "px" grid.style.width = col * BOX_DIMENSION + "px" for (let i = 0; i < (col * rows); i++) { const div = document.createElement('div'); grid.style.gridTemplateColumns = `repeat(${col}, 1fr)`; grid.style.gridTemplateRows = `repeat(${rows}, 1fr)`; grid.appendChild(div).classList.add('box'); } } const boxEventListener = (e) => { e.target.style.backgroundColor = drawState.color } const setBoxesEventListener = (boxes) => { boxes.forEach(box => { box.addEventListener(drawState.mode, boxEventListener) }) } const removeBoxesEventListener = (boxes) => { boxes.forEach(box => { box.removeEventListener("mouseover", boxEventListener) box.removeEventListener("click", boxEventListener) }) } const changeBoxesEventListener = () => { const boxes = grid.querySelectorAll(".box") removeBoxesEventListener(boxes) setBoxesEventListener(boxes) } // make 16x16 grid when window loads window.onload = modifyGridSize() // modify grid size function modifyGridSize() { grid.innerHTML = "" createGrid(slider.value, slider.value); changeBoxesEventListener() } // change grid size with slider and apply button applyGridSize.addEventListener('click', modifyGridSize); // reset and clear grid to 16x16 when reset button is clicked resetBtn.addEventListener('click', () => { let boxes = grid.querySelectorAll(".box"); boxes.forEach(box => box.remove()); createGrid(16, 16); slider.value = 16; gridValue.textContent = `Grid Size: 16 x 16`; changeBoxesEventListener() }) // clear grid only when button is clicked resetGridBtn.addEventListener('click', () => { let boxes = grid.querySelectorAll('.box'); boxes.forEach(box => box.style.backgroundColor = 'white'); }) // function to toggle lines on and off with button toggleBtn.addEventListener('click', () => { let boxes = grid.querySelectorAll('.box'); boxes.forEach(box => box.classList.toggle('toggle-lines')); }) // add active class when a draw button is clicked drawModeBtns.forEach(btn => { btn.addEventListener('click', (e) => { drawModeBtns.forEach(f => f.classList.remove('active')); e.target.classList.toggle('active'); drawState.mode = e.target.getAttribute("data-drawval") changeBoxesEventListener() }); }); colorModeBtns.forEach(btn => { btn.addEventListener('click', (e) => { colorModeBtns.forEach(f => f.classList.remove('active')); e.target.classList.toggle('active'); drawState.colorMode = e.target.getAttribute("data-drawval") }); }); // random rainbow color background color function function rainbowColor() { const randomR = Math.floor(Math.random() * 256); const randomG = Math.floor(Math.random() * 256); const randomB = Math.floor(Math.random() * 256); // this.style.backgroundColor = `rgb(${randomR}, ${randomG}, ${randomB})`; return `rgb(${randomR}, ${randomG}, ${randomB})` }
.draw-mode-btn.active { background: purple; color: white; } .color-mode-btn.active { background: purple; color: white; } .box { border: 1px solid black; background: white; box-sizing: border-box; } #grid>.box.toggle-lines { border: 1px solid white; } #grid { display: grid; }
<h1>Etch-a-Sketch</h1> <button id="reset">Reset All</button> <button id="reset-grid">Reset Grid</button> <br><br> <div id="container"></div> <div id="gridSize"></div> <div class="slider"> <label for="range"></label> <span id="slider-value" style="color: black;">Grid Size: 16 x 16</span> <br> 2 <input type="range" name="range" id="sizeSlider" step="1" value="16" min="2" max="100" onchange="showValue(this.value);"> 100 <button id="apply">Apply</button> </div> <br> <form name="draw-mode" class="draw-mode"> <input type="button" value="Etch-a-Sketch Mode" id="etch" class="draw-mode-btn active" data-drawval="mouseover"> <input type="button" value="Pixel Drawing Mode" id="draw" class="draw-mode-btn" data-drawval="click"> </form> <br> <form name="color-mode" class="color-mode"> <input type="button" value="Black" id="black-btn" class="color-mode-btn active" data-drawval="black"> <input type="button" value="Color" id="color-btn" class="color-mode-btn" data-drawval="color"> <input type="button" value="Rainbow" id="rainbow-btn" class="color-mode-btn" data-drawval="rainbow"> </form> <br> <div> <input type="color" id="color-picker" name="color" value="" data-name="color-picker"> </div> <br> <div> <button id="eraser" class="btn color-mode-btn" data-drawval="eraser">Eraser</button> </div> <br> <div class="toggle-lines"> <button id="toggle">Toggle Lines On/Off</button> </div> <br> <div id="grid" class="toggle-lines"></div> <br><br>
The code could be simplified even further, but then some other basic ideas should have been updated - and it was not clear from the description if those can be changed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.