Pause Javascript for a few seconds on click - javascript

Ok i know this has to be a topic discussed earlier, but all the answers I found were a little complicated considering I'm new and still in the process of learning javascript.
I have the following code in the head section of my html
<script>
function timedText() {
setTimeout(function(){displayResult()},3000);
setTimeout(function(){displayResult1()},7000);
setTimeout(function(){displayResult2()},15000);
setTimeout(function(){timedText()},18000);
}
</script>
<script>
function change() {
setTimeout(function(){timedText()},1000);
}
</script>
<script>
function displayResult() {
document.getElementById("adimg_holder").style.bottom="0px";
document.getElementById("button1").style.backgroundPosition="bottom";
document.getElementById("button2").style.backgroundPosition="top";
document.getElementById("button3").style.backgroundPosition="top";
}
function displayResult1() {
document.getElementById("adimg_holder").style.bottom="370px";
document.getElementById("button1").style.backgroundPosition="top";
document.getElementById("button2").style.backgroundPosition="bottom";
document.getElementById("button3").style.backgroundPosition="top";
}
function displayResult2() {
document.getElementById("adimg_holder").style.bottom="739px";
document.getElementById("button1").style.backgroundPosition="top";
document.getElementById("button2").style.backgroundPosition="top";
document.getElementById("button3").style.backgroundPosition="bottom";
}
</script>
and the following html
<body onload="change()">
<div class="banner_area">
<div class="banner_wrapper">
<img src="images/image_holder.png" />
<div id="ad_holder">
<div id="adimg_holder">
<img class="ad_images" src="images/recruitment_banners.png" />
<img class="ad_images" src="images/training_banners.png" />
<img class="ad_images" src="images/staffing_banner.png" />
</div>
</div>
<div id="ad_buttons">
<div id="button1" style="background-image:url(images/buttonfirst.png);background-position:bottom;width:259px;height:41px" onclick="displayResult()"></div>
<div id="button2" style="background-image:url(images/buttonsecond.png);width:259px;height:41px" onclick="displayResult1()"></div>
<div id="button3" style="background-image:url(images/buttonthird.png);width:259px;height:41px" onclick="displayResult2()"></div>
</div>
</div>
</div>
So the buttons toggle different positions, and the script cycles through the positions at time intervals
Now what I'm trying to achieve is that when the positions are being cycled through, if I click on one of the button, it jumps to the related position and stays that way for a while (say a few seconds) and then continue with the loop.
Hope I've made my motive easy to understand.

Here is how you can achieve this behavior: http://jsfiddle.net/PcZsT/12/
Here is the JavaScript:
function timedText() {
setTimeout(function() {
displayResult();
},2000);
setTimeout(function() {
displayResult1();
},6000);
setTimeout(function() {
displayResult2();
},14000);
setTimeout(function() {
timedText();
},15000);
}
(function change() {
setTimeout(function() {
timedText();
},1000);
}());
var locked = false;
function button1Handler() {
moveTop();
lockFor(3);
}
function button2Handler() {
moveBottom();
lockFor(3);
}
function lockFor(seconds) {
locked = true;
setTimeout(function () {
locked = false;
}, seconds * 1000);
}
function displayResult() {
if (locked) return;
moveTop();
}
function moveTop() {
document.getElementById("adimg_holder").style.bottom="0px";
document.getElementById("button1").style.backgroundPosition="bottom";
document.getElementById("button2").style.backgroundPosition="top";
document.getElementById("button3").style.backgroundPosition="top";
}
function displayResult1() {
if (locked) return;
moveMiddle();
}
function moveMiddle() {
document.getElementById("adimg_holder").style.bottom="370px";
document.getElementById("button1").style.backgroundPosition="top";
document.getElementById("button2").style.backgroundPosition="bottom";
document.getElementById("button3").style.backgroundPosition="top";
}
function displayResult2() {
if (locked) return;
moveBottom();
}
function moveBottom() {
document.getElementById("adimg_holder").style.bottom="739px";
document.getElementById("button1").style.backgroundPosition="top";
document.getElementById("button2").style.backgroundPosition="top";
document.getElementById("button3").style.backgroundPosition="bottom";
}
The functions above are the click handlers of respectively button1 and button2.
I've also changed the change function to бe IIFE (Immediately Invoked Function Expression) but it's not necessary, you don't have to do it because you want to be invoked onload.

