Starting Javascript intervals nonsynchronously and stop each after three runs - javascript

I have a function for letting blink a OpenLayer marker three times. The simplified version which only shows console messages:
function blink_three_times(layername){
var x = 0;
setTimeout(function() {
blink_in = setInterval(function() {
x = x+1;
if ( x === 3) {clearInterval(blink_in)};
console.log(layername + ' is visible');
}, 500);
}, 250);
blink_out = setInterval(function() {
if (x === 2) {clearInterval(blink_out)};
console.log(layername + ' is invisible');
}, 500);
};
It works fine, but if it is started multiple times before one has finished, the counter (x) exceeds 3 and the interval does not stop. How can I avoid that?

That is because you have funcions blink_in & blink_out in global scope. When you are calling it second time it overwrites the definitions of functions.
Define them using var to make them local.
var blink_in = setInterval(function() {..})
and
var blink_out = setInterval(function() {..})
DEMO

Your variables blink_in and blink_out are global ones so if you call the function multiple times they will override it and therefore cannot stop the interval properly.
Use them in your function scope by definining them with "var" in order to avoid the problem (see http://jsfiddle.net/cb0h8tst/)
function blink_three_times(layername){
var x = 0;
var blink_in, blink_out;
setTimeout(function() {
blink_in = setInterval(function() {
x = x+1;
if ( x === 3) {clearInterval(blink_in)};
console.log(layername + ' is visible');
}, 500);
}, 250);
blink_out = setInterval(function() {
if (x === 2) {clearInterval(blink_out)};
console.log(layername + ' is invisible');
}, 500);
};

Based on your last update question,
you could also make a more dynamic to keep track of the layers that are actually being blinked, a possible example
function Blinker(opt) {
var ts = {};
this.elementId = opt ? opt.elementId : undefined;
this.runs = (opt ? opt.runs : 3) || 3;
this.completed = (opt ? opt.completed : function() { }) || function() { };
this.start = function(arg) {
var timestamp = arg || this.elementId, that = this;
if (typeof ts[timestamp] !== 'undefined') {
console.log('Cannot run multiple times on same layer');
return;
}
ts[timestamp] = {
timestamp: timestamp,
count: 0,
element: document.getElementById(arg || this.elementId),
controller: this
};
setTimeout(function() {
ts[timestamp].showInterval = setInterval(that.setVisibility.bind(ts[timestamp], true), 500);
}, 250);
ts[timestamp].hideInterval = setInterval(this.setVisibility.bind(ts[timestamp], false), 500);
};
this.setVisibility = function(visible) {
this.element.style.visibility = visible ? 'visible' : 'hidden';
this.element.style.display = visible ? 'inherit' : 'none';
if (visible) {
this.count++;
}
if (!visible && this.count === 2)
{
clearInterval(this.hideInterval);
}
if (visible && this.count === 3)
{
clearInterval(this.showInterval);
this.controller.completed.apply(this.controller, [this.element.id]);
delete ts[this.timestamp];
}
};
}
var blinker = new Blinker({
elementId: 'blinker',
runs: 3,
completed: function(elementId) {
var log = document.getElementById('log');
log.innerHTML += '<p><strong>' + elementId + '</strong> has finished blinking</p>';
}
});
you could find the fiddle here: http://jsfiddle.net/q70w0kpx/

Related

Return after clearInterval

I have a code that runs setInterval in a function. What I try to achive is to exit from that function after clearInterval occured. I set up a condition to check wheter the interval is cleared. I'm struggling to find a method to return from the main Start() function based on the current state of the code.
Code:
function Start() {
var elementX = document.getElementById('moveMeX')
var elementY = document.getElementById('moveMeY')
elementY.style.top = "0px"
var posX = 0
startPosX = 0
var posY = 0
startPosY = 0
var speed = 1
var xIsMoving = true
var yIsMoving = true
var myIntervalX = setInterval(function() {
if(startPosX == 0) {
posX+=speed
elementX.style.left = posX + 'px'
if(posX==100) {
startPosX = 100
}
}
else if (startPosX==100) {
posX-=speed
elementX.style.left = posX + 'px'
if(posX==0) {
startPosX = 0
}
}
}, 10);
function stopX() {
clearInterval(myIntervalX);
xIsMoving = false
}
elementX.addEventListener("mousedown", stopX);
elementX.addEventListener("mousedown", startY);
function startY() {
var myIntervalY = setInterval(function() {
if(startPosY == 0) {
posY+=speed
elementY.style.top = posY + 'px'
if(posY==100) {
startPosY = 100
}
}
else if (startPosY==100) {
posY-=speed
elementY.style.top = posY + 'px'
if(posY==0) {
startPosY = 0
}
}
}, 10);
function stopY() {
elementY.style.zIndex = "-1";
clearInterval(myIntervalY);
yIsMoving = false
}
elementY.addEventListener("mousedown", stopY);
}
if (xIsMoving === false && yIsMoving === false) {
console.log('stopped')
stopped = true
}
}
Start()
Codepen link: https://codepen.io/silentstorm902/pen/podNxVy
The part you state you have a problem with,
if (xIsMoving === false && yIsMoving === false) {
console.log('stopped')
stopped = true
}
currently only runs once: when Start() is first called. At that time, both conditions are false because the variables have their initial declared values of true.
You could create a new setInterval to run this if statement every so often, but it seems unnecessary because your current stopY function is really the place where you know that both xIsMoving and yIsMoving are both false -- because stopY only runs after stopX has run. So just move your statement of stopped=true at the end of the stopY function:
function stopY() {
elementY.style.zIndex = "-1";
clearInterval(myIntervalY);
yIsMoving = false;
console.log("stopped");
stopped = true;
}

Stopwatch frontend app stop, when tab is not active [duplicate]

So basically when I switch tabs, the countdown timer on a specific page just stops counting down and resumes when you return to the tab. Is there anyway to mitigate that so that it counts in the background or it accounts for the time you spend on another tab?
This is basically what I have for js:
document.getElementById('timer').innerHTML =
05 + ":" + 01;
startTimer();
function startTimer() {
var presentTime = document.getElementById('timer').innerHTML;
var timeArray = presentTime.split(/[:]+/);
var m = timeArray[0];
var s = checkSecond((timeArray[1] - 1));
if(s==59){m=m-1}
if(m<0){
return
} else if (m == 0 && s == 0) {
location.reload();
}
document.getElementById('timer').innerHTML =
m + ":" + s;
setTimeout(startTimer, 1000);
}
function checkSecond(sec) {
if (sec < 10 && sec >= 0) {sec = "0" + sec};
if (sec < 0) {sec = "59"};
return sec;
}
Any ideas whether the time could be done server side or something so that it can't be modified client side? If not, then whatever, but mainly just want to figure out how to make the countdown still work (or account for the time spent) when on another tab.
We can store the variable m and s values either globally or use the local storage to set the values after setting the inner HTML and get the stored values back whenever tabs were switched as:
Set values:
window.localStorage.setItem('minutes', m.toString()); //same for the seconds
Get values:
window.localStorage.getItem('minutes'); //same for the seconds
Hope this answers your questions.
Just a simple solution:
Add this piece of code.
<html>
<head>
<script>
(function() {
var $momentum;
function createWorker() {
var containerFunction = function() {
var idMap = {};
self.onmessage = function(e) {
if (e.data.type === 'setInterval') {
idMap[e.data.id] = setInterval(function() {
self.postMessage({
type: 'fire',
id: e.data.id
});
}, e.data.delay);
} else if (e.data.type === 'clearInterval') {
clearInterval(idMap[e.data.id]);
delete idMap[e.data.id];
} else if (e.data.type === 'setTimeout') {
idMap[e.data.id] = setTimeout(function() {
self.postMessage({
type: 'fire',
id: e.data.id
});
// remove reference to this timeout after is finished
delete idMap[e.data.id];
}, e.data.delay);
} else if (e.data.type === 'clearCallback') {
clearTimeout(idMap[e.data.id]);
delete idMap[e.data.id];
}
};
};
return new Worker(URL.createObjectURL(new Blob([
'(',
containerFunction.toString(),
')();'
], {
type: 'application/javascript'
})));
}
$momentum = {
worker: createWorker(),
idToCallback: {},
currentId: 0
};
function generateId() {
return $momentum.currentId++;
}
function patchedSetInterval(callback, delay) {
var intervalId = generateId();
$momentum.idToCallback[intervalId] = callback;
$momentum.worker.postMessage({
type: 'setInterval',
delay: delay,
id: intervalId
});
return intervalId;
}
function patchedClearInterval(intervalId) {
$momentum.worker.postMessage({
type: 'clearInterval',
id: intervalId
});
delete $momentum.idToCallback[intervalId];
}
function patchedSetTimeout(callback, delay) {
var intervalId = generateId();
$momentum.idToCallback[intervalId] = function() {
callback();
delete $momentum.idToCallback[intervalId];
};
$momentum.worker.postMessage({
type: 'setTimeout',
delay: delay,
id: intervalId
});
return intervalId;
}
function patchedClearTimeout(intervalId) {
$momentum.worker.postMessage({
type: 'clearInterval',
id: intervalId
});
delete $momentum.idToCallback[intervalId];
}
$momentum.worker.onmessage = function(e) {
if (e.data.type === 'fire') {
$momentum.idToCallback[e.data.id]();
}
};
window.$momentum = $momentum;
window.setInterval = patchedSetInterval;
window.clearInterval = patchedClearInterval;
window.setTimeout = patchedSetTimeout;
window.clearTimeout = patchedClearTimeout;
})();
</script>
</head>
</html>

how to clear all javascript Timeouts?

i have a loop function that in first 5 seconds it runs social1() and in second 5 seconds it runs social2() then loop ...
i have 2 hover functions too
i need clear all active timeouts because when i hover on images (.social1 & .social2), i can see that multiple timeouts are running
how to fix this?
function social1() {
$('.social1').fadeTo(500, 1);
$('.social2').fadeTo(500, 0.5);
timeout = setTimeout(function() {
social2();
}, 5000);
}
function social2() {
$('.social1').fadeTo(500, 0.5);
$('.social2').fadeTo(500, 1);
timeout = setTimeout(function() {
social1();
}, 5000);
}
$(document).ready(function ()
{
social1();
$('.social1').hover(
function () {
window.clearTimeout(timeout);
social1();
},
function () {
timeout = setTimeout(function() {
social2();
}, 5000);
}
);
$('.social2').hover(
function () {
window.clearTimeout(timeout);
social2();
},
function () {
timeout = setTimeout(function() {
social1();
}, 5000);
}
);
__EDIT__
To manage a collection of timeouts (and intervals), you could use following snippet.
This will allow to clear any timeouts or intervals set anywhere in code, although, you have to set this snippet before setting any timeout or interval. Basically, before processing any javascript code or external script which uses timeout/interval.
JS:
;(function () {
window.timeouts = {},
window.intervals = {},
window.osetTimeout = window.setTimeout,
window.osetInterval = window.setInterval,
window.oclearTimeout = window.clearTimeout,
window.oclearInterval = window.clearInterval,
window.setTimeout = function () {
var args = _parseArgs('timeouts', arguments),
timeout = window.osetTimeout.apply(this, args.args);
window.timeouts[args.ns].push(timeout);
return timeout;
},
window.setInterval = function () {
var args = _parseArgs('intervals', arguments),
interval = window.osetInterval.apply(this, args.args);
window.intervals[args.ns].push(interval);
return interval;
},
window.clearTimeout = function () {
_removeTimer('timeouts', arguments);
},
window.clearInterval = function () {
_removeTimer('intervals', arguments);
},
window.clearAllTimeout = function () {
_clearAllTimer('timeouts', arguments[0]);
},
window.clearAllInterval = function () {
_clearAllTimer('intervals', arguments[0]);
};
function _parseArgs(type, args) {
var ns = typeof args[0] === "function" ? "no_ns" : args[0];
if (ns !== "no_ns")[].splice.call(args, 0, 1);
if (!window[type][ns]) window[type][ns] = [];
return {
ns: ns,
args: args
};
}
function _removeTimer(type, args) {
var fnToCall = type === "timeouts" ? "oclearTimeout" : "oclearInterval",
timerId = args[0];
window[fnToCall].apply(this, args);
for (var k in window[type]) {
for (var i = 0, z = window[type][k].length; i < z; i++) {
if (window[type][k][i] === timerId) {
window[type][k].splice(i, 1);
if (!window[type][k].length) delete window[type][k];
return;
}
}
}
}
function _clearAllTimer(type, ns) {
var timersToClear = ns ? window[type][ns] : (function () {
var timers = [];
for (var k in window[type]) {
timers = timers.concat(window[type][k]);
}
return timers;
}());
for (var i = 0, z = timersToClear.length; i < z; i++) {
_removeTimer(type, [timersToClear[i]]);
}
}
}());
How to use it:
Set timeout(s)/interval(s) as usual:
var test1 = setTimeout(function(){/**/, 1000);
var test2 = setTimeout(function(){/**/, 1000);
Then you could use to clear both:
clearAllTimeout(); // clearAllInterval(); for intervals
This will clear both timeouts (test1 & test2)
You can use some namespaces to clear only specific timers, e.g:
// first (optional) parameter for setTimeout/setInterval is namespace
var test1 = setTimeout('myNamespace', function(){/**/, 1000); // 'myNamespace' is current namespace used for test1 timeout
var test2 = setTimeout(function(){/**/, 1000); // no namespace used for test2 timeout
Again, clearAllTimeout(); will clear both timeouts. To clear only namespaced one, you can use:
clearAllTimeout('myNamespace'); // clearAllInterval('myNamespace'); for namespaced intervals
This will clear only test1 timeout
You could for some reason wish to delete non namespaced timeouts only. You could then use:
clearAllTimeout('no_ns'); // clearAllInterval('no_ns'); for non namespaced intervals only
This will clear only test2 timeout in this example
See jsFiddle DEMO
__END of EDIT__
Old post specific to opening question here:
You could try that:
var timeouts = [];
timeouts.push(setTimeout(function() {
social2();
}, 5000));
timeouts.push(setTimeout(function() {
social1();
}, 5000));
//etc...
function clearAllTimeouts(){
for(var i = 0, z = timeouts.length; i < z; i++)
clearTimeout(timeouts[i]);
timeouts = [];
}
UPDATED following David Thomas comment
var timeouts = {'social' : [], 'antisocial' : []};
//a social timeout
timeouts.social.push(setTimeout(function() {
social1();
}, 5000));
//an anti-social timeout
timeouts.antisocial.push(setTimeout(function() {
antisocial1();
}, 5000));
function clearTimeouts(namespace){
for(var i = 0, z = timeouts[namespace].length; i < z; i++)
clearTimeout(timeouts[namespace][i]);
timeouts[namespace] = [];
}
//usage e.g
clearTimeouts("social");
//Incase if you are looking for full fledged code
var dict = {};
function checkForIntervals(id){
var index = index;
var result = findOrAddProperty(id);
if(result.length != 0){
clearTimeoutsFor(id);
}
dict[id].push(setTimeout(function(){alertFunc(id,index);}, 60000));
};
// to clear specific area timeout
function clearTimeoutsFor(namespace){
for(var i = 0, z = dict[namespace].length; i < z; i++)
clearTimeout(dict[namespace][i]);
dict[namespace] = [];
}
to clear all timeouts
function clearAllTimeOuts(){
for (key in dict) {
for(var i = 0, z = dict[key].length; i < z; i++)
clearTimeout(dict[key][i]);
dict[key] =[];
}
};
function findOrAddProperty(str){
var temp = [];
for (key in dict) {
if(key == str){
if (dict.hasOwnProperty(key)) {
temp = dict[key];
break;
}
}
}
if(temp.length == 0){
dict[str] = [];
}
return temp;
};
function alertFunc(id,index) {
jQuery(document).ready(function($) {
do the ajax call here after 1 min
});
};

Accessing a jQuery Closure function outside

I have this code embedded in my file for managing session time out. This was referred from http://www.fairwaytech.com/2012/01/handling-session-timeout-gracefully/
I want to call SessionManager.extend() for all the ajax request
complete. So i can automatically refresh my session manager time.
This is what i tried
<script type="text/javascript">
$(document).ajaxSuccess(function (event, xhr, settings) {
if (xhr.status === 200) {
SessionManager().extend();
}
});
</script>
Getting an error that SessionManager object not found. How do we call this?
Below is the library code taken from that site
$(function () { // Wrap it all in jQuery documentReady because we use jQuery UI Dialog
// HtmlHelpers Module
// Call by using HtmlHelpers.getQueryStringValue("myname");
var HtmlHelpers = function () {
return {
// Based on http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript
getQueryStringValue: function (name) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
};
} ();
// StringHelpers Module
// Call by using StringHelpers.padLeft("1", "000");
var StringHelpers = function () {
return {
// Pad string using padMask. string '1' with padMask '000' will produce '001'.
padLeft: function (string, padMask) {
string = '' + string;
return (padMask.substr(0, (padMask.length - string.length)) + string);
}
};
} ();
// SessionManager Module
var SessionManager = function () {
// NOTE: globalTimeoutPeriod is defined in _Layout.cshtml
var sessionTimeoutSeconds = HtmlHelpers.getQueryStringValue('smt') || (globalTimeoutPeriod),
countdownSeconds = HtmlHelpers.getQueryStringValue('smc') || 300,
secondsBeforePrompt = sessionTimeoutSeconds - countdownSeconds,
$dlg,
displayCountdownIntervalId,
promptToExtendSessionTimeoutId,
originalTitle = document.title,
count = countdownSeconds,
extendSessionUrl = '/Session/Extend',
expireSessionUrl = '/Session/Expire?returnUrl=' + location.pathname;
var endSession = function () {
$dlg.dialog('close');
location.href = expireSessionUrl;
};
var displayCountdown = function () {
var countdown = function () {
var cd = new Date(count * 1000),
minutes = cd.getUTCMinutes(),
seconds = cd.getUTCSeconds(),
minutesDisplay = minutes === 1 ? '1 minute ' : minutes === 0 ? '' : minutes + ' minutes ',
secondsDisplay = seconds === 1 ? '1 second' : seconds + ' seconds',
cdDisplay = minutesDisplay + secondsDisplay;
document.title = 'Expire in ' +
StringHelpers.padLeft(minutes, '00') + ':' +
StringHelpers.padLeft(seconds, '00');
$('#sm-countdown').html(cdDisplay);
if (count === 0) {
document.title = 'Session Expired';
endSession();
}
count--;
};
countdown();
displayCountdownIntervalId = window.setInterval(countdown, 1000);
};
var promptToExtendSession = function () {
$dlg = $('#sm-countdown-dialog')
.dialog({
title: 'Session Timeout Warning',
height: 250,
width: 350,
bgiframe: true,
modal: true,
buttons: {
'Continue': function () {
$(this).dialog('close');
refreshSession();
document.title = originalTitle;
},
'Log Out': function () {
endSession(false);
}
}
});
count = countdownSeconds;
displayCountdown();
};
var refreshSession = function () {
window.clearInterval(displayCountdownIntervalId);
var img = new Image(1, 1);
img.src = extendSessionUrl;
window.clearTimeout(promptToExtendSessionTimeoutId);
startSessionManager();
};
var startSessionManager = function () {
promptToExtendSessionTimeoutId =
window.setTimeout(promptToExtendSession, secondsBeforePrompt * 1000);
};
// Public Functions
return {
start: function () {
startSessionManager();
},
extend: function () {
refreshSession();
}
};
} ();
SessionManager.start();
});
Remove the var prefix from SessionManager.
Bit of info here about scope, http://msdn.microsoft.com/en-us/library/ie/bzt2dkta(v=vs.94).aspx

JavaScript countdown timer not starting

I tried using this JavaScript countdown timer on my page but the timer won't start.
What am I doing wrongly?
var CountdownID = null;
var start_msecond = 9;
var start_sec = 120;
window.onload = countDown(start_msecond, start_sec, "timerID");
function countDown(pmsecond, psecond, timerID) {
var msecond = ((pmsecond < 1) ? "" : "") + pmsecond;
var second = ((psecond < 9) ? "0": "") + psecond;
document.getElementById(timerID).innerHTML = second + "." + msecond;
if (pmsecond == 0 && (psecond-1) < 0) { //Recurse timer
clearTimeout(CountdownID);
var command = "countDown("+start_msecond+", "+start_sec+", '"+timerID+"')";
CountdownID = window.setTimeout(command, 100);
alert("Time is Up! Enter your PIN now to subscribe!");
}
else { //Decrease time by one second
--pmsecond;
if (pmsecond == 0) {
pmsecond=start_msecond;
--psecond;
}
if (psecond == 0) {
psecond=start_sec;
}
var command = "countDown("+pmsecond+", "+psecond+", '"+timerID+"')";
CountdownID = window.setTimeout(command, 100);
}
}
<span style="color:red" name="timerID" id="timerID">91.6</span>
here is what you need to do first
window.onload = countDown(start_msecond, start_sec, "timerID");
should be
window.onload = function () {
countDown(start_msecond, start_sec, "timerID");
}
also you should avoid using a string in your setTimeout function:
CountdownID = window.setTimeout(function () {
countDown(pmsecond,psecond,"timerID");
}, 100);
See here http://jsbin.com/ifiyad/2/edit

Categories

Resources