Slider with Synchronized Navigation - javascript

Here is what I have created so far:
screenshot here
Basically you start off with the red div on the left with the red circle that is active on the right. When you click on the blue circle, for example, you get the div on the left to turn blue and then the blue circle gets active and the red circle gets inactive. Here is how it looks after clicking on the blue circle: screenshot here
And of course, if you click on the green circle the div on the left turns green if you click on the black circle the div on the left turns black.
Here is the code:
$(document).ready(function(){
$('#circle-2').click(function(){
$(this).addClass('active-circle')
$('#circle-1').removeClass('active-circle')
$('#circle-3').removeClass('active-circle')
$('#circle-4').removeClass('active-circle')
$('.rect').removeClass('rect-1').removeClass('rect-3').removeClass('rect-4').addClass('rect-2')
})
$('#circle-1').click(function(){
$(this).addClass('active-circle')
$('#circle-2').removeClass('active-circle')
$('#circle-3').removeClass('active-circle')
$('#circle-4').removeClass('active-circle')
$('.rect').removeClass('rect-2').removeClass('rect-3').removeClass('rect-4').addClass('rect-1')
})
$('#circle-3').click(function(){
$(this).addClass('active-circle')
$('#circle-1').removeClass('active-circle')
$('#circle-2').removeClass('active-circle')
$('#circle-4').removeClass('active-circle')
$('.rect').removeClass('rect-1').removeClass('rect-2').removeClass('rect-4').addClass('rect-3')
})
$('#circle-4').click(function(){
$(this).addClass('active-circle')
$('#circle-1').removeClass('active-circle')
$('#circle-2').removeClass('active-circle')
$('#circle-3').removeClass('active-circle')
$('.rect').removeClass('rect-1').removeClass('rect-2').removeClass('rect-3').addClass('rect-4')
})
})
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
}
.rect {
height: 50vh;
width: 100%;
}
.rect-1 {
background: red;
}
.rect-2 {
background: blue;
}
.rect-3 {
background: green;
}
.rect-4 {
background: black;
}
.circle {
height: 100px;
width: 100px;
border-radius: 50%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
opacity: .25;
}
.circle-color-1 {
background-color: red;
}
.circle-color-2 {
background-color: blue;
}
.circle-color-3 {
background-color: green;
}
.circle-color-4 {
background-color: black;
}
.active-circle {
opacity: 1;
}
<div class="grid">
<div class="rect rect-1">
</div>
<div class="circles-container">
<div id="circle-1" class="circle circle-color-1 active-circle">Circle 1</div>
<div id="circle-2" class="circle circle-color-2">Circle 2</div>
<div id="circle-3" class="circle circle-color-3">Circle 3</div>
<div id="circle-4" class="circle circle-color-4">Circle 4</div>
</div>
</div>
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous">
</script>
<script src="./index.js"></script>
Now here is where I am struggling. I want the div on the left to switch color automatically every 3 seconds and of course, the circles on the right should match that as well. So we start with the div on the left being red and the red circle on the right being active and after 3 seconds the div changes to blue and the active circle is the blue one. Basically what I have now but happening automatically without having to click on the circles and keeping the click functionality as well.

