how to create an automatic traffic light sequence in javascript - javascript

Hi I'm relatively new to JavaScript and I'm attempting to create a traffic light sequence that runs automatically, the code I currently have only works on click, if anyone can help me make this automatic, that'd be great.
<!DOCTYPE html>
<html>
<body>
<img id="Change Lights" src="red.gif" width="36" height="98">
<br><button onclick="nxt()" id="button">Change colour</button></br>
<script>
var img = new Array("red.gif","redamber.gif","green.gif","yellow.gif");
var imgElement = document.getElementById("Change Lights");
var lights = 0;
var imgLen = img.length;
function nxt()
{
if(lights < imgLen-1)
{
lights++;
}
else{
lights=0;
}
imgElement.src = img[lights];
}
</script>
</body>
</html>

A similar question was posted yesterday, but I thought I'd chip in with an answer here.
JavaScript
var timeIndex = 0;
var lightIndex = 0;
var timer;
var trafficLight = document.getElementById('light');
var lights = [
{
duration: 5,
color: 'red',
image: 'red.gif'
},
{
duration: 4,
color: 'green',
image: 'green.gif'
},
{
duration: 1,
color: 'yellow',
image: 'yellow.gif'
}
]
function advanceTrafficLightTimer() {
timeIndex++;
if(timeIndex == lights[lightIndex].duration) {
timeIndex = 0;
lightIndex = lightIndex < lights.length - 1 ? lightIndex = lightIndex + 1 : 0;
trafficLight.src = lights[lightIndex].image;
trafficLight.className = lights[lightIndex].color;
}
}
timer = setInterval(advanceTrafficLightTimer,1000);
CSS
.red { border: 3px solid #f00; }
.green { border: 3px solid #0f0; }
.yellow { border: 3px solid #ff0; }
HTML
<img id="light" class="red" src="red.gif">
The JS works by updating the timeIndex every second, and checking a variable lightIndex against the available traffic light objects stored in the array trafficLight. If the timeIndex has reached the duration of the current trafficLight, it will update the lightIndex to the next object in the array and change the image.
You can see it working here: https://jsfiddle.net/igor_9000/a2w9g8qa/3/
This seems to be a homework problem (nothing wrong with posting questions about homework). I've left out the redamber color, hopefully adding that in gives you a little bit of practice with the homework.
Hope that helps!

Related

Looping through array of colors infinite amount of times

I have a button with a default background color(black). I want to change the background color (from an array) of this button when hovering over it. I have it working at a fundamental level, but I want it to repeat the loop over and over.
this is what i have so far.
var color = ['#3e50a2', '#faa51a', '#ed1c24', '#2a9446'];
var i = -1;
document.querySelector('.customBtn').addEventListener('mouseover', function() {
i = 1 < color.length ? ++i : 0;
document.querySelector('.customBtn').style.background = color[i]
});
document.querySelector('.customBtn').addEventListener('mouseout', function() {
document.querySelector('.customBtn').style.background = '#000';
})
<a class="customBtn">Button</a>
I think you tried to reset the value of i with this i = 1 < color.length ? ++i : 0; but it doesn't. This will continuously increase the value never resetting it because 1 is always less than the length of the array.
I think you meant to increment the value and then reset if it's too big:
i = ++i < color.length ? i : 0;
Here's the complete code. I've refactored the query selector as there's no point to doing it more than once, and changed the mouseout background colour so you can read the button
var color = ['#3e50a2', '#faa51a', '#ed1c24', '#2a9446'];
var i = -1,
btn = document.querySelector('.customBtn');
btn.addEventListener('mouseover', function() {
i = ++i < color.length ? i : 0;
btn.style.background = color[i];
});
btn.addEventListener('mouseout', function() {
// revert to default colour
btn.style.background = '';
})
<input type="button" class="customBtn" value="My button" />
Just replace i = 1 < color.length ? ++i : 0; with i = (i+1 < color.length) ? ++i : 0;. That's all.
var color = ['#3e50a2', '#faa51a', '#ed1c24', '#2a9446'];
var i = -1;
document.querySelector('.customBtn').addEventListener('mouseover', function() {
i = (i+1 < color.length) ? ++i : 0;
document.querySelector('.customBtn').style.background = color[i]
});
document.querySelector('.customBtn').addEventListener('mouseout', function() {
document.querySelector('.customBtn').style.background = '#000';
})
<a class="customBtn">Button</a>
If you must use javascript, take a look at the second example.
Pure CSS solution
You could accomplish this with a CSS animation, which would be both more efficient and less error prone. Unless there's a specific reason you need to use javascript here I'd strongly recommend this approach.
This example could be modified to do hard transitions instead of fading from one color to the next, but here's a quick demo:
button {
background: black;
color: white;
border: none;
padding: 0.5em 1em;
}
button:hover {
animation: buttonhover 1s infinite;
}
#keyframes buttonhover {
0% {
background: #3e50a2;
}
25% {
background: #faa51a;
}
50% {
background: #ed1c24;
}
75% {
background: #2a9446;
}
}
<button>Hello</button>
Javascript Solution
If you must use javascript for whatever reason, you can use the % operator to keep from running off the end of the colors array:
const colors = ['#3e50a2', '#faa51a', '#ed1c24', '#2a9446'];
let index = 0;
let interval;
const hover = (e) => {
interval = setInterval(() => {
e.target.style.backgroundColor = colors[index];
index = (index + 1) % colors.length;
}, 300);
}
document.querySelector('button').addEventListener('mouseover', hover);
document.querySelector('button').addEventListener('mouseout', (e) => {
clearInterval(interval);
e.target.style.backgroundColor = 'black';
});
button {
background: black;
color: white;
border: none;
padding: 0.5em 1em;
}
<button>Hello</button>

Where is my setting and calling of a shuffle array function going wrong?

I'm able to loop a function to display 5 random images. Now I want to use the same 5 images and shuffle them, where each image appears only once (giving 5! = 120 permutations).
I've found plenty of tips on how to shuffle and display random numbers (not images), but where I think my issue is is setting and then calling functions. How do I do that?
Assumptions:
Between my <style> tags I need to define my shuffle function
My array of images can remain as it is (since it's the same ones, clearly making sure to update any changed references form the new URL)
The shuffle function gets called in the body of my page (I'm not sure about this bit)
In simple English I'm trying to achieve:
"Take the five images in the collection and put them, once only, into any order."
What happens:
Five images appear, often images are repeated.
The successful webpage has this:
</style>
<script type="text/javascript">
// place your images in this array
var random_images_array = ['Weare.jpg', 'Always.jpg', 'There.jpg', 'For.jpg', 'You.jpg'];
function getRandomImage(imgAr, path) {
path = path || '../Public/images/'; // default path here
var num = Math.floor( Math.random() * imgAr.length );
var img = imgAr[ num ];
var imgStr = '<img src="' + path + img + '" alt = "">';
document.write(imgStr); document.close();
}
</script>
</head>
<body>
And then this (which is, I assume the calling of the function)
<div>
<!-- This script segment displays an image from the array -->
<script type="text/javascript">for (i = 0; i < 5; i++) getRandomImage(random_images_array, 'images/')</script>
</div>
How can I fix this?
The following shuffles an array of image URLs, and then adds those URLs as images to the DOM, one by one.
const $ = document.querySelector.bind(document)
function shuffle(arr) {
for (let curr = arr.length - 1; curr >= 0; --curr) {
const random = ~~(Math.random() * curr)
;[arr[random], arr[curr]] = [arr[curr], arr[random]]
}
return arr
}
function render(arr) {
let html = "";
for (let el of arr) {
html += img`${el}`
}
$("#images").innerHTML = html
}
function img(_, url) {
return `<img style="background:url(${url}); background-size:cover;"/>`
}
const arr = [
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX//wCKxvRFAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg==",
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUA/wA0XsCoAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg==",
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/AAAZ4gk3AAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg==",
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAP+KeNJXAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg=="
]
$("button").addEventListener("click", () => render(shuffle(arr)))
render(shuffle(arr))
body {
font-family: sans-serif;
font-size: 0;
}
img {
display: inline-block;
width: 170px;
height: 60px;
box-shadow: 0 0 0 2px white inset;
padding: 0;
margin: 0;
}
button:focus { outline: none }
button {
font-size: 1rem;
border: none;
background: rgb(0, 200, 200);
border-radius: 5px;
cursor: pointer;
line-height: 40px;
height: 40px;
width: 340px;
padding: 0;
margin: 0;
color: white;
-webkit-user-select: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
box-shadow: 0 0 0 2px white inset;
}
#images {
box-shadow: 0 0 0 2px silver inset;
width:340px;
height:120px;
}
<button>Shuffle!</button>
<section id="images"></section>
A kind commenter who deleted their answer gave me the following:
var random_images_array = ['Weare.jpg', 'Always.jpg', 'There.jpg', 'For.jpg', 'You.jpg'];
function shuffleArray(arr) {
for (var i = arr.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// Shuffle images here
shuffleArray(random_images_array);
function getRandomImage(imgAr, path) {
path = path || '../Public/images/'; // default path here
for (var i = 0; i < imgAr.length; i++) {
var img = imgAr[i];
var imgStr = '<img src="' + path + img + '" alt = "">';
document.write(imgStr);
document.close();
}
}
getRandomImage(random_images_array, 'images/')
And it worked! Thank you, mystery helper!

trying to understand "Simon" game

I'm Working on Simon game. I need help with understanding how to reference an id and creating an action without a click but say with page refresh.
1) on screen refresh (the start of the game), I CAN randomize the color id chosen...and save it in a var called randomColorChosen... but I can NOT figure out how to make that var randomColorChosen, make the same actions as if they were a clicked on button like my code at the bottom.
2) My btn click and animate color and play sound... work fine,
I have tried many iterations of my newbie coding...
Now I'm just guessing and here is it's last state....
... random Color Chosen works... its what's next I need help (explanations on)
... $(document).keydown(function(event) {} works and tested with an alert()
... but the rest, down until my but clicks, I have changed so many times my head is spinning. Help my understand where I am dumb AF! lol
... user btn click event action and sound... works fine!
Here is my code so far:
buttonColors=["btn green","btn red", "btn yellow", "btn blue"];
randomColorChosen=buttonColors[Math.floor(Math.random() * (buttonColors.length))];
$(document).keydown(function(event) {
setTimeout(2000);
$("#id").attr(function(randomColorChosen){
$(this).fadeOut(100).fadeIn(100);
var myPadColor = $(this).attr("#id");
});
});
$(document).ready(function() {
$(".btn").click(function(event) {
$(this).fadeOut(100).fadeIn(100);//when a "this" button is clicked .fadeOut(100).fadeIn(100);
var myPadColor = $(this).attr("class");
;
switch (myPadColor) {
case "btn green":
var greenPad = new Audio('sounds/green.mp3');
greenPad.play();
break;
case "btn red":
var redPad = new Audio('sounds/red.mp3');
redPad.play();
break;
case "btn yellow":
var yellowPad = new Audio('sounds/yellow.mp3');
yellowPad.play();
break;
case "btn blue":
var bluePad = new Audio('sounds/blue.mp3');
bluePad.play();
break;
default:
console.log(myPadColor);
}
});
});
It was a little unclear what you are trying to accomplish. I created an example with some possible improved code.
$(function() {
var seq = [];
var player = [];
var c;
var round = 0;
var sounds = [
new Audio('sounds/green.mp3'),
new Audio('sounds/red.mp3'),
new Audio('sounds/yellow.mp3'),
new Audio('sounds/blue.mp3')
];
function getRandom() {
return Math.floor(Math.random() * 4);
}
function initSeq(n) {
for (var i = 0; i < n; i++) {
seq.push(getRandom());
}
}
function flash(b) {
//console.log("Flashing Button " + b);
var btn = $("#game-board .btn").eq(b);
btn.fadeTo(300, 1.0, function() {
btn.fadeTo(300, 0.35);
});
sounds[b].play();
}
function endGame() {
$("#game-board").hide();
$("h1").show();
$("h1").after("<h2>Gome Over. Score: " + player.length + "</h2>");
}
function waitUserInput() {
c = setInterval(endGame, 10 * 1000);
}
function playSequence(x) {
if (x == 0 || x == undefined) {
x = 20;
}
$.each(seq, function(i, s) {
if (i < x) {
flash(s);
}
});
}
function nextRound() {
playSequence(++round);
}
function initGame() {
initSeq(20);
player = [];
c = null;
round = 0;
nextRound();
}
$(document).keydown(function(event) {
$("h1").hide();
$("#game-board").show();
initGame();
});
$("#game-board .btn").click(function(event) {
var i = $(this).index();
flash(i);
player.push(i);
});
$("#playSeq").click(function() {
var p = $(this).next().val();
console.log("TEST: Play Sequence to " + p + " Position.");
if (seq.length == 0) {
initSeq(20);
$("#game-board").show();
}
//console.log("TEST", seq);
playSequence(p);
});
});
#game-board {
width: 410px;
white-space: normal;
}
.btn {
width: 200px;
height: 200px;
display: inline-block;
opacity: 0.35;
padding: 0;
margin: 0;
border: 0;
}
.green {
background: green;
border-radius: 199px 0 0 0;
}
.red {
border: 0;
background: red;
border-radius: 0 199px 0 0;
}
.yellow {
border: 0;
background: yellow;
opacity: 0.65;
border-radius: 0 0 0 199px;
}
.blue {
border: 0;
background: blue;
opacity: 0.65;
border-radius: 0 0 199px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="test-bar">
<button id="playSeq">Play To</button> <input type="number" value="1" style="width: 2.5em;" />
</div>
<h1>Press Any Key to Begin.</h1>
<div id="game-board" style="display: none;">
<div class="btn green"></div>
<div class="btn red"></div>
<div class="btn yellow"></div>
<div class="btn blue"></div>
</div>

Quickly change css attributes values?

I have sample code:
<div></div>
<button>
Go
</button>
div {
width: 50px;
height: 50px;
border: 1px solid #ccc;
}
var bgs = ['red', 'blue', 'yellow', 'green', 'black'];
$('button').click(function() {
for (var i = 0; i < bgs.length; i++) {
$('div').css('background-color', bgs[i]);
}
});
https://jsfiddle.net/e4jhwtyc/2/
What I want to achieve is that when users click the Go button, users will be able to see the background very quickly changing from red, blue, yellow, green, and then black.
But what I got was just black color when the Go button was clicked.
Am I missing something?
You need to set some timeout to see change in color otherwise it will happen too quickly.
var bgs = ['red', 'blue', 'yellow', 'green', 'black'];
$('button').click(function() {
for (var i = 0; i < bgs.length; i++) {
setTimeout(function(){
$('div').css('background-color','').css('background-color', bgs[i]);
}, 1000);
}
});
You can use setInterval() to change color on some period of time (0.3s for example) otherwise it will change instantly with your code. And when it reaches last element of array you can clearInterval() and reset counter i
var bgs = ['red', 'blue', 'yellow', 'green', 'black'];
var i = 0;
$('button').click(function() {
var x = setInterval(function() {
if (i < bgs.length) {
$('div').css('background-color', bgs[i++]);
} else {
clearInterval(x);
i = 0;
}
}, 300)
});
div {
width: 50px;
height: 50px;
border: 1px solid #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<button>
Go
</button>
Every time there is a click event the for ends at black color. So it gets black!!!. The for is to fast if you compare that with browser rendering so the other colors don't get rendered.
Try the setTimeout() function with a different offset for each color
This version does not deal with "setTimeout" and "setInterval"
var bgs = ['red', 'blue', 'yellow', 'green', 'black'];
function *getBgs(){
for(let v of bgs) {
yield v;
}
}
$('button').click(function() {
let iter = getBgs();
let $div = $('div');
var delay = 150;
var prev = 0;
(function nextColor(){
requestAnimationFrame(function(t){
if(prev && t - prev < delay) {
return nextColor();
}
prev = t;
let next = iter.next();
if(next.done) return;
$div.css('background-color', next.value);
nextColor();
});
})();
});
div {
width: 50px;
height: 50px;
border: 1px solid #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<button>
Go
</button>

Pause or Delay a loop on a array in a setInterval()

I want the color of the box I have created to change every 0.5 seconds, I have stored the colors in an array and I want the color to change every .5 seconds but it changes all at once.
<style type="text/css">
#box{
width: 100px;
height: 100px;
background: green;
}
</style>
</head>
<body>
<div id="box"></div>
<script type="text/javascript">
var colors = ['red','blue','green','violet','purple'];
var box = document.getElementById('box');
setInterval(function(){
for(var i=0; i < colors.length; i++){
box.style.backgroundColor=colors[i];
}
}, 300);
</script>
Depending on whether you want the box to continue changing after it has been through all the colours, there are a number of ways to solve this:
/*
Keeps running
*/
var colors = ['red','blue','green','violet','purple'],
i = 0;
setInterval(function () {
box.style.backgroundColor = colors[i++ % colors.length];
}, 500);
/*
Runs once only
*/
var colorsOnce = colors.slice(),
interval = setInterval(function () {
once.style.backgroundColor = colorsOnce.shift();
if(!colorsOnce.length) clearInterval(interval);
}, 500);
.box{
width: 100px;
height: 100px;
background: green;
}
<div id="box" class="box"></div>
<div id="once" class="box"></div>
Note: Despite these examples, where timing functions are involved best practice is generally to use a timeout as described by #AmmarCSE above.
You are looping inside the interval callback, which means that it will go through all the colors each interval.
Make the interval be the loop instead, i.e. go one step furter for each interval. Example:
var index = 0;
setInterval(function(){
box.style.backgroundColor = colors[index];
index = (index + 1) % colors.length;
},300);
Demo:
var colors = ['red','blue','green','violet','purple'];
var box = document.getElementById('box');
var index = 0;
setInterval(function(){
box.style.backgroundColor = colors[index];
index = (index + 1) % colors.length;
},300);
#box{
width: 100px;
height: 100px;
background: green;
}
<div id="box"></div>
Note: To actually get an interval that runs every 0.5 seconds, you should use 500 instead of 300 in the setInterval call.
Use setTimeout()
var colors = ['red', 'blue', 'green', 'violet', 'purple'];
var box = document.getElementById('box');
for (var i = 0; i < colors.length; i++) {
(function(index) {
setTimeout(function() {
console.log(index);
box.style.backgroundColor = colors[index];
}, 300 * i);
})(i)
}
#box {
width: 100px;
height: 100px;
background: green;
}
<div id="box"></div>
Two key points you missed in your code
Half a second is "500 milliseconds". So you need to change from 300 ms to 500ms in setInteval.
When the timer kicks in, you need to update the background color with the "next color in the array".
So you may try something like:
var color = 0;
var colors = ['red','blue','green','violet','purple'];
function nextColor(){
color ++;
if (color>=colors.length)
color = 0;
return colors[color];
}
setInterval(function(){
box.style.backgroundColor = nextColor();
},500);
This will keep the box changes its color every half a second and cycle through the color array endlessly.

Categories

Resources