When the top property of each div .js-player is between 10 and 100 the word #muteshould have the class .active added. The code below only executes the adding of .active on the last .js-active div. Where am I going wrong? Any pointer would be greatly appreciated.
const players = Array.from(document.querySelectorAll('.js-player')),
mute = document.querySelector('#mute');
window.addEventListener('scroll', function(e) {
players.forEach(function(player) {
let distance = player.getBoundingClientRect().top;
if (10 < distance && distance < 100) {
mute.classList.add('active');
} else {
mute.classList.remove('active');
}
})
});
.js-player {
height: 150px;
width: 200px;
background-color: red;
margin: 8em 2em;
}
#mute {
position: fixed;
top: 10px;
left: 10px;
}
.active {
color: green;
}
.filler {
height: 400px;
}
<div class="js-player"></div>
<div class="js-player"></div>
<div class="js-player"></div>
<div class="filler"></div>
<div id="mute">mute</div>
I think what you are wondering is why only the last .js-player determines whether or not the div has the active class?
If so, each time a scroll event happens, it loops over the players, and either add or removes the active class. So, when it gets to the last .js-player, if this last .js-player is not within the distance, it will remove the active class if another one set it, and add it if is, it will set it even if another one removed it.
What you need to do is stop checking once you have found a player within the distance required, something like:
const players = Array.from(document.querySelectorAll('.js-player')),
mute = document.querySelector('#mute');
window.addEventListener('scroll', function(e) {
var matched = false;
players.forEach(function(player) {
if (matched) return;
let distance = player.getBoundingClientRect().top;
if (10 < distance && distance < 100) {
mute.classList.add('active');
matched = true;
} else {
mute.classList.remove('active');
}
})
});
.js-player {
height: 150px;
width: 200px;
background-color: red;
margin: 8em 2em;
}
#mute {
position: fixed;
top: 10px;
left: 10px;
}
.active {
color: green;
}
.filler {
height: 400px;
}
<div class="js-player"></div>
<div class="js-player"></div>
<div class="js-player"></div>
<div class="filler"></div>
<div id="mute">mute</div>
You are setting active class on mute element on each iteration, which means that only the last element of array will matter.
Here's a working verions:
const players = Array.from(document.querySelectorAll('.js-player'));
const mute = document.querySelector('#mute');
window.addEventListener('scroll', function(e) {
var active = false;
players.forEach(function (player) {
let distance = player.getBoundingClientRect().top;
if (10 < distance && distance < 100) {
active = true;
}
});
active ? mute.classList.add('active') : mute.classList.remove('active');
});
.js-player {
height: 150px;
width: 200px;
background-color: red;
margin: 8em 2em;
}
#mute {
position: fixed;
top: 10px;
left: 10px;
}
.active {
color: green;
}
.filler {
height: 400px;
}
<div class="js-player"></div>
<div class="js-player"></div>
<div class="js-player"></div>
<div class="filler"></div>
<div id="mute">mute</div>
Cheers!
Related
I am resizing and positioning a box using the mousemove event. Those. i change transform translate and width (height) with pageX (pageY). But due to the fact that the mouse event mousemove does not always have time to be processed (for example, if you move the mouse quickly) or does not have time to read conditions, the block goes out of bounds.
Question: what do I need to do in this case so that the block does not go beyond the boundaries?
This is how it looks roughly. Those. in this example, the second_block is outside the first_block (500px), i.e. it does not have time to read the condition. How should this issue be resolved? Also for convenience https://jsfiddle.net/ManuOP/t1r4szdx/3/
<div id="first_block" class="first_block">
<div id="auxiliary_block">
<div id="second_block" class="second_block"></div>
<input id="point" class="point" name="name_point" type="button">
</div>
</div>
<script src="1.block_in_center_question.js"></script>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
div {
display: flex;
flex-direction: column;
}
div.first_block {
height: 300px;
width: 500px;
background: green;
}
div#auxiliary_block {
position: absolute;
}
div.second_block {
height: 200px;
width: 300px;
background: orange;
}
input.point {
position: absolute;
cursor: pointer;
height: 14px;
width: 14px;
border: none;
background: black;
right: -7px;
top: 50%;
}
"use strict";
let second_block = document.getElementById('second_block');
let point = document.getElementById('point');
function change_second_block() {
if(second_block.clientWidth < 500) {
second_block.style.width = `${start_x + event.pageX}px`;
}
}
point.addEventListener('mousedown', (event) => {
window.start_x = second_block.clientWidth - event.pageX;
document.addEventListener('mousemove', change_second_block);
});
You could just test the new width and if it's too large then constrain it to be no more than the maximum.
This snippet does this for the x direction and forces it to remain at or below 500px.
"use strict";
let second_block = document.getElementById('second_block');
let point = document.getElementById('point');
function change_second_block() {
if (second_block.clientWidth < 500) {
second_block.style.width = (start_x + event.pageX) < 500 ? `${start_x + event.pageX}px` : '500px';
}
}
point.addEventListener('mousedown', (event) => {
window.start_x = second_block.clientWidth - event.pageX;
document.addEventListener('mousemove', change_second_block);
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
div {
display: flex;
flex-direction: column;
}
div.first_block {
height: 300px;
width: 500px;
background: green;
}
div#auxiliary_block {
position: absolute;
}
div.second_block {
height: 200px;
width: 300px;
background: orange;
}
input.point {
position: absolute;
cursor: pointer;
height: 14px;
width: 14px;
border: none;
background: black;
right: -7px;
top: 50%;
}
<div id="first_block" class="first_block">
<div id="auxiliary_block">
<div id="second_block" class="second_block"></div>
<input id="point" class="point" name="name_point" type="button">
</div>
</div>
You can work around this issue if the size of the change in the item is above a certain limit, or by checking the limit and stopping the update. I prevented the overflow caused by rapid mouse movement by updating its code as follows:
function change_second_block()
{
console.log("Event.PageX: " + event.pageX);
if(event.pageX < 500 )
{
if(second_block.clientWidth < 500)
{
second_block.style.width = `${start_x + event.pageX}px`;
}
}
}
References
Javascript mouse event not captured properly when mouse moved very fast
I'm trying to get the progress bar animation to run when I click the .trigger. I'm getting the data-percentage value in the logs but the animation isn't running. It works without using $(this).closest() but I cannot figure out why the animation isn't running with my current JS code.
$(".list").on("click", ".trigger", function() {
var e = $(this).closest(".item");
$(".progressbar").attr("data-percentage", e.find("#percent").text());
var t = e.find("#percent").text();
return (
$(".progressbar").each(function() {
var n = e,
r = t;
console.log(t),
parseInt(n.data("percentage"), 10) < 2 && (r = 2),
n.children(".bar").animate({
width: r + "%"
}, 500);
}), !1
);
});
.item {
width: 50px;
height: 50px;
border: 1px solid;
}
.trigger {
height: 30px;
width: 30px;
border: 3px solid blue;
cursor: pointer;
}
.progressbar {
position: relative;
display: block;
height: 10px;
background: #f5f5f5;
}
.bar.money-green {
background: #3cd3ad;
}
.bar {
position: absolute;
display: block;
height: 100%;
background: #fcb31c;
width: 0%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="list">
<div class="item">
<div class="trigger">
<p id="percent">22</p>
</div>
</div>
</div>
<div class="progressbar" data-percentage="">
<div class="money-green bar"><span></span></div>
</div>
I updated the code for you. Clean and clear way
You don't need to return in onclick function. And you should use $(this) inside .each to get current index element
$(".list").on("click", ".trigger", function() {
var e = $(this).closest(".item");
var t = e.find("#percent").text();
$(".progressbar").attr("data-percentage", t);
$(".progressbar").each(function() {
$(this).find(".bar").animate({
width: t + "%"
}, 500);
});
});
See the codepen
I am currently trying to create a Character Selection for Airconsole.
I thought I could create this using a Jquery method like a Gallery.
So I need a previous button, a next button and the character display.
It seems that I am making a mistake that I can't figure out, because I am not used to working with Javascript.
var speed = 100;
$(".prev").click(function() {
var now = $(this).parent().next("ul.char_display").children(":visible"),
last = $(this).parent().next("ul.char_display").children(":last"),
prev = now.prev();
prev = prev.index() == -1 ? last : prev;
now.fadeOut(speed, function() {
prev.fadeIn(speed);
});
});
$(".next").click(function() {
var now = $(this).parent().next("ul.char_display").children(':visible'),
first = $(this).parent().next("ul.char_display").children(':first'),
next = now.next();
next = next.index() == -1 ? first : next;
now.fadeOut(speed, function() {
next.fadeIn(speed);
});
});
$(".char_display li").click(function() {
var first = $(this).parent().children(':first'),
next = $(this).next();
next = next.index() == -1 ? first : next;
$(this).fadeOut(speed, function() {
next.fadeIn(speed);
});
});
.prev {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.next {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.char_display li {
display: none;
list-style: none;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.char_display li:first-child {
display: block;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.char_display {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.char {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#char1 {
background: blue;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#char2 {
background: red;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="characterScreen_characterBlock">
<div id="characterScreen_leftArrow" class="characterScreen_left" ontouchend="otherChar(true);" ontouchend="otherChar(true);">
<div class="prev"></div>
</div>
<div id="characterScreen_characterDisplay" class="characterScreen_center">
<ul class="char_display">
<li>
<div class="char" id="char1"></div>
</li>
<li>
<div class="char" id="char2"></div>
</li>
</ul>
</div>
<div id="characterScreen_rightArrow" class="characterScreen_right" ontouchend="otherChar(false);" ontouchend="otherChar(false);">
<div class="next"></div>
</div>
</div>
I haven't look through all of your code, but I am pretty sure
$(this).parent().next("ul.char_display").children("...")
doesn't do what you want it to. Especially since it always returns an error for pushing the next-button.
$.next() returns the next DOM-element. characterScreen_rightArrow however doesn't have a next element (in this snippet)
What you were searching for is probably $.siblings(). Personally I would however use the qualifier #characterScreen_characterDisplay ul instead of searching for it relatively.
I am attempting to make a simon game. I'm trying to use the glowInOrder() function to make the divs glow in the order of the array. Unfortunately only the first div in the array glows, not the others that follow. (When I say 'glow', I simply mean add effect that looks like glow using CSS.) I suspect the issue is in the glowInOrder() function, but i am unable to find the issue.
Here's my code (also on CodePen):
var colorArray = ["red", "blue", "green", "yellow", "pink"];
var player = [];
var computer = [];
var round = 0;
var randomOrder;
var myColor;
var chosenColor;
//--------------------------------------------------------//
function makeGlow(yolo) {
$(yolo).addClass('hover');
setTimeout(function() {
$(yolo).removeClass('hover');
}, 300);
}
//--------------------------------------------------------//
function makeGlowTwo(yolo) {
setTimeout(function() {
$(yolo).addClass('hover');
}, 500);
setTimeout(function() {
$(yolo).removeClass('hover');
}, 800);
}
//--------------------------------------------------------//
function newGame() {
player = [];
computer = [];
round = 0;
}
//---------------------------------------------------------//
function playerChoice() {
$('.all').on('click', function(e) {
player.push(e.target.id);
makeGlow(this);
});
};
//---------------------------------------------------------//
function computerChoice() {
randomOrder = Math.floor(Math.random() * colorArray.length);
myColor = colorArray[randomOrder];
computer.push(myColor);
chosenColor = "#" + myColor;
makeGlowTwo(chosenColor);
}
//--------------------------------------------------------//
function newRound() {
round++;
glowInOrder();
}
//---------------------------------------------------------//
function glowInOrder() {
//computerChoice();//this may not work take out if you find it doesn't
var i = 1;
var moves = setInterval(function() {
makeGlowTwo(computer[i]);
i++;
if (i >= computer.length) {
clearInterval(moves);
}
}, 400)
}
//---------------------------------------------------------//
function arraysEqual(arr1, arr2) {
if (arr1.length !== arr2.length)
return false;
for (var i = arr1.length; i--;) {
if (arr1[i] !== arr2[i])
return false;
}
return true;
}
//---------------------------------------------------------//
$(document).ready(function() {
newGame();
playerChoice();
computerChoice();
$('.all').on('click', function() {
if (arraysEqual(computer, player)) {
alert('yes');
glowInOrder();
}
});
});
* {
margin: 0;
padding: 0;
}
body {
background-color: black;
}
.all {
border-radius: 50%;
height: 100px;
width: 100px;
}
#red {
border: 5px solid red;
display: table;
margin-left: auto;
margin-right: auto;
}
#blue {
border: 5px solid blue;
border-radius: 50%;
float: right;
display: inline;
}
#green {
border: 5px solid green;
border-radius: 50%;
display: inline-block;
}
#yellow {
border: 5px solid yellow;
border-radius: 50%;
display: inline-block;
margin-left: 40px;
}
#pink {
border: 5px solid pink;
border-radius: 50%;
float: right;
display: inline;
margin-right: 40px;
}
.middleRow {
margin-top: 70px;
margin-bottom: 110px;
}
.gameContainer {
height: 500px;
width: 500px;
margin-left: 25%;
margin-top: 10%;
}
.hover {
background-color: white;
}
<div class="container">
<div class="gameContainer">
<div class="topRow">
<div id="red" class="all"></div>
</div>
<div class="middleRow">
<div id="green" class="all"></div>
<div id="blue" class="all"></div>
</div>
<div class="bottomRow">
<div id="yellow" class="all"></div>
<div id="pink" class="all"></div>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Two issues that jump out:
You're only calling computerChoice once, and it adds only one entry to the array. So you have only one entry in computer at index 0.
Your glowInOrder function starts with i set to 1, which doesn't match any entry in your array. And naturally stops when you do the i >= computer.length check.
You need to ensure that computer has the correct number of entries (I'm guessing 5), and you need to start with i = 0 to start with the first one in your glowInOrder.
There are probably other logic issues in the code, but that's what's going on in relation to what you asked about. If you work through it in a debugger (there's one built into your browser) you'll be able to sort the other issues out.
I am learning javascript these days and I have a little problem with my code.
I have three elements on page wrapper1, wrapper2 and wrapper3 and every of these has its triggerand redbox element.
My goal is when the trigger is hit, it will show the redbox element corresponding to number.
Examples:
clicking trigger1 inside wrapper1 element shows up redbox1 element,
trigger2 inside wrapper2 element shows up redbox2 element etc.
The problem is, when I click on trigger3 for example it always shows redbox1 element. (as example shows).
What I am doing wrong? I am just a begginer.
function showTheRedBox() {
var theRedBox = document.getElementsByClassName('redbox');
theRedBox[0].style.display = 'block';
}
body {background: #222;}
.wrapper {
background: yellow;
width: 100px;
height: 100px;
}
.trigger {
background: blue;
width: 50px;
height: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
}
.redbox {
background: red;
width: 200px;
height: 100px;
margin-left: 100px;
position: absolute;
display: none;
}
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox();">trigger1</div>
<div class="redbox">hurrah1</div>
wrapper1</div>
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox();">trigger2</div>
<div class="redbox">hurrah2</div>
wrapper2</div>
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox();">trigger3</div>
<div class="redbox">hurrah3</div>
wrapper3</div>
You can use a for loop and a closure to access the .wrapper information for each onclick event. This method will work whether there are the same amount of children or not, and will always show the correct child.
Also, it is best to not use inline JavaScript attributes (e.g. onclick="showTheRedBox();") you should always assign your event handlers in your script for readability and maintainability.
var wrappers = document.querySelectorAll('.wrapper'), i;
var redboxes = document.querySelectorAll('.redbox');
for(i = wrappers.length - 1; i >= 0; --i) {
(function(wrapper){
wrapper.querySelector('.trigger').onclick = function() {
hideAll();
wrapper.querySelector('.redbox').style.display = 'block';
}
})(wrappers[i]);
}
function hideAll() {
for(i = redboxes.length - 1; i >= 0; --i) {
redboxes[i].style.display = 'none';
}
}
var wrappers = document.querySelectorAll('.wrapper'), i;
var redboxes = document.querySelectorAll('.redbox');
for(i = wrappers.length - 1; i >= 0; --i) {
(function(wrapper){
wrapper.querySelector('.trigger').onclick = function() {
hideAll();
wrapper.querySelector('.redbox').style.display = 'block';
}
})(wrappers[i]);
}
function hideAll() {
for(i = redboxes.length - 1; i >= 0; --i) {
redboxes[i].style.display = 'none';
}
}
body {background: #222;}
.wrapper {
background: yellow;
width: 100px;
height: 100px;
}
.trigger {
background: blue;
width: 50px;
height: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
}
.redbox {
background: red;
width: 200px;
height: 100px;
margin-left: 100px;
position: absolute;
display: none;
}
<div class="wrapper">
<div class="trigger">trigger1</div>
<div class="redbox">hurrah1</div>
wrapper1</div>
<div class="wrapper">
<div class="trigger">trigger2</div>
<div class="redbox">hurrah2</div>
wrapper2</div>
<div class="wrapper">
<div class="trigger">trigger3</div>
<div class="redbox">hurrah3</div>
wrapper3</div>
This method will also work, but it will use more memory as it queries the DOM once more than the above solution.
var wrappers = document.querySelectorAll('.wrapper'), i;
var redboxes = document.querySelectorAll('.redbox');
for(i = wrappers.length - 1; i >= 0; --i) {
wrappers[i].querySelector('.trigger').onclick = function() {
hideAll();
this.parentNode.querySelector('.redbox').style.display = 'block';
}
}
function hideAll() {
for(i = redboxes.length - 1; i >= 0; --i) {
redboxes[i].style.display = 'none';
}
}
var wrappers = document.querySelectorAll('.wrapper'), i;
var redboxes = document.querySelectorAll('.redbox');
for(i = wrappers.length - 1; i >= 0; --i) {
wrappers[i].querySelector('.trigger').onclick = function() {
hideAll();
this.parentNode.querySelector('.redbox').style.display = 'block';
}
}
function hideAll() {
for(i = redboxes.length - 1; i >= 0; --i) {
redboxes[i].style.display = 'none';
}
}
body {background: #222;}
.wrapper {
background: yellow;
width: 100px;
height: 100px;
}
.trigger {
background: blue;
width: 50px;
height: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
}
.redbox {
background: red;
width: 200px;
height: 100px;
margin-left: 100px;
position: absolute;
display: none;
}
<div class="wrapper">
<div class="trigger">trigger1</div>
<div class="redbox">hurrah1</div>
wrapper1</div>
<div class="wrapper">
<div class="trigger">trigger2</div>
<div class="redbox">hurrah2</div>
wrapper2</div>
<div class="wrapper">
<div class="trigger">trigger3</div>
<div class="redbox">hurrah3</div>
wrapper3</div>
The problem you have was that the method "getElementsByClassName", returns you an Array that contains all the elements of that class. So, when you where doing this:
theRedBox[0].style.display = 'block'
You were changing the display style of the First element of the Array, in this case "wrapper1".
Here's a modify version that functions whit the others wrappers:
<!DOCTYPE html>
<html lang = 'es'>
<head>
<title> MY TEST </title>
<style>
body {
background: #222;
}
.wrapper {
background: yellow;
width: 100px;
height: 100px;
}
.trigger {
background: blue;
width: 50px;
height: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
}
.redbox {
background: red;
width: 200px;
height: 100px;
margin-left: 100px;
position: absolute;
display: none;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox(0)">trigger1</div> <!-- When the onClick event is trigered the function "showTheRedBox receives a parameter , that parameter is the position of the element in the Array "theRedBox"-->
<div class="redbox">hurrah1</div>
wrapper1
</div>
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox(1)">trigger2</div>
<div class="redbox">hurrah2</div>
wrapper2
</div>
<div class="wrapper">
<div class="trigger" onclick="showTheRedBox(2)">trigger3</div>
<div class="redbox">hurrah3</div>
wrapper3</div>
<script>
function showTheRedBox(wrapperNumber) {
var theRedBox = document.getElementsByClassName('redbox');
theRedBox[wrapperNumber].style.display = 'block';
}
</script>
</body>
</html>