Your first priority, aside from achieving the automatic cycle through the elements, is to DRY up your code. Given that all that changes between the multiple repeated event handlers is the class you add, you can remove the id attributes and target the elements by their common .circle class. You can then bind a single event handler which works for all elements and applies the class to .rect which is stored in a data attribute on each element.
To create the cycle effect you can use setInterval(), targeting the next element from the one which currently has .active-circle. Try this:
jQuery($ => {
var $rect = $('.rect');
var $circles = $('.circle').on('click', setActiveCircle);
$circles.first().trigger('click');
function setActiveCircle() {
$circles.removeClass('active-circle');
$(this).addClass('active-circle');
$rect.removeClass('rect-1 rect-2 rect-3 rect-4').addClass($(this).data('rect'));
}
setInterval(function() {
let $targetCircle = $circles.filter('.active-circle').next();
if ($targetCircle.length === 0)
$targetCircle = $circles.first();
setActiveCircle.call($targetCircle);
}, 3000);
});
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
}
.rect {
height: 50vh;
width: 100%;
}
.rect-1 { background: red; }
.rect-2 { background: blue; }
.rect-3 { background: green; }
.rect-4 { background: black; }
.circle {
height: 100px;
width: 100px;
border-radius: 50%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
opacity: .25;
}
.circle-color-1 { background-color: red; }
.circle-color-2 { background-color: blue; }
.circle-color-3 { background-color: green; }
.circle-color-4 { background-color: black; }
.active-circle { opacity: 1; }
<div class="grid">
<div class="rect"></div>
<div class="circles-container">
<div class="circle circle-color-1" data-rect="rect-1">Circle 1</div>
<div class="circle circle-color-2" data-rect="rect-2">Circle 2</div>
<div class="circle circle-color-3" data-rect="rect-3">Circle 3</div>
<div class="circle circle-color-4" data-rect="rect-4">Circle 4</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous">
</script>

Related

Changing background color of a div in click event gives unexpected (or is it expected?) result

