I''m getting input as a stream of x/y coords, and I'd like to trigger an event if those coords fall within a specified range for a given period of time (say 2 seconds). Could someone suggest a way to do this?
Algorithmically, when you first detect that it's in the range, you do a setTimeout() for 2 seconds. From then on, if the coords stay in the bounds and the timer is already set, you do nothing. If the coords fall outside the bounds, you stop the timer with clearTimeout(). If the timer fires before you've cleared it, then the coords have stayed in the bounds for the desired time.
Here's a code example:
var myTimer = null;
function processCoordinatePair(x,y) {
if (inBounds(x,y)) {
if (!myTimer) {
setTimeout(function() {
// we stayed in bounds for 2 seconds, do whatever needs doing
myTimer = null; // clear timer for future use
}, 2000);
}
} else { // not in bounds any more
if (myTimer) {
clearTimeout(mytimer); // if timer was running, stop it
myTimer = null;
}
}
}
The implementation of the inBounds() function is obviously up to you since you haven't described that part of the problem.
Related
I have a problem for tweening my camera.position . I create a codepen with the minimum of code just to reproduce my issue and I annotate all my code. I also put a lot of console.log() for debugging purpose .
Codepen
the start point is my camera.postion
camera.position.z = 30;
and my tween001
var tween001 = gsap.to(camera.position,{ delay:2,duration:5,z:60,onUpdate:function(){
camera.updateProjectionMatrix();
console.log("play");
},onComplete:function(){console.log("complete");},ease:"elastic"});
so the tween is about to move my camera from the Z = 30 to Z = 60
its work perfectly but ... When the user move the camera when the user move/over/click on the 3d its fire and eventlistener that pause "tween001.pause()" I want the tween001 use the "actual" camera.postion and not when the camera.postion used when the tween 001 get fire .
Cause when the tween001 is played again or it resume from a pause the start point used is the default one x=0 y=0 z=30 .
An idle function play the tween001 again
window.setInterval(checkTime, 1000);// every 1 second launch checktime()
function checkTime() { //idleCounter get 1 every second and at 5 second coz timeout is 5 checktime relaunch the tween001
if (idlecounter < timeout) {
idlecounter++;
//console.log("++ ");
} else if (idlecounter == timeout) {
tween001.play();
console.log('timeout');
}
}
So you have to understand that GSAP assumes it's the only thing that's controlling camera.position. So when you declare gsap.to(camera.position, {z: 60}) it'll store internally the starting position (30) and the ending (60) to build its timeline. It doesn't know that you've changed the z-position with the mousewheel, so when you call .play() it'll still assume you want to go from 30 to 60.
What you have to do is re-initialize a new tween each time so it has to look up the starting position when you want to replay it:
var tween001;
function doTween() {
tween001 = gsap.to(camera.position, { delay:2,duration:5, z:60, ease:"elastic", onComplete:function(){
// camera.updateProjectionMatrix();
console.log("complete");
}});
}
Notice that I declared var tween001 outside the function, in the global scope, so you can still call tween001.pause() whenever you need
There's no need to update the projection matrix while changing position.
Now, when you're ready to start the animation again, instead of using tween001.play() you can call doTween() and it'll build a new timeline that re-reads the camera's current z-position to start the animation:
// ...
else if (idlecounter == timeout) {
doTween();
idlecounter = 0;
}
see here for the updated codepen
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);
Using Waypoints and the Inview shortcut, how might I be able to only trigger the handler function if an element is in view for X amount of time, say 5 seconds, rather than trigger immediately on the enter event?
new Waypoint.Inview({
element:document.getElementById('target'),
enter: function(direction) {
// Only do this if in view for 5 seconds
}
});
Note: This question comes from somebody else, asked through the issue tracker. I've copied it here because it's a good question.
This question has two answers, one specific and one general. I'll start with the general.
Any time you want to see if some condition is true for X amount of time you will need to look for:
An event that marks the condition becoming true.
An event that marks the condition becoming false.
When the condition becomes true, you start a timer using setTimeout that will trigger the action you desire after the given time has elapsed. When the condition becomes false, you clear the timer using clearTimeout. If the clearing event happens to fire after the timer has elapsed and the original event has fired, clearing has no effect.
One of the more common uses of this pattern is with mouse events. We sometimes want to trigger something when a user has been hovering over an element for X amount of time. In this next example the "becoming true" event will be mouseenter. The "becoming false" event will be mouseleave. Here we'll log to the console when the user has hovered over an element for five seconds.
var timer;
$('#something')
.on('mouseenter', function() {
timer = window.setTimeout(function() {
console.log('Hovered for 5 seconds');
}, 5000);
})
.on('mouseleave', function() {
window.clearTimeout(timer);
});
The specific answer: You can use this pattern for any of these class of problems in JavaScript, and the Inview events are no different. In this case we'll use enter and exit as the true and false events respectively.
var timer;
Waypoint.Inview({
element: $('#something')[0],
enter: function() {
timer = window.setTimeout(function() {
console.log('In view for 5 seconds');
}
},
exit: function() {
window.clearTimeout(timer);
}
});
For this kind of problem, generally, one starts a timer on enter and stop the timer on exit.
example:
var timerId;
new Waypoint.Inview({
element: document.getElementById('target'),
enter: function(direction) {
timerId = setTimeout(function() {
// Only do this if in view for 5 seconds
}, 5000);
},
exit: function(direction) {
clearTimeout(timerId);
}
});
I have a div displaying some horizontally scrollable images with white-space:nowrap; overflow-x:scroll and i'm trying to make the function below work:
var mouseIsInDiv = false;
function autoScroll() {
var i = 1;
while (mouseIsInDiv = false) {
setTimeout(function(){
document.getElementById("theDiv").scrollLeft = i;
i++;
},50);
}
}
It is supposed to loop through (while the mouse is not within this scrollable div) incrementing the scroll position by 1px every 50 miliseconds. In other words it's supposed to scroll through the images automatically when this function is called. I'm not getting any syntactic errors but whenever i press a button that calls this function on a webpage, the browser crashes completely - I'm using the latest versions of Chrome, Safari and Firefox. Any ideas would be really helpful, I've been tearing my hair out over this!
Your loop creates many timeouts that happens in the same time (after 50 milisecs) you need to set the timeout recursivly, inside the set timeout function, and ask if mouseISInDiv inside the set timeout function as well.
The current code state, the loop will run many many times in a small amount of time, and page will crush(it's liek infinite) and after 50 millisecs there will be many set timeouts that ran.
I had a fun time working on this one, so I'll post my response despite the correct answer already having been accepted.
Basically, you need to restructure everything so that the whole scheme is asynchronous. That means event listeners respond to mouse movement, and there are no while loops.
Thus, I present this fiddle. Here is the javascript:
var mouseIsInDiv = false;
var theDiv = document.getElementById("theDiv");
theDiv.onmouseover = function() { mouseIsInDiv = true; };
theDiv.onmouseout = function() {
mouseIsInDiv = false;
scrollLeft1();
};
function scrollLeft1() {
if (mouseIsInDiv == false && theDiv.scrollLeft < theDiv.clientWidth) {
theDiv.scrollLeft += 1;
setTimeout(scrollLeft1, 50);
}
}
scrollLeft1();
As you can see, the function calls itself recursively and asynchronously, and the whole thing can be restarted after manually resetting the scroll. You could also add an event listener for the scroll completion.
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.