How to setInterval once inside foreach using javascript - javascript

I need to set interval once for each slider element inside array when "if" statement is true but my code sets unlimited interval every time "if" statement is true. it is my js code:
const sliders = [realestateSlider,carsSlider,spectechnicSlider,motorcyclesSlider,partsSlider,beautySlider,clothesSlider,bestsellersSlider,topproductsSlider,salesSlider];
function checkIfIntoView(sliders){
sliders.forEach(function(slider,index){
if(slider.getBoundingClientRect().top <= window.innerHeight || document.documentElement.innerHeight){
setInterval(function(){slider.scrollLeft += scrollWidth;},1000);
}
});
}
window.addEventListener('wheel',function(event){ checkIfIntoView(sliders); });

Since you call the checkIfIntoView function in event listener, event listner will tiger that function each and every time a on wheel event occur. So if you want to call the checkIfIntoView function once the wheel event triggered, use a Boolean variable.
let ran = false;
function checkIfIntoView(sliders){
if (!ran) {
ran = true
sliders.forEach(function(slider,index){
if(slider.getBoundingClientRect().top <= window.innerHeight || document.documentElement.innerHeight){
setInterval(function(){slider.scrollLeft += scrollWidth;},1000);
}
});
}
}

Assuming that those are all Elements in the sliders Array, maybe you're looking to do something like:
const sliders = [realestateSlider, carsSlider, spectechnicSlider, motorcyclesSlider, partsSlider, beautySlider, clothesSlider, bestsellersSlider, topproductsSlider, salesSlider];
onscroll = e=>{
requestAnimationFrame(()=>{
let b, t, l;
for(let n of sliders){ // n is each node
b = n.getBoundingClientRect(); t = b.top; l = b.left;
if(t+b.height > -1 && t <= innerHeight && l+b.width > -1 && l <= innerWidth){
console.log('in view');
}
else{
console.log('not in view');
}
}
});
}
Note that you can always leave window. off of any property of window.

