I've got the following problem:
I'm using Google Maps on my site. I've attached the following eventListener to the map itself:
google.maps.event.addListener(map, 'bounds_changed', scheduleDelayedCallback);
The event bounds_changed is called every time someone drags the map. My Problem is, that it is called several times during the drag process. Now I need to find a way to call the callback function only, if it wasn't called during the last, let's say, 750 milliseconds.
I did this using these two functions:
function fireIfLastEvent() {
var now = new Date().getTime();
if (lastEvent.getTime() + 750 <= now) {
this_function_needs_to_be_delayed();
} else {
$("#main").html('Lade...');
}
}
function scheduleDelayedCallback() {
lastEvent = new Date();
setTimeout(fireIfLastEvent, 750);
}
This method works great in Chrome and Opera. In IE it works sometimes, in Firefox it never works (it calls the functions even if the 750 milliseconds haven passed).
Is there any rock-solid way to timeout a function call?
Thanks.
You shouldn't need a timeout here.
function scheduleDelayedCallback() {
var now = new Date();
if (now.getTime() - lastEvent.getTime() >= 750) {
// minimum time has passed, go ahead and update or whatever
$("#main").html('Lade...');
// reset your reference time
lastEvent = now;
}
else {
this_function_needs_to_be_delayed(); // don't know what this is.
}
}
Your explanation of what you want to happen isn't the clearest so let me know if the flow is wrong.
Related
I am using open layers 4. I am moving and stoping marker animation as this example without any problem. But I want to add pause and continue functionality to marker also. I edit some variables and endeavor on the issue with these functions. When I call continueAnimation function at first, the elapsedTime parameter become negative and give exception on moveFeature function. When I secondly call the continueAnimation function. It is working as expected. It is looking like kind of javascript implementation issue.
function pauseAnimation() {
animating = false;
//I hold elapsed time globally
var index = Math.round($("[id='rightfrm:tbv1:txt1']").val() * elapsedTime / 1000);
(geoMarker.getGeometry()).setCoordinates(line_coordinates[index].lc);
map.un('postcompose', moveFeature);
}
function continueAnimation() {
animating = true;
now = new Date().getTime();
now = now - 10000 + elapsedTime; // --10000-- for negativeness
geoMarker.setStyle(null);
map.on('postcompose', moveFeature);
map.render();
}
I found my problem. It was a logical error. Pause and Continue working now.
now = new Date().getTime() - elapsedTime;
Anyone can use these functions for Pause/Continue functionality.
I'm encountering some issues with JavaScript's watchPosition and clearWatch functions that I don't quite understand, would appreciate it if someone could help out.
First off, the function in question...
function location(x){
var getLocation;
var lat_input = $(x).find(".latitude");
var lon_input = $(x).find(".longitude");
var acc_input = $(x).find(".accuracy");
function showPosition(position) {
latitude = position.coords.latitude;
longitude = position.coords.longitude;
accuracy = position.coords.accuracy;
$(lat_input).val(latitude);
$(lon_input).val(longitude);
$(acc_input).val(accuracy);
setTimeout(function(){
navigator.geolocation.clearWatch(getLocation);
alert('done');
}, 10000);
};
getLocation = navigator.geolocation.watchPosition(showPosition, null, {maximumAge: 0, timeout: Infinity, enableHighAccuracy: true});
};
In particular, my problem is with the code in the setTimeout section.
When I run this function on my laptop, everything starts out ok - the .longitude, .latitude, and .accuracy fields are populated accordingly. After 10 seconds, setTimeout is triggered - I can't say if clearWatch runs successfully (since the computer is pretty limited in its ability to find itself), but the odd behavior that I note here is that alert('done') is triggered twice.
When I run this function on my phone (the intended platform), everything gets off to a similarly good start, but after 10 seconds, alert('done') starts triggering endlessly, sometimes in immediate succession, sometimes with a few seconds in between. Most distressing, however, is that clearWatch doesn't appear to run at all - that lat, long, and accuracy fields continuously update after the 10 second mark.
If anyone can see what I am doing wrong here, your guidance would be much appreciated.
I hit a similar issue. I found the following code did not stop the watch:
navigator.geolocation.clearWatch(locationID);
STEP 1: Create a variable and assign it to navigator.geolocation
var geoLoc = navigator.geolocation;
var geoWatchID = geoLoc.watchPosition(
onGPSSuccess, onGPSError,
{ maximumAge: 300, timeout: 1500, enableHighAccuracy: true });
STEP 2: Stop Watch use the var geoloc not navigator.geolocation.clearWatch()
geoLoc.clearWatch(geoWatchID);
geoWatchID = null;
See http://www.tutorialspoint.com/html5/geolocation_clearwatch.htm
Without knowing the libraries to re-create the code, I can't duplicate the issue so I can only give something to try.
Add a timer variable to your outer scope.
clearTimeout(timer);
timer = setTimeout(function(){
navigator.geolocation.clearWatch(getLocation);
alert('done');
}, 10000);
I am creating a Google Script that includes this code:
ScriptApp.newTrigger("fetchTweets")
.timeBased()
.everyMinutes(1)
.create();
How can I change this to trigger the event every ten seconds instead of once every minute?
A solution similar to this should work for you, it's working correctly in my test area:
function callSixTimes() {
fetchTweets();
for(var i = 1; i <= 5; i++)
{
Utilities.sleep(10000);
fetchTweets()
}
}
function generateTriggers() {
var everyMinute = ScriptApp.newTrigger("callSixTimes")
.timeBased()
.everyMinutes(1)
.create();
}
According to this post in google groups, this appears to be the recommended way to achieve this level of granularity. Please note that even after the trigger is deleted, the function with settimeout in it may continue to fire until it finishes looping.
I have a jQuery slider on my site and the code going to the next slide is in a function called nextImage. I used setInterval to run my function on a timer, and it does exactly what I want: it runs my slides on a timer. BUT, if I go to the site in Chrome, switch to another tab and return, the slider runs through the slides continuously until it 'catches up'. Does anyone know of a way to fix this. The following is my code.
setInterval(function() {
nextImage();
}, 8000);
How to detect when a tab is focused or not in Chrome with Javascript?
window.addEventListener('focus', function() {
document.title = 'focused';
},false);
window.addEventListener('blur', function() {
document.title = 'not focused';
},false);
To apply to your situation:
var autopager;
function startAutopager() {
autopager = window.setInterval(nextImage, 8000);
}
function stopAutopager() {
window.clearInterval(autopager);
}
window.addEventListener('focus', startAutopager);
window.addEventListener('blur', stopAutopager);
Note that in the latest version of Chromium, there is either a bug or a 'feature' which is making this less reliable, requiring that the user has clicked at least once anywhere in the window. See linked question above for details.
I post an answer here: How can I make setInterval also work when a tab is inactive in Chrome?
Just do this:
setInterval(function() {
$("#your-image-container").stop(true,true);
nextImage();
}, 1000);
inactive browser tabs buffer some of the setInterval or setTimeout functions.
stop(true,true) - will stop all buffered events and execute immadietly only last animation.
The window.setTimeout() method now clamps to send no more than one timeout per second in inactive tabs. In addition, it now clamps nested timeouts to the smallest value allowed by the HTML5 specification: 4 ms (instead of the 10 ms it used to clamp to).
A few ideas comes to mind:
Idea #1
You can make it so that a short burst is idempotent. For example, you could say:
function now() {
return (new Date()).getTime();
}
var autopagerInterval = 8000;
function startAutopager() {
var startImage = getCurrentImageNumber();
var startTime = now();
var autopager = setInterval(
function() {
var timeSinceStart = now() - startTime();
var targetImage = getCurrentImageNumber + Math.ceil(timeSinceStart/autopagerInterval);
if (getCurrentImageNumber() != targetImage)
setImageNumber(targetImage); // trigger animation, etc.
},
autopagerInterval
);
return autopager;
}
This way even if the function runs 1000 times, it will still run in only a few milliseconds and animate only once.
note: If the user leaves the page and comes back, it will have scrolled. This is probably not what the original poster wants, but I leave this solution up since it is sometimes what you want.
Idea #2
Another way to add idempotence (while still keeping your nextImage() function and not having it scroll to the bottom of the page) would be to have the function set a mutex lock which disappears after a second (cleared by another timeout). Thus even if the setInterval function was called 1000 times, only the first instance would run and the others would do nothing.
var locked = false;
var autopager = window.setInterval(function(){
if (!locked) {
locked = true;
window.setTimeout(function(){
locked=false;
}, 1000);
nextImage();
}
}, 8000);
edit: this may not work, see below
Idea #3
I tried the following test:
function f() {
console.log((new Date()) + window.focus());
window.setTimeout(f, 1000);
}
f();
It seems to indicate that the function is being called every second. This is odd... but I think this means that the callbacks are being called, but that the page renderer refuses to update the page in any graphical way while the tab is unfocused, delaying all operations until the user returns, but operations keep piling up.
Also the window.focus() function doesn't say if the window has focus; it GIVES focus to the window, and is thus irrelevant.
What we want is probably this: How to detect when a tab is focused or not in Chrome with Javascript? -- you can unset your interval when the window loses focus (blur), and reset it when it gains focus.
I don't know exactly what is going on in your function nextImage(), but I had a similar issue. I was using animate() with setInterval() on a jQuery image slider that I created, and I was experiencing the same thing as you when I switched to a different tab and back again. In my case the animate() function was being queued, so once the window regained focus the slider would go crazy. To fix this I just stopped the animate() function from queuing.
There are a couple ways you can do this. the easiest is with .stop(), but this issue and ways to fix it are documented in the jQuery docs. Check this page near the bottom under the heading additional notes: http://api.jquery.com/animate/
I had faced similar issue, somehow this code below works fine for me.
var t1= window.setInterval('autoScroll()', 8000);
window.addEventListener('focus', function() {
focused = true;
window.clearInterval(t1);
t1 = window.setInterval('autoScroll()', 8000);
},false);
window.addEventListener('blur', function() {
focused = false;
window.clearInterval(t1);
},false)
function autoScroll()
{
if ( running == true){
if ( focused = true){
forwardSlide();
}
}
else {
running = true;
}
}
If you are using Soh Tanaka's image slider then just add this...to solve your Google Chrome issue:
$(".image_reel").stop(true, true).fadeOut(300).animate({ left: -image_reelPosition}, 500 ).fadeIn(300);
Take note of the .stop() function. Ignore the fading in and out stuff, that's what I used on my version
Thanks
Seconding the comment by jgerstle to use page visibility events instead, see https://www.w3.org/TR/page-visibility/#example-1-visibility-aware-video-playback for more around subscribing to 'visibilitychange' for hidden/visible states.
This seems to be more useful than focus/blur these days as it covers visible-but-not-selected windows if concerned also about multi-window operating systems.
I'm writing a script for a form-faces xforms product that is keyed off an event built into form faces. The event is called 'xforms-ready'. I have define 'startTime' as happening as soon as the document in 'ready'. What I want the script to do is warn the user that it is taking too long before the 'xforms-ready' happens, say if it's been 6 seconds since 'startTime'. I can easily do things when the 'xforms-ready' event happens using the code below:
new EventListener(document.documentElement,
"xforms-ready",
"default",
function() {
var endTime = (new Date()).getTime();
}
);
however the warning will want to happen before 'endTime' is defined. So I guess I want something that works like this:
If 6 seconds has passed since startTime and endTime is not yet defined do X
or possibly more efficiently:
If 6 seconds has passed since startTime and 'xforms-ready' has not yet happened do X
Can anyone suggest a way of doing this?
You can do this with setTimeout. (Complete example below.) In jQuery's ready handler, set a function to be called in six seconds via setTimeout, and in your xforms ready handler, cancel that via clearTimeout if it hasn't happened yet.
Edit Complete example (rather than my earlier fragmented code snippets), assumes it's okay if your xforms ready handler is within your jQuery ready handler:
jQuery.ready(function() {
var xformsReadyTimer;
xformsReadyTimer = setTimeout(function() {
// Too long, show the warning
xformsReadyTimer = undefined;
alert("XForms is taking too long!");
}, 6000);
new EventListener(document.documentElement,
"xforms-ready",
"default",
function() {
if (xformsReadyTimer) {
// Cancel the warning
clearTimeout(xformsReadyTimer);
xformsReadyTimer = undefined;
}
}
);
});
(You might consider making those named functions rather than anonymous ones, but I've used anonymous ones above for simplicity.)