New to javascript. I am writing this website and I want to randomly change the color of the logo periodically whilst the mouse hovers over it. So it goes color1, then waits x milliseconds, then color2 and so on until the mouse is not hovering over it anymore. So far I am only able to change the logo to one randomly chosen color. Furthermore I think the way I am using 'mouseover' and 'mouseout' seems pretty confusing and inefficient, is there a better way to use them?
My code (I've left only the essentials)
!DOCTYPE html>
<html lang="en">
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<link href="styles.css" rel="stylesheet">
<title>My Webpage</title>
<script>
document.addEventListener('DOMContentLoaded', function listen() {
var logo = document.querySelector('.logo-btn');
logo.addEventListener("mouseover", event => setTimeout(changeColor(event), 500));
logo.addEventListener("mouseout", event => resetColor(event));
})
function changeColor (event) {
var colors = ["#ff3300", "#fbfb32", "#99ff33", "orange", "magenta", "#3399ff"]
var color = colors[Math.floor(Math.random() * colors.length)];
var logo = event.target;
logo.style.color = color;
}
function resetColor (event) {
var logo = event.target;
logo.style.color = "black";
}
</script>
</head>
<body>
<header>
<div class="header-logo">
<a href="x">
<button class="logo-btn">Logo</button>
</a>
</div>
</body>
</html>
header {
background-color: #fff;
height: 80px;
position: relative;
}
.header-logo {
font-size: 50px;
position: absolute;
bottom: -15px;
left: 40px;
}
.logo-btn {
background-color: transparent;
border: none;
text-align: bottom;
}
```
Thank you very much!
You had done it pretty much right. All you needed was to use setInterval instead of setTimeout. Also, you need to store the interval in a variable and clear it on mouseout so that the text does not keep changing the color.
let interval;
document.addEventListener('DOMContentLoaded', function listen() {
var logo = document.querySelector('.logo-btn');
logo.addEventListener("mouseover", event => {interval = setInterval(()=>changeColor(event), 500)});
logo.addEventListener("mouseout", event => resetColor(event));
})
function changeColor(event) {
var colors = ["#ff3300", "#fbfb32", "#99ff33", "orange", "magenta", "#3399ff"]
var color = colors[Math.floor(Math.random() * colors.length)];
var logo = event.target;
logo.style.color = color;
}
function resetColor(event) {
var logo = event.target;
logo.style.color = "black";
clearInterval(interval);
}
header {
background-color: #fff;
height: 80px;
position: relative;
}
.header-logo {
font-size: 50px;
position: absolute;
bottom: -15px;
left: 40px;
}
.logo-btn {
background-color: transparent;
border: none;
text-align: bottom;
}
<!DOCTYPE html>
<html lang="en">
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<link href="styles.css" rel="stylesheet">
<title>My Webpage</title>
</head>
<body>
<header>
<div class="header-logo">
<a href="x">
<button class="logo-btn">Logo</button>
</a>
</div>
</header>
</body>
</html>
A recursive function can be a solution for your problem.
You set mouseOver variable on 1 when mouse is over, and on 0 when mouse is out.
You also call setColor on mouseover and check if mouse is over with mouseOver flag.
Now you call setColor that set a new color every time it's called based on selected variable
var logo = document.querySelector('.logo-btn');
logo.addEventListener("mouseover", event => {setColor(event); mouseOver = 1});
logo.addEventListener("mouseout", event => resetColor(event));
var colors = ["#ff3300", "#fbfb32", "#99ff33", "orange", "magenta", "#3399ff"],
selected = 0,
mouseOver = 0
function setColor(e){
e.target.style.backgroundColor = colors[selected]
if(mouseOver){
setTimeout(function(){
if(colors.length > selected + 1){
selected = 0
}
else{
selected ++
}
setColor(e)
}, 500)
}
}
function resetColor(event){
selected = 0
mouseOver = 0
e.target.style.backgroundColor = colors[selected]
}
It should be like this...
let colors = [1,2,3],
element = document.querySelector('whatever-your-logo'),
colorIndex = 0;
function changeColor(){
//set color
element.style.color = colors[colorIndex];
//change to next color
colorIndex++;
// if it's last color then back to first colorIndex
if(colorIndex >= colors.length-1) colorIndex = 0;
}
//Interval
let priod = 1000; //in ms
let interval = setInterval(changeColor, priod);
//done...
Related
sorry its a bit of a confusing question.
I am working on a Javascript problem that has multiple parts, i believe i solved all of them except for the last step:
Every time i press "Click Me" button, my background color, color's name and background color of the "click me" button changes randomly using an array of colors. It also creates a square (its a div via .innerHTML in JS). I want to add another function, when i click the "click me" button, i would like to keep adding more boxes and each box that is added inherits the same background color as the at the time of the click. As i keep pressing the button, those squares stay with their background colors, and new ones continue to be created with the with the changing background.
I apologize if the description is confusing and thank you so much for your time!
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 id="bgcolor">
<h1>Background Color : <span id="color">Red</span></h1>
</div>
<button id="click">click me</button>
<div id="squares"></div>
<script src="index.js"></script>
</body>
</html>
CSS
* {
margin: 0;
padding: 0;
}
body {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 100px;
}
h1 {
font-size: 100px;
color: white;
}
button {
padding: .5em 1.5em;
font-size: 60px;
border: 7px solid black ;
border-radius: 10px;
font-weight: 700;
}
#bgcolor {
background-color: black;
padding: 1.5em 2em;
border-radius: 30px;
}
#squares {
display: flex;
flex-wrap: wrap;
}
#test {
width: 150px;
height: 150px;
background-color: blue;
border: 3px solid white;
}
Javascript
const colorChange = document.querySelector('#color');
const click = document.querySelector('#click');
const squares = document.querySelector('#squares');
let cubes = [];
const defaultBackground = 'lightgray';
// Set default background color and color name to uppger case when the page loads
document.body.style.backgroundColor = defaultBackground;
colorChange.textContent = defaultBackground[0].toUpperCase() + defaultBackground.substring(1);
colorChange.style.color = defaultBackground;
click.style.backgroundColor = defaultBackground;
// Colors
const colors = ["red", "beige", "burlywood", "coral", "aqua", "darkcyan", "pink", "lawngreen", "fuchsia"];
click.addEventListener('click', function samecolor() {
// Random Color Selector
const ranColor = colors[Math.floor(Math.random() * colors.length)];
// If statement to ensure that some color does not repeat two times in a row.
// Statement reads if background color already displayed doesn't equal to the random color selected, then display
// that color. Do the same for color name and button background.
if (document.body.style.backgroundColor != ranColor
&& colorChange.style.color != ranColor
&& click.style.backgroundColor != ranColor) {
document.body.style.backgroundColor = ranColor;
colorChange.style.color = ranColor;
click.style.backgroundColor = ranColor;
// If all the conditions above are met, also display the name of the random color selected with upper case first letter.
colorChange.textContent = ranColor[0].toUpperCase() + ranColor.substr(1);
} else {
samecolor()
}
function work() {
squares.innerHTML += `<div id="test"> </div>`
document.getElementById('test').style.backgroundColor = ranColor;
}
work()
})
Here is the solution in a playground: playground
const colorChange = document.querySelector("#color");
const click = document.querySelector("#click");
const squares = document.querySelector("#squares");
let cubes = [];
const defaultBackground = "lightgray";
// Set default background color and color name to uppger case when the page loads
document.body.style.backgroundColor = defaultBackground;
colorChange.textContent =
defaultBackground[0].toUpperCase() + defaultBackground.substring(1);
colorChange.style.color = defaultBackground;
click.style.backgroundColor = defaultBackground;
// Colors
const colors = [
"red",
"beige",
"burlywood",
"coral",
"aqua",
"darkcyan",
"pink",
"lawngreen",
"fuchsia"
];
let currentColor = null;
function changeColor() {
// Random Color Selector
const ranColor = colors[Math.floor(Math.random() * colors.length)];
// If color is the same as the previous one, it calls itself again
if (currentColor === ranColor) {
changeColor();
return;
}
// Sets the current color so that we don't repeat it
currentColor = ranColor;
// Change the colors
document.body.style.backgroundColor = ranColor;
colorChange.style.color = ranColor;
click.style.backgroundColor = ranColor;
colorChange.textContent = ranColor[0].toUpperCase() + ranColor.substr(1);
// Add a square with that color
const newSquare = document.createElement("div");
newSquare.style.backgroundColor = ranColor;
newSquare.className = "test";
squares.append(newSquare);
}
click.addEventListener("click", changeColor);
Some points worth mentioning:
In CSS, if you have an ID #test it should only be on the page once, otherwise it's best to use a classname. I've changed your #test to .test
I simplified your if statement with a variable currentColor.
I have written this code to get the squares of a grid to change their background color to black upon a mouseover event. It works when the page initially loads, but if I create a new grid the mouseover event no longer works.
I updated the original post with a snippet. Sorry I didn't do that from the beginning.
let number = 16;
makeGrid(number);
function makeGrid(number) {
for (let i=0; i < number; i++) {
for (let j=0; j < number; j++) {
const rows = document.createElement('div');
const container = document.getElementById('container')
rows.setAttribute('class', 'rows');
container.appendChild(rows);
}
}
container.style.gridTemplateColumns = `repeat(${number}, 1fr)`;
container.style.gridTemplateRows = `repeat(${number}, 1fr)`;
}
//create new grid with on button
let newGrid = document.getElementById('newGrid');
newGrid.addEventListener('click', () => {
let number = prompt('Enter a number');
let container = document.getElementById('container');
container.textContent = '';
makeGrid(number);
})
//change background color to black
let changeClass = document.querySelectorAll('.rows');
changeClass.forEach((item) => {
item.addEventListener('mouseover', e => {
item.style.backgroundColor = 'black';
})
})
body {
background-color: rgb(5, 51, 5) ;
}
#container {
margin: auto;
width: 500px;
height: 500px;
display: grid;
border-style: solid;
border-width: thin;
border-color: lightslategray;
background-color: white;
}
.rows{
}
.black { background-color: black;
}
#header {
text-align: center;
}
#button {
text-align: center;
}
#footer {
text-align: center;
}
#newGrid {
background-color: lightgray;
color: darkcyan;
font-size: 20px;
padding: 12px 28px;
border-radius: 0px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Etch-a-Sketch</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1 id='header'>Etch-a-Sketch</h1>
<br>
<div id='button'>
<button id='newGrid' class='button'>New Grid</button>
</div>
<br>
<br>
<div id='container'></div>
<br>
<footer id='footer'>Made by: Joe Maniaci</footer>
<script src="main.js"></script>
</body>
</html>
When you query the DOM with document.querySelectorAll('.rows') and add the event listeners, there is only one "grid" in the DOM at that time. When a "grid" is subsequently added to the DOM, as triggered by the user's click event, you must instantiate event listeners on the newly added DOM nodes too.
A way to avoid this problem and a better approach overall in your situation is to use delegated event listeners. For example:
document.addEventListener('mouseover', e=>{
if(e.target.matches(‘.myClickableItemClass’){
e.target.style.backgroundColor = 'black';
}
}
Learn more about event delegation here: https://medium.com/#bretdoucette/part-4-what-is-event-delegation-in-javascript-f5c8c0de2983
I want to make something that is like this:
http://www.lessmilk.com/imgtut/FB1/3.gif
But my square dosen't seem to bounce up properly (it should move up to a certain distance then fall back. Like that in example), especially when it is falling, it stops for in same position on first click and then requires second click to move up . What did I do wrong or is it not just tuned properly? Can it be done in some other way? Need help and suggestions.
Here is my code.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Bounce</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.container {
background-color: aqua;
height: 300px;
width: 500px;
position: relative;
}
.square {
height: 25px;
position: absolute;
width: 25px;
background-color: brown;
}
</style>
</head>
<body>
<div class="container" onclick="accelerateUp()">
<div class="square" style="top:0; left:20px"></div>
</div>
<script>
var square = document.querySelector('.square');
var updateInterval, gravitySpeed = 0, gravity = 0.05;
function accelerateUp() {
clearInterval(updateInterval)
gravity = -0.2;
setTimeout(() => { gravity = 0.05 }, 100)
updateInterval = setInterval(() => accelerateDown(), 5)
}
function accelerateDown() {
let topValue = parseInt(square.style.top);
let leftValue = parseInt(square.style.left);
gravitySpeed += gravity;
square.style.top = topValue + gravitySpeed + 'px';
hitBottom();
}
function hitBottom() {
if (parseInt(square.style.top) > 250 || parseInt(square.style.top) < 0) {
gravitySpeed = 0;
}
}
updateInterval = setInterval(() => accelerateDown(), 5);
</script>
</body>
</html>
Instead of having an "accelerateUp" you should just consider setting the velocity to a specific/set value on each click OR changing the velocity by a set amount.
I think part of the problem is trying to manage how the acceleration changes as a result of the click hitting the square up, and I think it's just easier to change the velocity and let the acceleration remain constant.
const square = document.querySelector('.square');
const frameRate = 60; // fps
const yAcceleration = .5; // change in px / frame
const hitUpForce = -10;
let yVelocity = 0; // px / frame
let yPosition = 0; // px
function timeStep() {
// velocity changes position
const willHitGround = yPosition + yVelocity > 275
yPosition = willHitGround ? 275 : yPosition + yVelocity;
// accerlation changes velocity
yVelocity = willHitGround ? 0 : yVelocity + yAcceleration;
square.style.top = `${yPosition}px`
}
function hitUp() {
// just set contant velocity as result of hit
yVelocity = hitUpForce; // Or possibly yVelocity += hitUpForce
}
updateInterval = setInterval(timeStep, 1000/frameRate);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Bounce</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.container {
background-color: aqua;
height: 300px;
width: 500px;
position: relative;
}
.square {
height: 25px;
position: absolute;
width: 25px;
background-color: brown;
}
</style>
</head>
<body>
<div class="container" onclick="hitUp()">
<div class="square" style="top:0; left:20px"></div>
</div>
</body>
</html>
Ok, I just figured it out that I have to reset the gravitySpeed variable to 0 on click (because when falling it's value is negative and that was stoping the ball from jumping on first click). So resetting the variable helped me. I posted the answer here so that it can help someone.
function accelerateUp() {
clearInterval(updateInterval);
gravitySpeed = 0;
gravity = -0.2;
setTimeout(() => { gravity = 0.05 }, 100)
updateInterval = setInterval(() => accelerateDown(), 5)
}
I know this question has been asked more than once, but the answers I have found don't seem to apply to my situation... I am very novice at JavaScript, and even more so at debugging it. I am trying to lean by working through an online tutorial, but when I tried the onclick event, everything appears to be null at first - the function is supposed to resize the canvas and place the image in the top left corner on the first click. What is does is resizes the canvas on the first click, then on the 3rd click, adds the image... Since I am not calling on the style or display (to my knowledge), and there are no conditional statements in the function, I'm not sure why this is happening. I also tried to link the function instead of inline as suggested by another post, but to no avail... I am using Chrome. Any input would be greatly appreciated!
HTML:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="js/main.js"></script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<canvas id="gameCanvas" onclick="changeCanvasSize(this);" width = "400" height = "300"></canvas>
</body>
</html>
js:
function changeCanvasSize()
{
var gameCanvas = document.getElementById("gameCanvas");
var avatarImage = new Image();
gameCanvas.width = 600;
gameCanvas.height = 800;
avatarImage.src = "img/avatar.png";
gameCanvas.getContext("2d").drawImage(avatarImage, 0, 0);
}
css:
body {
background: #ffffff;
text-align: center;
padding: 20px;
color: #575757;
font: 14px/21px Arial,Helvetica,sans-serif;
}
a {
color: #B93F14;
}
a:hover {
text-decoration: none;
}
ol {
width: 600px;
text-align: left;
margin: 15px auto
}
canvas {
border: 1px solid black;
}
you have to wait for the image to load before inserting it:
function changeCanvasSize()
{
var gameCanvas = document.getElementById("gameCanvas");
var avatarImage = new Image();
gameCanvas.width = 600;
gameCanvas.height = 800;
avatarImage.src = "img/avatar.png";
avatarImage.onload = function() {
gameCanvas.getContext("2d").drawImage(avatarImage, 0, 0);
}
}
Background:
I started Javascript the other day and built this sketch pad:
http://frankpeelen.github.io/sketch-pad/
following alongside the instructions on:
http://www.theodinproject.com/web-development-101/javascript-and-jquery
Problem:
It's basically finished, and works fine except for when creating a new grid with the "New" button. All of a sudden the 'squares' stop responding to 'hover' events. I've searched, but have been unable to find any similar problems. Any ideas?
Code:
$(document).ready(function() {
var build = function(h, w) {
var height = h;
var width = w;
//Loop through height to create rows
for (i = 1; i <= height; i++) {
$("#sketchpadcontainer").append("<div class='row'></div>");
//Loop through width to create divs in each row
for (j = 1; j <= width; j++) {
$(".row:last-child").append("<div class='sqrcontainer'><div class='square'></div></div>");
}
}
};
//Build default 16x16 grid
build(16, 16);
$("button").click(function() {
var size = parseInt(prompt("How many squares per side would you like? Please enter a number."));
//In case the number entered > 50
if (size > 50) {
$(".row").remove();
build(50, 50);
alert("The number you entered was too large. The number 50 has been used instead.")
}
//In case a non-number is entered
else if (isNaN(size)) {
$(".row").remove();
build(16, 16);
alert("You didn't enter a number. The default of 16 has been used.")
}
//In case a number <= 50 is entered
else {
$(".row").remove();
build(size, size);
}
})
$(".square").hover(
//Mouse in
function () {
$(this).css("background-color", "blue");
},
//Mouse out
function () {} );
});
html, body, #sitecontainer {
height: 100%;
width: 100%;
margin: 0px;
}
#sketchpadcontainer {
}
button {
display: block;
margin: 0 auto;
margin-top: 2em;
margin-bottom: 1em;
}
#sketchpadcontainer {
}
.row {
text-align: center;
}
.sqrcontainer {
height: 1.5em;
width: 1.5em;
display: inline-block;
}
.square {
width: 1em;
height: 1em;
margin: .1em;
border-color: black;
border-style: solid;
border-radius: .1em;
}
<!DOCTYPE html>
<head>
<title>Sketch Pad</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type='text/javascript' src="js/javascript.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="sitecontainer">
<div id="buttoncontainer">
<button type="button">New</button>
</div>
<div id="sketchpadcontainer">
</div>
</div>
</body>
You are deleting the divs before the build method. That means the hover listeners will be deleted to. You have to add them to the .sqare elements again.
Just move
$(".square").hover(
//Mouse in
function () {
$(this).css("background-color", "blue");
},
//Mouse out
function () {} );
inside your build method
change $(".square").hover(
to $(document).on("hover" ,".square", function(){ . . . })
Ur problem in $(".square").hover( - work after $(document).ready, but after u appending new rows - document ready dont triggering, and ur elements have not events, and trigger .on work on every elems on page, even on dynamically added.