you don't need so much code : just make one displayResult function that will call itself over and over :
var scrollParam = { scrollPos : 0, // current pos
scrollIncr : 370, // incr in px each call
loopScrollAfter : 700 // set scrollPos to >0 if above that number
delay : 3000, // std scroll delay
whichIsOnTop : 0, // index of the topmost item (button)
pauseDelay : 1000, // added delay if someone clicks
pauseRequired : 0 }; // current required click delay
var mainItem = document.getElementById("adimg_holder");
function displayResult()
{
mainItem.style.bottom=scrollParam.scrollPos +"px";
scrollParam.scrollPos += scrollParam.scrollIncr;
if (scrollParam.scrollPos>scrollParam.loopScrollAfter) scrollParam.scrollPos=0;
setBackgroundPosition("button1",0);
setBackgroundPosition("button2",1);
setBackgroundPosition("button3",2);
scrollParam.whichIsOnTop = (scrollParam.whichIsOnTop + 1) % 3;
// now setup the next call, taking into account if a pause is required
var requiredDelay = scrollParam.delay;
if (scrollParam.pauseRequired >0) {
requiredDelay += scrollParam.pauseRequired;
scrollParam.pauseRequired=0;
}
setTimeout(displayResult, requiredDelay);
}
var setBackgroundPosition(itemName, index ) {
document.getElementById(itemName).style.backgroundPosition=topOrBottom(index );
};
// returns "top" for the right index (==scrollParam.whichIsOnTop) and "bottom" for the others
var topOrBottom(thisIndex) { return (thisIndex == scrollParam.whichIsOnTop) ? "top" : "bottom"; };
// in the button click handler you should use :
scrollParam.pauseRequired += scrollParam.pauseDelay;
// to launch the scroll, just call :
displayResult(); // in the loaded() event handler for example.
Rq : you can change easily the parameters to have a smoother scrolling if you like.

you can make use of the setTimeout timing function itself.
write a function as:
function calldesiredFunctionafterPause (functionTobeCalled){
setTimeout(function(){functionTobeCalled,1000}) //increase the millisec as needed
}
and on the onClick call this function and pass the function name as parameter.
This will make the onclick function to be delayed for the required time

Related

Function inside event listener triggers only on it's initialization

var init = true;
$('#btn').on('click', delay(function() {
$('#text').append('click');
init = false;
}, 100));
function delay(fn, ms, enabled = true) {
$('#text').append(init);
// if(init) disable delay
let timer = 0;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(fn.bind(this, ...args), ms || 0);
}
}
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<button id='btn'> TRIGGER </button>
<div id="text"></div>
Init is a global variable which is meant to be used inside delay function to disable delay (init true/false) only on event listener initialisation.
The problem is that the delay function is triggered only once and ignores the change (to false) of the init variable.
For example, try clicking the trigger button. The init variable value is printed only for the first time.
You are calling the delay function in a wrong way in the click handler. You have to call it like so:
$('#btn').on('click', function () {
delay(function() {
$('#text').append('click');
init = false;
}, 100);
});
You will have to check for the value of init inside the function, like this:
$('#btn').on('click', delay(function() {
if(init) {
$('#text').append('click');
init = false;
}
}, 100));
At the moment I don't know why append is not working but with a little workaround you can obtain what you want. Concatenate the original text and the actual one and use text() to set it again:
var init = true;
$('#btn').on('click', function() {
$('#text').text(init);
setTimeout(myDelay, 5000);
});
function myDelay() {
let originalText = $('#text').text();
init = false;
console.log("init is false");
console.log("original text displayed: " + originalText);
$('#text').text(originalText + " " + init);
}
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<button id='btn'> TRIGGER </button>
<div id="text"></div>

JavaScript Timeout reset mechanism