I'm working on a word guessing game, and when the user clicks a letter on the visual keyboard I've created, I want the background color of that letter to change (light green if correctly guessed, grey if incorrect). However, the default background (set with 'letter' class) doesn't seem to get replaced properly after clicking. Instead, an unstyled box (no border radius etc.) with the new background color overlays the default background color (it's visually obvious). I'm interested to know why this happens. Could someone please enlighten me? Is this a known phenomenon? Or is it to do with my event and use of e.target?
Please see my HTML, CSS & Javascript below.
const currentWord = "abc"
$('.keyboard .row .letter').click(function(e) {
// Check if 'currentWord' contains clicked letter
let check = [];
currentWord.split('').forEach(function(letter, i) {
let clickedLetter = e.target.firstChild.textContent.toLocaleUpperCase();
if(clickedLetter === letter.toLocaleUpperCase()) {
// Change background of correctly guessed letter
$(e.target).css('background-color','lightgreen');
// Make letter appear in letter box
$(`#${letter} .word-letter`).text(clickedLetter).fadeOut(1).fadeIn(250);
check.push(1);
} else if((i === currentWord.length - 1) && !check.length) {
// Change background of incorrectly guessed letter
$(e.target).css('background-color', 'grey');
}
})
})
/* KEYBOARD */
.keyboard {
grid-column: 2/5;
grid-row: 6/8;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: rgb(223, 255, 196);
}
.row {
height: 40%;
width: 100%;
font-size: 2em;
display: flex;
justify-content: center;
}
.letter {
text-align: center;
width: 5%;
background-color: rgb(158, 228, 255);
margin: 1%;
border-radius: 10px;
box-shadow: 3px 3px lightgray;
}
.letter:hover {
background-color: rgb(255, 138, 255);
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="keyboard">
<div class="row">
<div class="letter"><p>Q</p></div>
<div class="letter"><p>W</p></div>
<div class="letter"><p>E</p></div>
<div class="letter"><p>R</p></div>
<div class="letter"><p>T</p></div>
<div class="letter"><p>Y</p></div>
<div class="letter"><p>U</p></div>
<div class="letter"><p>I</p></div>
<div class="letter"><p>O</p></div>
<div class="letter"><p>P</p></div>
</div>
<div class="row">
<div class="letter"><p>A</p></div>
<div class="letter"><p>S</p></div>
<div class="letter"><p>D</p></div>
<div class="letter"><p>F</p></div>
<div class="letter"><p>G</p></div>
<div class="letter"><p>H</p></div>
<div class="letter"><p>J</p></div>
<div class="letter"><p>K</p></div>
<div class="letter"><p>L</p></div>
</div>
<div class="row">
<div class="letter"><p>Z</p></div>
<div class="letter"><p>X</p></div>
<div class="letter"><p>C</p></div>
<div class="letter"><p>V</p></div>
<div class="letter"><p>B</p></div>
<div class="letter"><p>N</p></div>
<div class="letter"><p>M</p></div>
</div>
</div>
That is because you are setting the background-color on e.target which might not be the element with the letter class. The event target is the element that was actually clicked and can be a child (e.g. the p tag). This happens because events bubble up the dom and trigger any listeners that they encounter. To get the element on which the event listener is attached use e.currentTarget
const currentWord = "abc"
$('.keyboard .row .letter').click(function(e) {
// Check if 'currentWord' contains clicked letter
let check = [];
currentWord.split('').forEach(function(letter, i) {
let clickedLetter = e.currentTarget.firstChild.textContent.toLocaleUpperCase();
if(clickedLetter === letter.toLocaleUpperCase()) {
// Change background of correctly guessed letter
$(e.currentTarget).css('background-color','lightgreen');
// Make letter appear in letter box
$(`#${letter} .word-letter`).text(clickedLetter).fadeOut(1).fadeIn(250);
check.push(1);
} else if((i === currentWord.length - 1) && !check.length) {
// Change background of incorrectly guessed letter
$(e.currentTarget).css('background-color', 'grey');
}
})
})
/* KEYBOARD */
.keyboard {
grid-column: 2/5;
grid-row: 6/8;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: rgb(223, 255, 196);
}
.row {
height: 40%;
width: 100%;
font-size: 2em;
display: flex;
justify-content: center;
}
.letter {
text-align: center;
width: 5%;
background-color: rgb(158, 228, 255);
margin: 1%;
border-radius: 10px;
box-shadow: 3px 3px lightgray;
}
.letter:hover {
background-color: rgb(255, 138, 255);
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="keyboard">
<div class="row">
<div class="letter"><p>Q</p></div>
<div class="letter"><p>W</p></div>
<div class="letter"><p>E</p></div>
<div class="letter"><p>R</p></div>
<div class="letter"><p>T</p></div>
<div class="letter"><p>Y</p></div>
<div class="letter"><p>U</p></div>
<div class="letter"><p>I</p></div>
<div class="letter"><p>O</p></div>
<div class="letter"><p>P</p></div>
</div>
<div class="row">
<div class="letter"><p>A</p></div>
<div class="letter"><p>S</p></div>
<div class="letter"><p>D</p></div>
<div class="letter"><p>F</p></div>
<div class="letter"><p>G</p></div>
<div class="letter"><p>H</p></div>
<div class="letter"><p>J</p></div>
<div class="letter"><p>K</p></div>
<div class="letter"><p>L</p></div>
</div>
<div class="row">
<div class="letter"><p>Z</p></div>
<div class="letter"><p>X</p></div>
<div class="letter"><p>C</p></div>
<div class="letter"><p>V</p></div>
<div class="letter"><p>B</p></div>
<div class="letter"><p>N</p></div>
<div class="letter"><p>M</p></div>
</div>
</div>

Toggle "addClass" at 3 divs successively

This is my html:
<div class="button"></div>
<div class="wrapper>
<div class="something">Hello</div>
<div class="box one">Box 1</div>
<div class="box two">Box 2</div>
<div class="box three">Box 3</div>
</div>
By clicking the div "button", I want to add the class "active" to the first div with class name "box". If I clicking the button again, I want to remove the class "active" from box 1 and add it to box 2. Aso.
Later, if box 3 has the added class name "active" and I press the div "button" again, it should start from the beginning.
I try something like this, but it fails:
$(".button").click(function() {
$(this).find(".wrapper").add(".box").toggleClass("active");
});
You'll need to use css :eq() selector or .eq() on jquery
$(document).ready(function(){
var index = 0; // define index for the first box
$('.button').on('click',function(){
$('.wrapper .box').removeClass('active'); // remove class active from all box divs
$('.wrapper .box:eq('+index+')').addClass('active'); // add class active to the box index we need
index = (index < $('.wrapper .box').length - 1) ? index +1 : 0; // if index = the number of box divs add + 1 if not return it back to 0
}).click(); // if you need to run it onload add .click()
});
.active{
background : red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="button">Click</div>
<div class="wrapper">
<div class="something">Hello</div>
<div class="box one">Box 1</div>
<div class="box two">Box 2</div>
<div class="box three">Box 3</div>
</div>
You can try something like this:
jQuery(".button").click(function(){
var active = jQuery(".wrapper").children(".active").first();
if (!active.length)
jQuery(".wrapper").children(":first").addClass("active");
else{
active.removeClass("active");
if (active[0] != jQuery(".wrapper").children(":last")[0])
active.next().addClass("active");
else
jQuery(".wrapper").children(":first").addClass("active");
}
});
.button {
width: 150px;
height: 50px;
cursor: pointer;
background-color: blue;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
border-style: solid;
border-width: 0.5px;
border-radius: 9px;
position: relative;
left: 30%;
}
.wrapper {
margin-top: 20px;
margin-left: 30px;
background-color: white;
width: 450px;
height: 550;
text-align: center;
border-style: dashed;
}
.active {
background-color: grey;
}
.something {
margin-bottom: 8px;
margin-top: 8px;
}
.box {
margin-bottom: 8px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="button">
<p>Press Me</p>
</div>
<div class="wrapper">
<div class="something">Hello</div>
<div class="box one">Box 1</div>
<div class="box two">Box 2</div>
<div class="box three">Box 3</div>
</div>
Some fun with generator functions :)
let box = 0;
$('.button').on('click', function() {
const boxes = document.querySelectorAll('.box'); // get all boxes
let iter = activateBox(box, boxes); // create itarator to go over boxes
$('.box').removeClass('active'); // remove any active class from all boxes
iter.next(box++).value.classList.add('active'); // add active class to the next box in line
if (box === boxes.length) box = 0; // reset counter if last box reached
});
function* activateBox(i, boxes) {
yield boxes[i];
}
body {
font-family: 'Arial', sans-serif;
}
.button {
display: inline-block;
padding: 8px;
border: 2px solid lightblue;
border-radius: 4px;
color: #444;
cursor: pointer;
transition: background .15s ease-out;
}
.button:hover {
background: lightblue;
color: #FFF;
}
.box {
display: flex;
justify-content: center;
align-items: center;
width: 300px;
height: 100px;
background: #FFF;
margin: 8px 0;
border: 2px solid lightblue;
border-radius: 4px;
}
.box.active {
background: lightblue;
color: #FFF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="button">Apply Active</div>
<div class="wrapper">
<div class="box one">Box 1</div>
<div class="box two">Box 2</div>
<div class="box three">Box 3</div>
</div>

CSS how to make divs fill all the vertical space

I made this example: https://jsfiddle.net/jpdjkdr0/
What i want to achieve is making the divs always fit the #wrapper height (which is 500px fixed) in any case.
So that when toggling a new div (click the button) all the divs should adjust themselves to fit the full wrapper height.
I would like to achieve this in pure css if possible but i have no ideas atm.
Any advice? Maybe some flexbox ?!
You can add display: flex; flex-direction: column; to the #wrapper and set the child divs to flex: 1.
This will allow them to grow to fill the available space: https://jsfiddle.net/jpdjkdr0/1/
.hide {
display:none;
}
#wrapper {
height: 500px;
width:500px;
border: 10px solid violet;
display: flex;
flex-direction: column;
}
#wrapper div {
flex: 1;
}
#div-1 {
background: brown;
color: white;
}
#div-2 {
background: green;
color: white;
}
#div-3 {
background: red;
color: white;
}
#div-4 {
background: blue;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="$('#div-1').toggle()">
show div
</button>
<div id="wrapper">
<div id="div-1" class="hide">
1
</div>
<div id="div-2">
2
</div>
<div id="div-3">
3
</div>
<div id="div-4">
4
</div>
</div>