I'm not sure exactly what you are asking... But if you want to scroll until slider.getBoundingClientRect().top >= window.innerHeight then you could write your function like this:
const sliders = [realestateSlider,carsSlider,spectechnicSlider,motorcyclesSlider,partsSlider,beautySlider,clothesSlider,bestsellersSlider,topproductsSlider,salesSlider];
function checkIfIntoView(sliders){
sliders.forEach(function(slider,index){
let interval = setInterval(function(slider){
if (slider.getBoundingClientRect().top <= window.innerHeight || document.documentElement.innerHeight) {
slider.scrollLeft += scrollWidth;
} else {
clearInterval(interval);
}
}, 1000);
}
window.addEventListener('wheel',function(event){ checkIfIntoView(sliders); });
That way the interval will be cleared after the criteria is met. Keep in mind setInterval will continue to run until it is cleared via clearInterval

Related

clearInterval is not working on keydown addEventListener inside setInterval in javascript

This code will work fine when you press ArrowRight key in once at a time. But When you press ArrowKey twice or many at a time then the interval execute with infinity, clearInterval and if condition will not work. please help. Must run this code in your pc. then you will understand what I want to say.
var increaseNum;
function endLevel() {
window.clearInterval(increaseNum);
}
var n=0;
window.addEventListener("keydown", (e)=>{
if(e.key == "ArrowRight"){
increaseNum = setInterval(()=>{
n +=1;
if(n>10){
endLevel();
}
console.log(n);
}, 50)
}
})
Can't you do this:
window.addEventListener("keydown", (e) => {
if (e.key == "ArrowRight") {
function endLevel() {
window.clearInterval(increaseNum);
}
var increaseNum;
var n = 0;
increaseNum = setInterval(() => {
n +=1;
if(n>10){
endLevel();
}
console.log(n);
}, 50)
}
})
Because as you have it now, when you press multiple times increaseNum gets reassigned, hence clearInterval will not work as you expect. Also all those intervals will be increasing the same n.
In the above example, multiple intervals will fire now, each closing over its own version of n, increaseNum, endLevel. Not sure if that's what you want though.
Or you may find more suitable to not start a new interval if there is another already running. Or you may clear existing interval (as in the other answer). Depends on your use case.
you can just check if there is already a count in progress and if there is one don't start another, something like this:
var increaseNum;
function endLevel() {
window.clearInterval(increaseNum);
increaseNum = null;
n = 0;
}
var n = 0;
window.addEventListener("keydown", (e) => {
if (increaseNum) return;
if (e.key == "ArrowRight") {
increaseNum = setInterval(() => {
n += 1;
if (n > 10) {
endLevel();
}
console.log(n);
}, 50);
}
});
If I understand what you are wanting to do as while the user is pressing the right arrow then you want the game to continue but if they stop then the setInterval will reach n>10 and the endLevel method will be called.
let increaseNum;
let n = 0;
let reset = true;
function endLevel() {
n = 0;
window.clearInterval(increaseNum);
}
window.addEventListener("keydown", (e)=>{
if(e.key == "ArrowRight"){
window.clearInterval(increaseNum);
n = 0;
increaseNum = setInterval(()=>{
if(n>10){
endLevel();
}
n++;
}, 50)
}
})

Rotation tween stop and tween start on mouse down

I have an object rotating on z axis. onMouseDown the rotation stops and onMouseUp the rotation resumes after 2 seconds.
Is there a way for the rotation to resume slowly (like ease in for css)?
The code for the rotation start and stop.
if ( etaj1 !== undefined ) {
etaj1.rotation.z += delta * 0;
if(!isMouseDown){
etaj1.rotation.z += delta * 0.05 ;
}
}
Also there is a resetTimer condition if a new click is made before the 2 seconds have passed.
var timerHandle = setTimeout (wait , 2000);
function resetTimer () {
window.clearTimeout (timerHandle);
timerHandle = setTimeout (wait , 2000);
}
function onMouseDown(){
console.log("Mouse DOWN");
isMouseDown = true;
}
function onMouseUp(){
window.clearTimeout (timerHandle);
timerHandle = setTimeout (wait , 2000);
}
function wait (){
resetTimer;
console.log("Mouse UP");
isMouseDown = false;
}
the idea is to make a transition for isMouseDown = false; and another transition for isMouseDown = true;
Basically what i want to do is stop the rotation from the link below with a quart.out tween, wait 2 seconds and if no click resume rotation with a quart.in tween.
https://threejs.org/examples/#webgl_loader_collada
Thanks.
I'm not a three.js guy, however what you are asking is applicable in other areas as well. So I will put here a general solution. First the proof of concept:
https://jsfiddle.net/ibowankenobi/u4xwnLam/4/
I'll start declaring the globals I need, wrap them up as you want:
var rotation = 0;
var bar = document.getElementById("bar");
var container = document.getElementById("container");
I need to demonstrate this without three.js so I need to have a container and something to rotate so you do not need bar and container in your case. Rotation in your case is your etaj1.rotation.z
We first need a function that will map 0-1 to 0-1 again, but not linearly. These are called interpolations, there are many ones, cosine, this, that, most widely used one is a stitched and transformed x^3 and gives a "slow in slow out" affect:
function slowInSlowOut(t){
if(2*t<<0){
return 4*(t-1)*(t-1)*(t-1)+1;
} else {
return 4*t*t*t;
}
}
We have to do something with this function so I will write another animate
function changeSpeed(obj,newSpeed){
var oldSpeed = obj.__oldSpeed || 0;
var startTime;
newSpeed = newSpeed || 0;
obj.__currentFrame && window.cancelAnimationFrame(obj.__currentFrame);//cancel a previous changeSpeed if fired twice
obj.__currentFrame = window.requestAnimationFrame(anim);
function anim(t){
startTime = startTime || t;
var elapsed = t - startTime,
parametric = slowInSlowOut(elapsed/2000);
if(parametric>=1){
obj.__oldSpeed = newSpeed;
} else {
obj.__oldSpeed = newSpeed + (oldSpeed-newSpeed) * (1-parametric);
obj.__currentFrame = window.requestAnimationFrame(anim);
}
}
}
You provide this function an object, and it will attach it a proprietary __oldSpeed property, the newSpeed parameter is measured in means of degrees/17ms (because I am using requestAnimationFrame and that will fire each ~17ms). So in your case the obj is your etaj1.
Within this function you can already update your etaj1.rotation.z if you want. But I will write a third function to fire continuously and listen to __oldSpeed property and take action based on that:
function animate(obj){
rotation += (obj.__oldSpeed || 0);
rotation = rotation % 360;
obj.style.transform = "rotate("+rotation+"deg)";
window.requestAnimationFrame(function(){animate(obj)});
}
Again here, obj is your etaj1 and rotation is etaj1.rotation.z. I am using DOM here, so I need to use the styles. You can adapt it to your case.
Animate won't fire, so we need to fire him:
window.requestAnimationFrame(function(){animate(bar)});
I'll add the eventListeners as you described:
container.addEventListener("mousedown",function(){changeSpeed(bar,0)},false);
container.addEventListener("mouseup",function(){changeSpeed(bar,12)},false);
Now we give it a starting speed:
changeSpeed(bar,12);
There you go. In case you wondered how to do it yourself, this might get you started. I guess people using other technology stacks can also adapt this to their case.
PS:
Someone mentioned a delay, in that case modify the changeSpeed a bit:
function changeSpeed(obj,newSpeed,delay){
delay = delay || 0;
var oldSpeed = obj.__oldSpeed || 0;
var startTime;
newSpeed = newSpeed || 0;
obj.__currentFrame && window.cancelAnimationFrame(obj.__currentFrame);
obj.__currentFrame = window.requestAnimationFrame(anim);
function anim(t){
startTime = startTime || t;
var elapsed = t - startTime;
if(elapsed < delay) {
return obj.__currentFrame = window.requestAnimationFrame(anim);
}
var parametric = slowInSlowOut((elapsed-delay)/2000);
if(parametric>=1){
obj.__oldSpeed = newSpeed;
} else {
obj.__oldSpeed = newSpeed + (oldSpeed-newSpeed) * (1-parametric);
obj.__currentFrame = window.requestAnimationFrame(anim);
}
}
}
Here is a fiddle that has a 2 second delay:
https://jsfiddle.net/ibowankenobi/u4xwnLam/10/

Return value from function whilst using setTimeout

Is there any way to have a function run with a setTimeout and also return a value assigned to a variable?
An example of what I mean is like this:
function count(start, target) {
if (start < target) {
start += 0.1;
return start;
} else if (start > target) {
return target;
}
// i'm fully aware the return above will prevent this line occur
// this is my issue currently
setTimeout(function () {
count(start, target)
}, 1000);
}
var el = document.getElementById('test');
var value = count(0.0, 1.0); //get the opacity value
function check() {
el.style.opacity = value; //assign what the value is in this moment
if (value != 1.0) {
setTimeout(check, 0);
}
}
check();
I know this code won't work the way i want it because return exit's the function, I wrote it to explain what I am trying to do.
The reason I want to do this in this kinda way is because I have an element which i want to fade in by altering it's opacity.
So i have a function which would increment a start value to a target value using what ever easing i want, this then returns said value which would be assigned to the element's opacity property.
I don't want to pass the element to this count function because that means it limits the use of it for when i want to animate other things besides elements.
What would the solution to this problem be?
I think what you are trying to do is to call the count method again if the value passed for start and target are not the same if so
function count(start, target) {
var ret;
if (start < target) {
ret = start + 0.1;
} else if (start > target) {
ret = target;
}
if (start != target) {
setTimeout(function () {
count(ret, target)
}, 1000);
}
return ret;
}

Prevent function from starting second time, if first is not finished

I created a code that throws an element to up with an acceleration(works like gravity) value and falls down when changed_lenght reaches to zero;
"mouseenter" is triggering this function. When mouse leaves and enters quickly the function starts over and over again, and not stoping the previous ones so it looks so bad.
I wonder is there any way to check if previous one was ended before starting the function. Or any other solution that can help me ?
here is my JS codes:
$('#outher').mouseenter(function moveone(){
var t = 0;
var v = 20;
var p = 275;
var a = 5;
var moveoneint = setInterval(jump, 50);
function jump(){
t++;
x = (v*t) - (0.5 * a * t * t);
p = (p - x);
if(x <= 0){
clearInterval(moveoneint);
t = 0;
var movetwo = setInterval(fall, 50);
function fall(){
t++;
x = (0.5 * a * t * t );
p = (p + x);
document.getElementById('inner').style.top = p + 'px';
if(p >= 275){
clearInterval(movetwo);
}
}
}
else{
document.getElementById('inner').style.top = p + 'px';
}
}
});
and Here is a Fiddle:
http://jsfiddle.net/ctarimli/TJte8/
You can simply remove the mouseenter handler until the animation has completed.
JSFIDDLE
Basically,
var $outher = $('#outher');
var onMouseEnter = function() {
$outher.off('mouseenter', onMouseEnter);
// do all your animation logic, and once complete...
$outher.on('mouseenter', onMouseEnter);
};
$outher.on('mouseenter', onMouseEnter);
If you are open to third-party library code, then throttle /debounce will do what you want. Note that the page mentions jQuery, but the library does not actually require jQuery.
In particular, look at the examples for the $.throttle method.
Use jQuery is to check if div is animating
if(!$('.inner').is(':animated'))
{
//Your code
}

How to disable a button with a timed loop?

i'm trying to disable a button for 6 seconds while in a loop but so far I can't quite figure it out.
var disabledStartTimer = setInterval(disabledTimer, 1000);
function disabledTimer() {
var start = 0;
if (start > 6) {
clearInterval(disabledStartTimer);
console.log("disabled timer stopped");
attack.disabled = true;
} else {
attack.disabled = false;
start++;
};
}
attack = the button I click to attack.
var start = 0;
if (start > 6){
Clearly this will always go into the else. You set the variable to 0 and then test if it's greater than 6... it isn't. You likely wanted this to be a global, move it outside of the function.

Categories

Resources