HTML BODY PART
<body>
<div class="main">
<img class="red" src="red.png" alt="">
<img class="blue" src="blue.png" alt="">
<img class="green" src="green.png" alt="">
<img class="yellow" src="yellow.png" alt="">
<div class="btn">
<button class="play">Play</button>
<button class="restart">Restart</button>
</div>
</div>
</body>
</html>
JS PART
const play=document.querySelector(".play")
const restart=document.querySelector(".restart")
let items=['red','blue','green','yellow']
let sequence=[]
let generateRandomSequence=()=>{
let count=Math.trunc(Math.random()*4)
sequence.push(items[count])
console.log(sequence)
}
let makeColorBright=async (array)=>{
let second=()=>{
for(item of array){
console.log(item)
document.querySelector(`.${item}`).style.filter="brightness(2)"
setTimeout(()=>{
document.querySelector(`.${item}`).style.filter="brightness(1)"
},2000)
}
}
return second()
}
play.addEventListener("click",async function(){
generateRandomSequence()
await makeColorBright(sequence)
})
So the generateRandomSequence() function is working fine , and it adds random items in sequence everytime when I press play . My goal was to initially just see if I can make random blocks light up for which I've used sequence array. Now makeColorBright() will take inputs from sequence and the goal is to make a color light up and then wait 2 secs before it lights down , and then move onto next color. But the issue is it works fine for only one element in Sequence array. When there are 2 or more elements in sequence , all the colors light up simultaneously , but only the last element lights down after 2 secs.
You can change for(item of array){ to for (let item of array) { to narrow the scope of the item variable. However, even after fixing that, I don't think the script will work as expected since you call setTimeout in succession, without waiting.
There are a few ways to fix. Here's one that creates a timeout function using Promises.
(Note: I changed the images to divs and brightness to opacity to facilitate creating a code snippet).
const play = document.querySelector(".play");
const restart = document.querySelector(".restart");
let items = ['red', 'blue', 'green', 'yellow'];
let sequence = [];
let generateRandomSequence = () => {
let count = Math.trunc(Math.random() * 4);
sequence.push(items[count]);
}
// Sleep function
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
async function makeColorBright(array) {
for (let color of array) {
await wait(500)
.then(() => document.querySelector(`.${color}`).style.opacity = 1);
await wait(1500)
.then(() => document.querySelector(`.${color}`).style.opacity = .2);
}
}
play.addEventListener("click", async function() {
generateRandomSequence();
makeColorBright(sequence);
})
.box {
width: 50px;
height: 50px;
display: inline-block;
opacity: .2;
}
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
.yellow {
background-color: yellow;
}
<div class="main">
<div class="box red"></div>
<div class="box blue"></div>
<div class="box green"></div>
<div class="box yellow"></div>
<div class="btn">
<button class="play">Play</button>
<button class="restart">Restart</button>
</div>
</div>
I haven't used await/async very much, Johnny's answer may be better than my solution, but it triggers your lights in a timed succession like you wanted. You had a timeout on turning the lights off, but not when they turn on.
const play=document.querySelector(".play")
const restart=document.querySelector(".restart")
let items=['red','blue','green','yellow']
let sequence=[]
let generateRandomSequence=()=>{
let count=Math.trunc(Math.random()*4)
sequence.push(items[count])
console.log(sequence)
}
doThing = async(item, t)=>{
setTimeout(()=>{
document.querySelector(`.${item}`).style.filter="brightness(2)";
setTimeout(()=>{
document.querySelector(`.${item}`).style.filter="brightness(1)";
}, 1000);
}, t);
}
play.addEventListener("click",async function(){
generateRandomSequence()
let t = 0;
for(item of sequence){
doThing(item, t*1000);
t++;
}
})
img{width:50px;height:50px}
.red{background:red;}
.blue{background:blue;}
.green{background:green}
.yellow{background:yellow}
<div class="main">
<img class="red" src="red.png" alt="">
<img class="blue" src="blue.png" alt="">
<img class="green" src="green.png" alt="">
<img class="yellow" src="yellow.png" alt="">
<div class="btn">
<button class="play">Play</button>
<button class="restart">Restart</button>
</div>
</div>
I'm trying to build a function that changes background(color a), box(color b) and text color(color a) when a user clicks on the refresh button. I've set the color array, but couldn't figure out how to loop the array properly. Could anyone please help?
var colors = [
["#808080", "#f08080"],
["#2f4f4f", "#cdcdc1"],
["#F3E4C3", "#191970"],
["#DD5C3D", "#495496"],
["#ffbdbd", "#bdffff"],
["#c9c9ff", "#282833"],
["#fff5ee", "#4682b4"]]
I think I can do something like this below:
$("#refresh").click(function(){
$("box").animate({
backgroundColor: colors[0][1],
}, 500);
$("box").css("color", colors[0][0]);
$("background").animate({
backgroundColor: colors[0][0],
}, 500);
//add something that triggers loop here
});
And my html below:
<body>
<section id="main" class="box" style="margin-bottom: 10px">
<div id="city"></div>
<div id="detail"></div>
<div id="icon"></div>
<div id="temperature"></div>
<div id="fcicon" class="inrow">
<div id="f">F</div><div style="opacity: 0.5">/</div><div id="c">C</div>
</div>
<div id="refresh"><i class="fa fa-refresh"></i></div>
</section>
I don't think you need a loop. Try the code below. However i would recommend you to make separate css classes and toggle between them.
var colors = [["#808080", "#f08080"],
["#2f4f4f", "#cdcdc1"],
["#F3E4C3", "#191970"],
["#DD5C3D", "#495496"],
["#ffbdbd", "#bdffff"],
["#c9c9ff", "#282833"],
["#fff5ee", "#4682b4"]];
$(document).on(function(){
var i=0;
$("#refresh").click(function(){
if(colors.length==i+1){
i=0;
}else{
i=i+1;
$("box").animate({
backgroundColor: colors[i][1],
}, 500);
$("section").animate({
backgroundColor: colors[i][0],
}, 500);
$("background").animate({
backgroundColor: colors[i][0],
}, 500);
});
}
});
Edited my example to use your HTML, works great. I changed the class from .container to .box, as that's what you're using.
Here it is as a fiddle, in case.
// Array of color pairs that we'll use for background
// colors, text colors and border colors.
var colors = [
["#808080", "#f08080"],
["#2f4f4f", "#cdcdc1"],
["#F3E4C3", "#191970"],
["#DD5C3D", "#495496"],
["#ffbdbd", "#bdffff"],
["#c9c9ff", "#282833"],
["#fff5ee", "#4682b4"]
];
// The counter refers to which pair in the array we're
// currently referencing.
var counter = 0;
// When the refresh div gets clicked,
$("#refresh").click(function() {
// check the counter and increment or reset it.
if (counter >= colors.length - 1) {
counter = 0;
} else {
counter++
}
// Now, we want to animate CSS attributes on the
// container object. We'll use the color pair
// we're currently pointing to for the background
// text and border colors.
$(".box").animate({
backgroundColor: colors[counter][1],
color: colors[counter][0],
borderColor: colors[counter][0]
}, 500);
});
.box {
position: relative;
border: 1px solid blue;
height: 200px;
width: 200px;
}
.box #city {
font-weight: bolder;
font-size: 14px;
}
#refresh {
position: absolute;
bottom: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<section id="main" class="box" style="margin-bottom: 10px">
<div id="city">Worcester, MA</div>
<div id="detail"></div>
<div id="icon"></div>
<div id="temperature"></div>
<div id="fcicon" class="inrow">
<div id="f">F</div><div style="opacity: 0.5">/</div><div id="c">C</div>
</div>
<div id="refresh"><i class="fa fa-refresh"></i></div>
</section>
Added comments to make it a bit easier to follow.
you can simply keep track of the index by creating a closure.
function looper(){
let i = 0;
return function(){
$("box").animate({
backgroundColor: colors[i][1],
}, 500);
$("section").animate({
backgroundColor: colors[i][0],
}, 500);
$("background").animate({
backgroundColor: colors[i][0],
}, 500);
i++;
if(i === colors.length){
i = 0;
}
}
}
let change = looper();
now you can listen for the event and call the function "change" accordingly.
So I would store the value in the element via data(). Makes it really easy and reusable. Take a moment and read Decoupling Your HTML, CSS, and JavaScript.
The following code is reusable and extensible. Reusable by allowing multiple buttons to have different targets to refresh. Extensible by allowing you to add as many items to the animate as you want. Honestly I'd just put the color in the js-refresh button so each refresh button can have it's own array.
$(document).ready(()=>{
var colors = [
["#808080", "#f08080"],
["#2f4f4f", "#cdcdc1"],
["#F3E4C3", "#191970"],
["#DD5C3D", "#495496"],
["#ffbdbd", "#bdffff"],
["#c9c9ff", "#282833"],
["#fff5ee", "#4682b4"]];
$(".js-refresh").on('click', (e) => {
var $this = $(e.currentTarget);
var selector = $this.data('refresh-target');
$(selector).each((i,e)=>{
var $this = $(e);
var idx = $this.data('js-refresh-index') || 1;
idx = idx >= colors.length ? 1 : idx + 1;
$this
.data('js-refresh-index', idx)
.stop()
.animate({
backgroundColor: colors[idx-1][0],
}, 1)
.animate({
backgroundColor: colors[idx-1][1],
}, 500);
})
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script
src="https://code.jquery.com/color/jquery.color-2.1.2.min.js"
integrity="sha256-H28SdxWrZ387Ldn0qogCzFiUDDxfPiNIyJX7BECQkDE="
crossorigin="anonymous"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<section id="main" class="box" style="margin-bottom: 10px">
<div id="city"></div>
<div id="detail"></div>
<div id="icon"></div>
<div id="temperature" class="refresh-1">Temp</div>
<div id="fcicon" class="inrow">
<div id="f">F</div><div style="opacity: 0.5">/</div><div id="c">C</div>
</div>
<div class="js-refresh" data-refresh-target=".refresh-1">
<i class="fa fa-refresh"></i>
</div>
</section>
JQuery Animate from their docs
Animation Properties and Values
All animated properties should be animated to a single numeric value, except as noted below; most properties that are non-numeric cannot be animated using basic jQuery functionality (For example, width, height, or left can be animated but background-color cannot be, unless the jQuery.Color plugin is used). Property values are treated as a number of pixels unless otherwise specified. The units em and % can be specified where applicable.
My Html and JavaScript
<!DOCTYPE html>
<html>
<head>
<title>Animate</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<div class="row">
<select id="colors">
<option value="BlueWhite">Background: Blue, Color: White</option>
<option value="YellowBlue">Background: Yellow, Color: Blue</option>
<option value="WhiteRed">Background: White, Color: Red</option>
<option value="BlackWhite">Background: Black, Color: White</option>
</select>
<div id="main" class="box" style="margin-bottom: 10px">
<div id="city"></div>
<div id="detail"></div>
<div id="icon"></div>
<div id="temperature"></div>
<div id="fcicon" class="inrow">
<div id="f">F</div><div style="opacity: 0.5">/</div><div id="c">C</div>
</div>
</div>
<button id="refresh" class="btn btn-primary"><i class="fa fa-refresh"></i></button>
</div>
<script>
$(document).ready(function () {
var colors = {
"BlueWhite": {
"Background": "#0000ff",
"Color": "#ffffff"
},
"YellowBlue": {
"Background": "#FFFF00",
"Color": "#0000ff"
},
"WhiteRed": {
"Background": "#ffffff",
"Color": "#ff0000"
},
"BlackWhite": {
"Background": "#000000",
"Color": "#ffffff"
}
};
$("#refresh").click(function () {
var selected = $("#colors").val();
var colorObj;
if(colors[selected] != undefined) {
colorObj = colors[selected];
} else {
colorObj = colors["BlackWhite"];
}
$("#main").animate({
backgroundColor: colorObj.Background,
color: colorObj.Color
}, function () {
$(this).css("backgroundColor", colorObj.Background).css("color", colorObj.Color);
});
});
});
</script>
</body>
</html>
I have repeating elements (section) on a page. I want to iterate the background colors of the elements between three colors that are held in a array. And within some of those elements I have text (p) that I want to iterate through those same colors, except I want it to be the next color in the array as the background.
So if I have an array that looks like ["111111", "222222", "333333"], I want the background color of the first section to be #111111 and the color of the first p to be #222222. Also there are more elements on the page than there are items in the array so we need to loop back through the array. The page when complete should look like:
<body>
<section style="background-color: #111111;">
<p style="color: #222222;">foo bar</p>
</section>
<section" style="background-color: #222222;">
<p style="color: #333333;">foo bar</p>
</section>
<section style="background-color: #333333;">
<!--no p in this one-->
</section>
<section style="background-color: #111111;">
<p style="color: #222222;">foo bar</p>
</section>
</body>
I have the background-color part done but I can't figure out how to shift to the next item in the array and start over at the first item when necessary.
var bgColors = ["111111", "222222", "333333"];
$('section').each(function(i) {
var bgColor = bgColors[i % bgColors.length];
$(this).css('background-color', '#'+bgColor);
// How to do text color???
$(this).find("p").css('color', ???);
});
The script should be flexible so you can add and change colors. Thanks.
EDIT: I realized I left out an important point which is that not every section has a p so you can't just iterate through them each independently. Also due to a c&p mishap my html didn't match my JS. Apologies.
Just use i+1 for the modulo for the foreground
It is the same logic you already apply for the bgColor, you just need to go one more for the foreground
var bgColors = ["red", "green", "blue", "yellow"];
$(function() {
$('.section').each(function(i) {
var bgColor = bgColors[i % bgColors.length];
var fgColor = bgColors[(i + 1) % bgColors.length];
$(this).css('background-color', bgColor);
$(this).find(".text").css('color', fgColor);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
You can have a logic like
var bgColorIndex = i % bgColors.length;
var bgColor = bgColors[i % bgColors.length];
$(this).css('background-color', '#'+bgColor);
var fgColor = bgColorIndex + 1 === bgColors.length ? bgColors[0] : bgColors[bgColorIndex + 1];
$(this).find("p").css('color', fgColor);
It checks if the next index is equal to the length, set the color to the first item, otherwise set to the next color by incrementing.
Code example
var bgColors = ['red', 'blue', 'green', 'yellow'];
$(document).ready(function() {
$('.section').each(function(i) {
var bgColorIndex = i % bgColors.length;
var bgColor = bgColors[i % bgColors.length];
$(this).css('background-color', bgColor);
var fgColor = bgColorIndex + 1 === bgColors.length ? bgColors[0] : bgColors[bgColorIndex + 1];
$(this).find(".text").css('color', fgColor);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
</body>
Do you specifically need to do this in JavaScript for some reason, or would a pure CSS solution be preferable? Because you can achieve the same effect with :nth-child():
.section:nth-child(3n+1) {
background-color: #111;
}
.section:nth-child(3n+1) .text {
color: #222;
}
.section:nth-child(3n+2) {
background-color: #222;
}
.section:nth-child(3n+2) .text {
color: #333;
}
.section:nth-child(3n+3) {
background-color: #333;
}
.section:nth-child(3n+3) .text {
color: #111;
}
More performant, no FOUC, works for people with JavaScript disabled, etc.
Codepen: https://codepen.io/anon/pen/aLyOwJ
Here is jsfiddle of raw code and the result should be like this
<div class="wrapper">
<div class="row">
<div class="col red">R</div>
<div class="col blue">B</div>
<div class="col green">G</div>
<div class="col orange">O</div>
</div>
</div>
The mission is: Last color of previous row should be the first in next row and first color from previuos row should be the second in next row.
I think that I have to use loop and recursion but I don't have enough knowledge to do this.
Thanks in advance :)
You can run through the for loop and do something like this
check this snippet
//last color of previous row should be first in next row
//first color from previous row should be second in next row
var colors = ['red', 'blue', 'green', 'orange'];
$(document).ready(function() {
var rows = $('.row');
rows.each(function(row) {
var index = $(this).index();
var prevRow;
if (index > 0)
prevRow = $(this).prev();
colorColumns($(this).find('.col'), prevRow);
});
});
function colorColumns(cols, prevRow) {
var index = 0;
// alert("hi");
cols.each(function(col) {
var colIndex = $(this).index();
if (prevRow) {
var cols = prevRow.find('.col').length;
var totalCols = cols - 1;
var currentIndex = ((colIndex + totalCols) % cols);
var prevRowColor = $(prevRow).find('.col').eq(currentIndex);
var classes = prevRowColor.attr('class');
var classArr = classes.split(" ");
$(this).addClass(classArr[1]);
} else {
$(this).addClass(colors[colIndex]);
}
});
}
.row {
display: flex;
}
.row .col {
width: 20px;
height: 20px;
border-radius: 100%;
text-align: center;
}
.red {
background: red;
}
.orange {
background: orange;
}
.blue {
background: blue;
}
.green {
background: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="row">
<div class="col">R</div>
<div class="col">B</div>
<div class="col">G</div>
<div class="col">O</div>
</div>
<div class="row">
<div class="col">R</div>
<div class="col">B</div>
<div class="col">G</div>
<div class="col">О</div>
</div>
<div class="row">
<div class="col">R</div>
<div class="col">B</div>
<div class="col">G</div>
<div class="col">O</div>
</div>
Hope it helps
I have an element that contains multiple elements inside it, what I need is to clone the element, but on every "new" element, I need to increment an element (the object number -see my script please-)
In the script I'm adding I need (every time I click on the button) to have : Hello#1 (by default it's the first one) but the first click make : Hello#2 (and keep on top Hello#1) second click = Hello#1 Hello#2 Hello#3 ... We need to keep the oldest hellos and show the first one.
var count = 1;
$(".button").click(function(){
count += 1;
num = parseInt($(".object span").text());
$(".object span").text(count);
var cont = $(".container"),
div = cont.find(".object").eq(0).clone();
cont.append(div);
});
.object{
width:100px;
height:20px;
background-color: gold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<button type="button" class="button">
create object
</button>
<div class="container">
<div class="object">
<p>
hello#<span>1</span>
</p>
</div>
</div>
You just have to change a little:
var count = 1;
$(".button").click(function() {
count += 1;
num = parseInt($(".object span").text());
var cont = $(".container"),
div = cont.find(".object").eq(0).clone();
div.find('span').text(count); // <------here you have to put the count
cont.append(div);
});
.object {
width: 100px;
height: 20px;
background-color: gold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<button type="button" class="button">
create object
</button>
<div class="container">
<div class="object">
<p>
hello#<span>1</span>
</p>
</div>
</div>
and if you want to simplify this more use this:
$(".button").click(function() {
var idx = ++$('.object').length; // check for length and increment it with ++
var cont = $(".container"),
div = cont.find(".object").eq(0).clone();
div.find('span').text(idx); // <------here you have to put the count
cont.append(div);
});
.object {
width: 100px;
height: 20px;
background-color: gold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<button type="button" class="button">
create object
</button>
<div class="container">
<div class="object">
<p>
hello#<span>1</span>
</p>
</div>
</div>
Use the following function, this is more modular and you can use it to update the count if you remove one of the elements
function updateCount() {
$(".object").each(function(i,v) {
$(this).find("span").text(i+1);
});
}
$(".button").click(function() {
num = parseInt($(".object span").text());
var cont = $(".container"),
div = cont.find(".object").eq(0).clone();
cont.append(div);
updateCount();
});
.object {
width: 100px;
height: 20px;
background-color: gold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<button type="button" class="button">
create object
</button>
<div class="container">
<div class="object">
<p>
hello#<span>1</span>
</p>
</div>
</div>