Sliding div off-screen

I’m having a little trouble with this template: basically, I’m trying to add functionality where if you click a box it will expand sliding the other ones off-screen, but instead sliding the div off-screen it’s disappearing completely.
Here is what I have so far: JSFiddle.
$(function() {
$(".box").click(function() {
var isopened = $(this).attr("isopen");
if (isopened == "true") {
$(this).css("position", "relative").css("width", $(this).attr("data-ow"));
$(this).attr("isopen", "false");
}
else {
$(this).attr("data-ow", $(this).css("width"));
$(this).css("position", "relative").css("width", "40%");
$(this).attr("isopen", "true");
}
});
});
* {
margin: 0;
padding: 0;
}
.container {
width: 100%;
max-width: 100%;
max-height: 600px;
overflow: hidden;
}
.box {
height: 600px;
display: block;
width: 13.33333333%;
border: 1px solid white;
background-color: black;
float: right;
position: relative;
}
.box:first-of-type {
width: 29.0%;
background-color: orange;
}
.box:last-of-type {
width: 29.0%;
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
What I ultimately want is when one of the boxes is clicked it expands and instead of the entire div being hidden only the part which is off-screen is hidden:
I think you might like this flexbox solution as you can do what you want without usign any jQuery/JS. Pure CSS and HTML:
body {
background-color: black
}
#container {
display: flex;
width: 100%;
height: 50vh;
}
#container > div {
flex: 1;
min-width: 0;
transition:min-width 0.2s ease;
outline:0;
}
#container > div:focus {
min-width: 50vw;
}
<div id="container">
<div tabindex="0" style="background-color:blue"></div>
<div tabindex="0" style="background-color:orange"></div>
<div tabindex="0" style="background-color:green"></div>
<div tabindex="0" style="background-color:white"></div>
<div tabindex="0" style="background-color:blue"></div>
</div>
I used tabindex to give me the ability to use the :focus selector.

