I'm trying to practice my scripting by making a Battleship game. As seen here.
I'm currently trying to make the board 2D. I was able to make a for-loop in order to make the board, however, due to testing purposes, I'm just trying to make the board, upon clicking a square, it turns red... But, the bottom square always lights up. I tried to debug it by making the c value null, but then it just stops working. I know it's not saving the c value properly, but I'm wondering how to fix this.
Do I have to make 100 squares by my self or can I actually have the script do it?
maincansize = 400;
document.getElementById("Main-Canvas").style.height = maincansize;
document.getElementById("Main-Canvas").style.width = maincansize;
document.getElementById("Main-Canvas").style.position = "relative";
var ize = maincansize * .1;
for (var a = 0; a < 10; a++) {
for (var b = 0; b < 10; b++) {
var c = document.createElement("div");
var d = c;
c.onclick = function() {
myFunction()
};
function myFunction() {
console.log("A square was clicked..." + c.style.top); d.style.backgroundColor = "red";
}
c.style.height = ize;
c.style.width = ize;
c.style.left = b * ize;
c.style.top = a * ize;
c.style.borderColor = "green";
c.style.borderStyle = "outset";
c.style.position = "absolute";
console.log(ize);
document.getElementById('Main-Canvas').appendChild(c);
} //document.getElementById('Main-Canvas').innerHTML+="<br>";
}
#Main-Canvas {
background-color: #DDDDDD;
}
<div>
<div id="header"></div>
<script src="HeaderScript.js"></script>
</div>
<div id="Main-Canvas" style="height:400;width:400;">
</div>
Here's your code with some fixes:
adding 'px' to style assignment
passing the clicked element to myFunction
var maincansize = 400;
document.getElementById("Main-Canvas").style.height = maincansize;
document.getElementById("Main-Canvas").style.width = maincansize;
document.getElementById("Main-Canvas").style.position = "relative";
var ize = maincansize * .1;
for (var a = 0; a < 10; a++) {
for (var b = 0; b < 10; b++) {
var c = document.createElement("div");
c.onclick = function(ev) {
myFunction(ev.currentTarget);
};
function myFunction(el) {
console.log("A square was clicked...");
el.style.backgroundColor = "red";
}
c.style.height = ize+'px';
c.style.width = ize+'px';
c.style.left = (b * ize)+'px';
c.style.top = (a * ize)+'px';
c.style.borderColor = "green";
c.style.borderStyle = "outset";
c.style.position = "absolute";
document.getElementById('Main-Canvas').appendChild(c);
}
}
#Main-Canvas {
background-color: #DDDDDD;
}
<div id="Main-Canvas" style="height:400;width:400;">
</div>
Here's a solution with major revamps. Since you're using a set width for the container element of your board cells you can float the cells and they will wrap to the next line. Absolute positioning tends to be a bit of a bugger. If you want 10 items per row it's as easy as:
<container width> / <items per row> = <width>
Using document fragments is faster than appending each individual element one at a time to the actual DOM. Instead you append the elements to a document fragment that isn't a part of the DOM until you append it. This way you're doing a single insert for all the cells instead of 100.
I moved some of the styling to CSS, but could easily be moved back to JS if you really need to.
function onCellClick() {
this.style.backgroundColor = 'red';
console.log( 'selected' );
}
var main = document.getElementById( 'board' ),
frag = document.createDocumentFragment(),
i = 0,
len = 100;
for ( ; i < len; i++ ) {
div = document.createElement( 'div' );
div.addEventListener( 'click', onCellClick, false );
frag.appendChild( div );
}
main.appendChild( frag );
#board {
width: 500px;
height: 500px;
}
#board div {
float: left;
box-sizing: border-box;
width: 50px;
height: 50px;
border: 1px solid #ccc;
}
<div id="board"></div>
Related
I'm working on a drum machine and I am not sure how to approach making the squares clickable. How can I alter the color of a specific square to crimson upon being clicked?
const drums = ["Crash", "CHiHat", "OHiHat", "Tom3", "Tom2", "Tom1", "Snare", "Kick"];
for (let i = 0; i < 8; i++) {
for (let v = 0; v < 16; v++) {
var block = document.getElementById('canvas');
var context = block.getContext('2d');
context.strokeRect(100 + (55 * v), (55 * i), 50, 50);
context.fillStyle = 'crimson';
context.fillRect(100 + (55 * v), (55 * i), 50, 50);
}
}
<canvas id="canvas" width="1920" height="1080"></canvas>
I tried addEventListener, but that returned an error.
A canvas is just a grid of pixels. You can't assign a click handler to a canvas shape, because that shape is just some pixels. If you aren't restricted to using canvas, try using regular elements, like this:
var drumMachine = document.getElementById("drumMachine");
var nRows = 8;
var nCols = 16;
for (let i = 0; i < nRows; i++) {
var row = document.createElement("tr");
for (let j = 0; j < nCols; j++) {
let cell = document.createElement("td");
cell.className = "clickable";
cell.addEventListener("click", function () {
this.classList.toggle("activated");
});
row.appendChild(cell);
}
drumMachine.appendChild(row);
}
#drumMachine {
margin-left: 100px;
}
.clickable {
width: 50px;
height: 50px;
background-color: black;
cursor: pointer;
margin-right: 5px;
margin-bottom: 5px;
display: inline-block;
}
.clickable.activated {
background-color: crimson;
}
<table id="drumMachine"></table>
This does a few things.
First, it defines the grid dimensions and then creates the elements in a two-dimensional loop.
It then adds an click event listener to each element (here is where HTML elements shine against HTML canvas!)
After which, the elements are assembled into a regular table setup. CSS is used to mimic your canvas setup.
If you have any questions don't hesitate to ask in the comments.
Hers's question which I need answer
Exercises: Level 1
Question 1
I tried to append the child dynamically and get the result vertical not in the compact manner as you will see in the question output when you go to the link
let hh = document.querySelector('h1')
hh.style.textAlign = 'center'
let hh1 = document.querySelector('h2')
hh1.style.textAlign = 'center'
let hh2 = document.querySelector('h3')
hh2.style.textAlign = 'center'
for (i = 0; i <= 100; i++) {
let p1 = document.createElement('div');
{
if (i % 2 == 0) {
p1.className = 'Container'
p1.style.fontSize = '25px'
p1.style.backgroundColor = '#91E537'
p1.textContent = i;
p1.style.padding = '55px'
p1.style.margin = '1px'
p1.style.textAlign = 'center'
p1.style.width = '20px'
document.body.appendChild(p1);
} else {
p1.className = 'Container'
p1.style.fontSize = '25px'
p1.textContent = i;
p1.style.backgroundColor = '#E5D037'
p1.style.padding = '55px'
p1.style.margin = '1px'
p1.style.textAlign = 'center'
p1.style.width = '20px'
document.body.appendChild(p1);
}
}
if (i >= 2) {
let flag = 0;
for (j = 2; j <= i / 2; j++) {
if (i % j == 0) {
flag = 1;
break;
}
}
if (flag == 0) {
p1.className = 'Container'
p1.style.fontSize = '25px'
p1.style.backgroundColor = '#E55137'
p1.textContent = i;
p1.style.padding = '55px'
p1.style.margin = '1px'
p1.style.textAlign = 'center'
p1.style.width = '20px'
document.body.appendChild(p1);
}
}
}
<h1>Number Generator</h1>
<h2>30 days of JavaScript</h2>
<h3>Author:ABC</h3>
<div class="container"></div>
You can see the code of both HTML and javascript above!!!
Do help with the code where I can easily append the data, and don't use box elements I need simple code for this.
I tried to do it with a few HTML styles but it didn't help me, also using insert-adjacent text also didn't work.
Try to make changes only on javascript code, not HTML,if it's possible else make minimum changes on HTML
I am using HTML5 AND CSS3
Rather than adding lots of inline style attributes to all the generate elements some simple CSS can be applied to the parent (container) and thus the children and then use Javascript to assign the classes to the elements based upon the given criteria of odd/even & prime. The comments throughout the code ought to help
// helper function to create basic DOM element with attributes
const node=( type='div', attr={} )=>{
let n = document.createElement(type);
Object.keys( attr ).forEach( a=>n.setAttribute( a, attr[a] ) );
return n;
};
// utility to test if a number is a "Prime Number"
const isprime=( n=0 )=>{
for( let i = 2; i < n; i++ ) {
if( n % i === 0 ) return false;
}
return n > 1;
};
// generate between these numbers
const iStart=1;
const iEnd=100;
// HTML container
const results = document.querySelector('#results');
// iterate through number range and add new DIV for each number
for( let i = iStart; i<=iEnd; i++ ) {
// calculate the className to assign
let cn=i % 2 === 0 ? 'even' : 'odd';
if( isprime( i ) ) cn='prime';
// create the DIV
let div=node( 'div', { 'class':cn, 'data-id':i } );
// append to output container
results.appendChild( div );
}
// generate Page headers before results / output
let headers={
h1:'Number Generator',
h2:'30 days of Javascript',
h3:'Geronimo Bogtrotter III'
};
// iterate over the keys/properties of the object and create
// a new header for each using the value assigned within the object.
Object.keys( headers ).forEach( prop=>{
let n=node( prop );
n.textContent=headers[ prop ];
// add the new header before the numbers grid
document.body.insertBefore( n, results );
});
/*
Some simple variables to help with layout.
Change here to modify displayed grid.
*/
:root{
--width:600px;
--m:0.25rem;
--r:0.35rem;
--wh:calc( calc( var( --width ) / 5 ) - calc( var( --m ) * 4 ) );
}
body{
font-family:monospace;
padding:0;
margin:0;
}
#results {
width: var(--width);
min-height: var(--width);
float: none;
margin: 1rem auto;
font-family:fantasy;
}
#results > div {
width: var( --wh );
height: var( --wh );
border: 1px solid black;
border-radius:var(--r);
margin: var(--m);
display: inline-block;
cursor:pointer;
}
/*
Use the pseudo element :after to
display the number of the square.
This uses the `data-id` attribute
assigned within Javascript.
*/
#results>div:after {
display:flex;
flex-direction:column;
justify-content:center;
align-content:center;
align-items:center;
flex:1;
margin:auto;
content: attr(data-id);
color:black;
text-shadow:0 0 15px rgba(255,255,255,1);
height:100px;
}
/*
modify the display for certain colours
to aid clarity
*/
#results>div.odd:after{
text-shadow:0 0 15px rgba(0,0,0,1);
}
#results>div.prime:after{
text-shadow:0 0 15px rgba(0,0,0,1);
color:white;
}
/*
The basic 3 colours to suit the odd/even/prime
status of each square.
*/
.even {
background: green;
}
.odd {
background: yellow
}
.prime {
background: red
}
h1,h2,h3{
text-align:center;
}
<div id='results'></div>
The idea here is to create a container for all of the blocks and set the display style attribute of this container to flex, style.flewrap to wrap and you can control how many blocks you want per line using style.width attribute.
After creating this element you would want to append to it your dynamically created blocks like p2.appendchild(p1);
Here is the code :
let p2 = document.createElement('div');
p2.className= 'p2';
p2.style.display = 'flex';
p2.style.flexwrap = 'wrap';
p2.style.width = '800px'
for (i = 0; i <= 101; i++) {
...
for every document.body.append(p1); --> p2.append(p1);
...
}
document.body.appendChild(p2);
I am working on an Etch-A-Scetch project. I created grid which contains a certain amount of squares of the same size (the user is able to type in the amount of squares which should be displayed). To create the squares I used CSS grid and a Javascript for loop. Now I want to add event listeners, which change the background of each Square when moving over it. Unfortunately, it always shows errors when I try to add some. The current code doesn't show an error, it just doesn't do anything.
The method createSquares() should just create and add the amount of squares to the DOM. The user types in an amount, for example 10, and the displayed squares are 10 in x-direction and 10 in y-direction --> makes 100 squares in total. After that I want to add an event listener, which changes the background color of the square the user hovers over (the background color should stay changed). I am thankful for any help, because I'm really clueless :D
let squareDiv = document.querySelector('.squareDiv');
let squares = document.getElementById('#squares')
let squareAmount = 10;
function blackColor() {
this.style.backgroundColor = '#000';
this.style.border = '0px';
}
function createSquares() {
for (i = 0; i < squareAmount * squareAmount; i++) {
squares = document.createElement('div');
squares.setAttribute("id", "squares");
// squares.setAttribute("onmouseover", "addEventListener")
squares.style.display = 'grid';
squareDiv.style.setProperty('--columns-amount', squareAmount);
squareDiv.style.setProperty('--rows-amount', squareAmount);
squareDiv.appendChild(squares);
}
}
createSquares();
if (squares) {
squares.addEventListener('mouseover', _ => {
squares.style.backgroundColor = blackColor;
});
}
<div class="squareDiv"></div>
<div id="squares"></div>
You likely need something like this
I fixed the script, now fix the CSS
let container = document.getElementById("container")
let squareAmount = 5;
function getRandom() {
return '#'+Math.floor(Math.random()*16777215).toString(16);
}
function colorIt(sq) {
sq.style.backgroundColor = document.getElementById("random").checked? getRandom() : '#000';
sq.style.border = '0px';
}
function createSquares() {
let grid = document.createElement('div');
grid.setAttribute("id","squares")
grid.classList.add("grid");
for (i = 0; i < squareAmount * squareAmount; i++) {
square = document.createElement('div');
square.classList.add("square");
grid.appendChild(square);
}
container.innerHTML="";
container.appendChild(grid)
}
createSquares();
container.addEventListener('mouseover',
e => {
const target = e.target;
if (target.matches(".square")) colorIt(target)
}
);
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
grid-auto-rows: 1fr;
}
.grid::before {
content: '';
width: 0;
padding-bottom: 100%;
grid-row: 1 / 1;
grid-column: 1 / 1;
}
.grid > *:first-child {
grid-row: 1 / 1;
grid-column: 1 / 1;
}
/* Just to make the grid visible */
.grid > * {
background: rgba(0,0,0,0.1);
border: 1px white solid;
}
<label><input type="checkbox" id="random" />Random</label>
<div id="container"></div>
You have already created the element in DOM, please remove this.
while creating the element using function createSquares assign class instead of ID. Since, you should have only element with one ID.
Move the addEventListener inside the function after you have created the element.
When creating similar html elements with same properties it is better to group them together with class and not id. This is good because it becomes simple to loop these html elements with forEach or other looping methods you may prefer.
let squareDiv = document.querySelector('.squareDiv');
let squares = document.getElementById('#squares')
let squareAmount = 10;
function blackColor() {
this.style.backgroundColor = '#000';
this.style.border = '0px';
}
function createSquares() {
for (i = 0; i < squareAmount * squareAmount; i++) {
squares = document.createElement('div');
squares.setAttribute("class", "squares");
squares.setAttribute("style", "width: 100px; height: 100px; background: #090; margin-bottom: .3rem;");
// squares.setAttribute("onmouseover", "addEventListener")
squares.style.display = 'grid';
squareDiv.style.setProperty('--columns-amount', squareAmount);
squareDiv.style.setProperty('--rows-amount', squareAmount);
squareDiv.appendChild(squares);
}
}
createSquares();
if (squares) {
squares.addEventListener('mouseover', _ => {
squares.style.backgroundColor = blackColor;
});
}
<div class="squareDiv"></div>
<div id="squares"></div>
I have three div p, p1, p3 which is inside in div r having different height
I want to set all div inside the div r similar to the first div inside the r as per their classname using object:
var firstChild = document.querySelector(".r:first-child");
var descendant = firstChild.querySelectorAll(".p, .p2,.p3");
var p, p2, p3;
[].forEach.call(descendant, function(itm) {
itm.style.backgroundColor = "green";
var ch = document.getElementsByClassName("p");
for (var i = 0; i < ch.length; i++) {
var ar = ['p', 'p2', 'p3']; //are the class name
p = ch[i].parentNode.clientHeight / 1.5; // height value for p
p2 = ch[i].parentNode.clientHeight + p; // height value for p2
p3 = p2 / 1.5; // height value for p3
var colors = {}; //using dynamic
colors[ar[0]] = p;
colors[ar[1]] = p2;
colors[ar[2]] = p3;
ch[i].style.height = colors[ch[i].className] + "px"; //problem comes here this shows undefined
itm.style.height = ch[i].clientHeight + "px";
document.getElementById('demo').innerHTML = "asfaf";
}
});
.p,
.p2,
.p3 {
display: inline-block;
width: 80px;
border: 1px solid #999;
}
.p {
height: 50px;
}
p2 {
height: 100px;
}
p3 {
height: 150px;
}
<div>
<div class="r">
<div class="p">fgdsgs</div>
<div class="p2">sdgdfg</div>
<div class="p3">sdgdfg</div>
</div>
</div>
<p id="demo"></p>
as you've seen p, p1, p2has different value in javascript , i want to make all div in same height
example = if the first div inside r is p the make all div inside r will be according to their value described (ch[i].parentNode.clientHeight / 1.5 ) i javascript , similarly if the first div is p3 then all div(p, p2, p3) inside r will be get same height described in javascript which is p2/1.5
using dynamic propery object , whats the problem in my code ?
Demo = https://jsfiddle.net/m2gj5dt5/
What I would do is, I would get the largest height and set it to all the p tags.
var firstChild = document.querySelector(".r > :first-child");
var descendant = document.querySelectorAll(".p, .p2, .p3");
var p, p2, p3;
for (var el = 0; el < descendant.length; el++) {
debugger;
var itm = descendant[el];
itm.style.backgroundColor = "green";
debugger;
var ch = document.getElementsByClassName("p");
for (var i = 0; i < ch.length; i++) {
var ar = ['p', 'p2', 'p3'];
p = ch[i].parentNode.clientHeight / 1.5;
p2 = ch[i].parentNode.clientHeight + p;
p3 = p2 / 1.5;
var colors = {};
colors[ar[0]] = p;
colors[ar[1]] = p2;
colors[ar[2]] = p3;
debugger;
ch[i].style.height = colors[ch[i].className] + "px";
itm.style.height = ch[i].clientHeight + "px";
document.getElementById('demo').innerHTML = "asfaf";
}
}
.p, .p2, .p3 {
display: inline-block;
width: 80px;
border: 1px solid #999;
}
<div>
<div class="r">
<div class="p">fgdsgs</div>
<div class="p2">sdgdfg</div>
<div class="p3">sdgdfg</div>
</div>
</div>
<p id="demo"></p>
Also, you forgot the .s in the CSS for p2 and p3.
Fiddle: https://jsfiddle.net/qsj1444p/
On my previous post I asked how I'd get the gradient set up. Now the problem is that the gradient "spreads" out. Here's What I'm using
function generateCSSGradient(colours) {
var l = colours.length, i;
for( i=0; i<l; i++) colours[i] = colours[i].join(" ");
return "linear-gradient( to right, "+colours.join(", ")+")";
}
var cols = [
["red","0%"],
["red","40%"],
["yellow","40%"],
["yellow","60%"],
["green","60%"],
["green","80%"]
];
yourElement.style.background = generateCSSGradient(cols);
With this. What I want to do is say you fill in one input. And the bar goes to 33%, then that could be a red color. Then the next would be a blue and so fourth. Not like this. Any ideas? I'd also avoid using div
I think you want it like this ... See the source code
HTML
I'v edited the HTML code and added another div called colors inside the div top ...
<div class="top">
<div class="colors"></div>
</div>
CSS
Also I edited the CSS of .top and added to it overflow:hidden; and create .colors style
.top{
/*background: #009dff;*/
background:linear-gradient(to right,#009dff 0,#00c8ff 100%);
position:fixed;
z-index:1031;
top:0;
left:0;
height:4px;
transition:all 1s;
width:0;
overflow: hidden;
}
.colors{
width: 100%;
height: 4px;
}
JavsScript
Then edited the JavaScript and made the CSSGradient to colors not top , and let the JavaScript set the width of colors to fit the window width , and changed the colors percentage..
document.querySelector(".colors").style.background = generateCSSGradient(cols);
var window_width = window.innerWidth + "px";
document.querySelector(".colors").style.width = window_width;
var cols = [
["red","0%"],
["red","33.3%"],
["yellow","33.3%"],
["yellow","66.6%"],
["green","66.6%"],
["green","100%"]
];
Hope this will help you ...
Update
if you want to change the color of the bar like this , See the source code ...
just edit the JavaScript to be like this
function cback(e) {
var t = [];
for (var n = inputs.length; n--;) {
if (!inputs[n].value.length) t.push(inputs[n]);
}
var r = t.length;
var i = inputs.length;
var s = document.querySelectorAll(".top");
for (var o = s.length; o--;) {
s[o].style.width = 100 - r / i * 100 + "%";
s[o].style.background = cols[i-r-1];
}
}
var forms = document.querySelectorAll(".form"),
inputs = [];
for (var i = forms.length; i--;) {
var els = forms[i].querySelectorAll("input, textarea, select");
for (var j = els.length; j--;) {
if (els[j].type != "button" && els[j].type != "submit") {
inputs.push(els[j]);
els[j].addEventListener("input", cback, false);
}
}
}
var cols = ["red","yellow","green"];