What I want:
There are two pictures that are being switched/swapped every three seconds.
I want to make it so that when the button is clicked, the picture switches and the auto-swap resets. So if the button is clicked, the image swaps and three seconds later, it will auto-swap, until the button is clicked again in which the cycle will repeat.
What I have right now
Currently, the problem is that: when the button is clicked, it messes up the timing of the auto-switches.
Edit:
Please don't create a new code base. Just modify mines. The code doesn't have to be an expert super concise level. I'm only three weeks into JavaScript (and it's my first programming language). I have to explain to classmates and it wouldn't be nice the code had elements I don't understand. So sorry for the inconvenience.
Right now I just need the button to correctly stop and restart the time.
<html>
<head>
<script>
let reset = setTimeout(change, 3000);
function change() {
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
setTimeout(change, 3000);
}
function fastChange() {
clearTimeout(reset);
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
}
</script>
</head>
<body>
<input type="button" onclick="fastChange();">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350" id="picture">
</body>
</html>
The reason why your timer resets is because you are not clearing the timeout.
you need to make a reference to the timeout and then use clearTimeout() on it whne you make the fast change. I don't think it is possible or wise to do that inline the way you have it so you code needs to be refactored
let imgSrc1 = 'https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350'
let imgSrc2 = 'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350'
let imgElement = document.getElementById('picture');
let timeout;
function change() {
if(imgElement.src === imgSrc1) {
imgElement.src = imgSrc2;
} else {
imgElement.src = imgSrc1;
  }
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(change, 3000);
}
You don't even need the second function fastChange. Now you can sent the onClick listener to change() like this
document.getElementById('whatever you want to click').onCLick = change;
Setting and clearing timeouts in multiple places will work, but I prefer using a "main loop" and a variable to count frames.
Here's an example that uses setInterval and resets a timer variable when the button was clicked:
const url1 = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
const url2 = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
function change() {
picture.src = picture.src == url1 ? url2 : url1;
}
var timer = 0;
setInterval(function() {
timer++;
time.textContent = timer;
if (timer === 30) fastChange();
}, 100);
function fastChange() {
change();
timer = 0;
}
picture.src = url1;
swap.onclick = fastChange;
#picture {
height: 70vh
}
<button id="swap">SWAP</button> <span id="time"></span><br>
<img id="picture">
You can do this by calling setTimeout and updating the index as necessary. Just be sure to store the most recent timeout id so that it can be cancelled on reset using clearTimeout.
// store the reference to the <img> that contains the picture
const pic = document.getElementById('picture')
// store a list (array) of the two picture urls
const sources = [
'https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350',
'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350'
]
// used to store a reference to the interval timer you created.
var lastTimer
// a starting index of the list (i.e. which image we are up to right now)
var index = 1
// this functions swaps the image and sets a timer
function startRotation() {
// update the index to the next one (goes 0-1-0-1->etc)
index = 1 - index
// sets the .src of the image element
pic.src = sources[index]
// starts a 3 second timer to call this same function again
// but also stores a reference to the timer so that it can be cancelled
lastTimer = setTimeout(startRotation, 3000)
}
// this functions resets the timer and restarts the process
function reset() {
// stop the current timer if there is one
if(lastTimer){
clearTimeout(lastTimer)
}
// restart the process
startRotation()
}
// start the swapping process on start
startRotation()
<input type="button" onclick="reset();">
<img id="picture">
NOT HOW YOU CLEARTIMEOUT:
<html>
<head>
<script>
var i;
function change() {
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
i = setTimeout(change, 3000);
}
function fastChange() {
clearTimeout(i);
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
i = setTimeout(change, 3000);
}
</script>
</head>
<body onload="setTimeout(change, 3000)">
<input type="button" onclick="fastChange();">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350" id="picture">
</body>
</html>

OnMouseOver start loop, OnMouseOut kill loop

I created this little function that loops through images when you go mouse over:
function THUMB_ROLL(NEXT)
{
LENGTH = ALL_IMAGES.length;
if(!LENGTH) { return false; }
if(!NEXT || NEXT === LENGTH) { NEXT = 0 }
$('#IMAGE_THUMB').css('background-image','url(/<?php echo $ITEM_CODE;?>/'+ALL_IMAGES[NEXT]+')');
setTimeout(function()
{
THUMB_ROLL(NEXT+2)
},800);
}
</script>
I have, onmouseover="THUMB_ROLL();"
But, I cannot seem to find a solution to stop the loop once onmouseout. Any help appreciated!
EDIT
<script>
var timer;
function THUMB_ROLL(NEXT)
{
LENGTH = ALL_IMAGES.length;
if(!LENGTH) { return false; }
if(!NEXT || NEXT === LENGTH) { NEXT = 0 }
$('#IMAGE_THUMB').css('background-image','url(/<?php echo $ITEM_CODE;?>/'+ALL_IMAGES[NEXT]+')');
timer = setTimeout(function()
{
THUMB_ROLL(NEXT+1)
},800);
}
$(document).on('mouseover','#IMAGE_THUMB',function()
{
THUMB_ROLL();
});
$(document).on('mouseout','#IMAGE_THUMB',function()
{
clearTimeout(timer);
});
</script>
Assign your timeout to a variable which store the timerID.
Then have the moueout clear the timeout, which should stop the flow.
var timer;
// mouseover event..
timer = setTimeout(function() {
THUMB_ROLL(NEXT+2)
},800);
// mouseout event
clearTimeout(timer);
Also it is a better idea to separate your concerns and attach the events inside the script tags instead of attaching them inline.

Wait until div is not visible to process next line