Jquery Animate effect to move div

I would like to be able to add an animation to this simple query for when the div is transitioned to its new position.
<div class="container">
<div class="left-side-bar">
<div class="long blue" id="1">
1
</div>
<div class="short red" id="2">
2
</div>
</div>
<div class='middle-side-bar'>
<div class='long green' id="3">
3
</div>
</div>
<div class='right-side-bar'>
<div class='short yellow' id="4">
4
</div>
</div>
</div>
the CSS
.left-side-bar{
clear: both;
width: 32%;
text-align: center;
float: left;
margin-top: 1%;
margin-bottom: 100px;
}
.middle-side-bar{
width: 32%;
text-align: center;
float: left;
margin: 1% 0 1% 1.6%;
}
.right-side-bar{
width: 32%;
text-align: center;
float: left;
margin: 1% 0 1% 1.6%;
}
.green {
background-color: green;
}
.long {
height: 300px;
}
.short {
height: 200px;
}
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.yellow {
background-color: yellow;
}
Basically I want the div to be moved to its new place as an animated transition, rather than have it simply appear.
here is the jsfiddle
DEMO
Unfortunately, the replaceWith method does not work with animate in jQuery. Instead, you will probably need to find an alternative method to your solution. Here's one that slowly transitions the red box on top of the yellow box... http://jsfiddle.net/aeyg89rd/4/
I added the following jQuery, note that I used offset() to get the left and top properties of the yellow box, then I moved the red box to those left and top positions using animate() :
$(document).ready(function () {
var num4 = $("#4").offset();
$("#2").animate({ top: num4.top, left: num4.left }, 1000);
});
And I changed some CSS attributes for .red class so that I can move it around with the jQuery code above. More specifically, I changed its position to absolute, and gave it a width dimension:
.red {
position: absolute;
top: 320px;
background-color: red;
width: 150px;
}

Categories