I need to write some code which is supposed to wait until a predefined div is no longer visible in order to process the next line. I plan on using jQuery( ":visible" ) for this, and was thinking I could have some type of while loop. Does anyone have a good suggestion on how to accomplish this task?
$( document ).ready(function() {
$(".scroller-right" ).mouseup(function( event ) {
alert('right');
pollVisibility();
});
});
function pollVisibility() {
if ($(".mstrWaitBox").attr("visibility")!== 'undefined') || $(".mstrWaitBox").attr("visibility") !== false) {
alert('inside else');
microstrategy.getViewerBone().commands.exec('refresh');
} else {
setTimeout(pollVisibility, 100);
}
}
$( document ).ready(function() {
$(".scroller-right" ).mouseup(function( event ) {
alert('right');
pollVisibility();
});
});
function pollVisibility() {
if (!$(".mstrWaitBox").is(":visible")) {
alert('inside if');
microstrategy.getViewerBone().commands.exec('refresh');
} else {
setTimeout(pollVisibility, 100);
}
}
div when not visible:
<div class=​"mstrWaitBox" id=​"divWaitBox" scriptclass=​"mstrDialogImpl" dg=​"1" ty=​"edt">​
</div>​
div when visible:
<div class=​"mstrWaitBox" id=​"divWaitBox" scriptclass=​"mstrDialogImpl" dg=​"1" ty=​"edt" visibility="visible">​
</div>​
You can use the setTimeout function to poll the display status of the div. This implementation checks to see if the div is invisible every 1/2 second, once the div is no longer visible, execute some code. In my example we show another div, but you could easily call a function or do whatever.
http://jsfiddle.net/vHmq6/1/
Script
$(function() {
setTimeout(function() {
$("#hideThis").hide();
}, 3000);
pollVisibility();
function pollVisibility() {
if (!$("#hideThis").is(":visible")) {
// call a function here, or do whatever now that the div is not visible
$("#thenShowThis").show();
} else {
setTimeout(pollVisibility, 500);
}
}
}
Html
<div id='hideThis' style="display:block">
The other thing happens when this is no longer visible in about 3s</div>
<div id='thenShowThis' style="display:none">Hi There</div>
If your code is running in a modern browser you could always use the MutationObserver object and fallback on polling with setInterval or setTimeout when it's not supported.
There seems to be a polyfill as well, however I have never tried it and it's the first time I have a look at the project.
FIDDLE
var div = document.getElementById('test'),
divDisplay = div.style.display,
observer = new MutationObserver(function () {
var currentDisplay = div.style.display;
if (divDisplay !== currentDisplay) {
console.log('new display is ' + (divDisplay = currentDisplay));
}
});
//observe changes
observer.observe(div, { attributes: true });
div.style.display = 'none';
setTimeout(function () {
div.style.display = 'block';
}, 500);
However an even better alternative in my opinion would be to add an interceptor to third-party function that's hiding the div, if possible.
E.g
var hideImportantElement = function () {
//hide logic
};
//intercept
hideImportantElement = (function (fn) {
return function () {
fn.apply(this, arguments);
console.log('element was hidden');
};
})(hideImportantElement);
I used this approach to wait for an element to disappear so I can execute the other functions after that.
Let's say doTheRestOfTheStuff(parameters) function should only be called after the element with ID the_Element_ID disappears, we can use,
var existCondition = setInterval(function() {
if ($('#the_Element_ID').length <= 0) {
console.log("Exists!");
clearInterval(existCondition);
doTheRestOfTheStuff(parameters);
}
}, 100); // check every 100ms

js/jQuery - exit function by mouse position

I have a recursive function for a kind of image slider.
function nextCol(col) {
$('.menubox_col').fadeOut();
$('.menubox_col').eq(col).fadeIn(function(){
col++;
if (col > 3) col = 0;
setTimeout(function(){ nextCol(col) }, 1000);
});
}
<div id="menubox">
<div class="menubox_col">content</div>
<div class="menubox_col">content</div>
<div class="menubox_col">content</div>
<div class="menubox_col">content</div>
</div>
This works fine, but I found no way to stop the recursive function when the mouse cursor enters the #menubox div.
While you could use clearTimeout and then restart the animation again, you could simply set a flag, which means you don't need to stop and start timers... This will stop the animation when the mouse is over the menubox, and continue it when it leaves. I also took the liberty of making some small code changes - I find the result much simpler:
$(function(){
var col = 0, hover = false;
function nextCol() {
if(hover){return;} // if their mouse is over, do nothing
col = (col+1) % 4; // make this a one-liner. the 4 probably shouldn't be hard-coded though, it could be $('.menubox_col').length
$('.menubox_col').fadeOut().eq(col).fadeIn();
}
setInterval(nextCol, 1000);
$('#menubox').hover(function(){ hover=true; }, function(){ hover=false; });
});
You could clear the timeout using clearTimeout:
var timeoutHandle = null;
function nextCol(col) {
$('.menubox_col').fadeOut();
$('.menubox_col').eq(col).fadeIn(function() {
col++;
if (col > 3) { col = 0; }
timeoutHandle = setTimeout(function() {
nextCol(col);
}, 1000);
});
}
$('#menubox div').mouseenter(function() {
window.clearTimeout(timeoutHandle);
});

Categories

Resources