I am currently working on a project that requires the web application to track how long user stays on one slide of a slide show. Say the online slideshow has 5 (slide-1.png to slide-5.png) slides, user can navigate through the slideshow using "Next" and "Previous" button.
User will always start on slide-1.png, after 5 seconds user clicked on "Next" button and goes to slide-2.png. After 10 seconds the user clicked on "Previous" to go back slide-1.png and stayed there for 5 seconds.
This is basically event-based application. The time will start recording when user click on "Next" or "Previous", and stop recording the old session and start recording the new session when user click on "Next" or "Previous" again.
User does not go to a new html page after clicking on "Next"/"Previous". It is simply images changing src information.
Any ideas about how I should approach this? I am currently using PHP, Javascript, and Java in my web application.
You'll want to capture the time when they start viewing a slide:
var startTime = new Date();
Then capture the time when the slide goes away:
var endTime = new Date();
Then you can calculate the elapsed time.
var elapsed = endTime - startTime; // elapsed time in milliseconds
If you need to account for the case where a user opens a slide and then walks away from the computer you could also start a timeout timer that will log the user as having timed out for that slide.
setTimeout(function () {
endTime = 'Timed out.';
}, ((3 * 60) * 60) * 1000); // ((3hrs * 60mins) * 60secs) * 1000ms
After 3 hours it would set the endTime to 'Timed out.' and you could use that to know that the user walked away from that particular slide and didn't finish viewing the rest.
The JavaScript function that loops over and 'sniffs' for the set conditions that you define will work best for this scenario. The approach you should take is to assign each .png it's own ID attribute. Create variables via JavaScript and jQuery that specifically targets each image. Then attach a mousedown or click event to the slideshow that will detect which image is visible and trigger a timer for that specific image. Ofcourse, you will need input fields hidden on the page for each image for the counter to increment into.
In the link, you will see similar functionality whereby when a use clicks on the 'zoom in' component a timer will start. It will only stop when the user clicks out of the image.
The JavaScript function is call setInterval() and can be stopped with clearInterval(). For best results, create the setInterval() function as a variable.
Sample variable:
var firstSlide = jQuery('img#slide1');
Sample Condition 01:
if (firstSlide.length > 0)
{
//start counter with setInterval();
}
Sample Condition 02:
if (firstSlide.is(':visible'))
{
//start counter with setInterval();
}
To ensure minimal overlaps in the timer and ensure stricter behavior, I would suggest applying a unique CSS class to the slideshow container when it is visible on click and to remove it when it is not visible.
Sample Condition 03:
slideShow.click( function() {
slideShow.addClass('isClicked');
});
if (firstSlide.is(':visible') && jQuery('slideShow.isClicked').length > 0)
{
//start counter with setInterval();
}
http://www.alexldixon.com/clicktimerhelp.htm
Another example where the setInvertval can 'sniff' dynamic conditions, is making element heights equal even when the window resizes and text wraps.
https://jsfiddle.net/dixalex/ojoevj1k/
var makeSameHeight = setInterval( function() {
var currentTextHeight = $('div.myClass-content').height() + "px";
var imgDivHeight = $('div.imgUrl').height() + "px";
if (currentTextHeight === imgDivHeight)
{
var doNothing = "";
} else {
$('div.imgUrl, div.postImageUrl, a.myClass').css("height", currentTextHeight);
}
}, 50);
Lastly, you can also use the new Date() function.
I hope this helps.
Related
I would like to implement a slider on top of every page of my website.
however this might be disturbing and annoying when a user starts browsing from page to page, since the slideshow will start over and over again.
I though the solution could lay in the builtin date function:
var d = new Date();
var n = d.getSeconds();
if(n%10 == 0)
{
rotate
}
Or perhaps I could set a cookie with the values from the slider when a user leaves that page (name=topSlider value=1 time=300), so the new page could pick it up and go further in it's sequence.
If I have a online shopping platform, I want to call my REST API after the user stops clicking the add button.
Let's say that he wants 10 products, and he starts clicking the "add" button. I don't want to make a call every time the user presses the "add" button. I want to know when the user stops clicking and then make a call to my server with the quantity = 10.
btw I'm using Angular2.
Add setTimeout(backendCallback, ms) on each click. If clicked again - clear timeout and repeat.
let timer;
let callbackDealy = 800;
onAddClick(){
clearTimeout(timer);
timer = setTimeout(() => {
this.http.get().subscribe(...);
}, callbackDelay);
}
I'm not sure you can reliably predict the end of user interaction in this manner, but that aside, you could do something like this:
var cancelToken;
$("#myButton").click(() => {
cancelToken && clearTimeout(cancelToken);
cancelToken = setTimeout(() => {
alert("5 seconds elapsed")
}, 5000);
});
Clicking the button sets a timer that is cancelled & renewed each time the button is clicked.
Fiddle: https://jsfiddle.net/oop5wyxL/3/
You can use (click) event handler and use a timeout to do the call. When a click is done, you reset the counter. So, you can set the counter to the time you think is correct to ensure the user stopped clicking. Something like this:
html
<button (click)="saveBasket()">
js
timer;
saveBasket(){
if (this.timer) { // RESET THE TIMER IN EVERY CLICK
clearTimeout(this.timer);
this.timer = null;
}
timer = setTimeout(callAPI(), 10000); // CALL THE API AFTER 10 SECONDS
}
The idea you're describing is similar to debouncing; but this isn't a typical use case for such an approach.
Well, if you really want to do it, I suppose you could use a timeout. So in the handler for clicking on Add, set a timeout that waits a short time and then sends the request to the server. (Before setting the timeout for this click, remember to cancel any timeouts from previous clicks or it's all for naught.) But then you also have to watch out for the user navigating away before the timeout expires...
In an angular app, why should a quantity change require a server call anyway? Isn't there something like "submit order" that the user will click once all quantities are set? Is the server call just so the server can recalculate a price to display? If so, do that client-side; that's why you use angular.
I'm creating an audio web player which I would like to function continuously, meaning that when a piece of audio finishes playing, it moves onto playing the next one.
However, I have come across a problem where everything works as it should, but once the previous audio finishes playing, and the next one starts, every 2 seconds, the new one will play & pause; continuously.
This is my current JavaScript code block:
function playPauseButton(button, wave, trackID){
var button = $(button); // play button
if(wave.isPlaying()){ // if the audio is playing and the user clicks play button, pause the audio
button.removeClass("playing");
wave.pause();
} else { // vice versa
button.addClass("playing");
wave.play();
}
waveDuration = wave.getDuration(); // audio duration
var nextTrack = ++trackID; // get the current audio track ID and plus 1 to get the new track ID
setInterval(function(){ // check every 2 seconds if the audio is finished playing
if(wave.getCurrentTime() >= waveDuration){ // if it has, make the play button a pause button
button.removeClass("playing");
$(nextTrack + '-ppbutton').click(); // simulate new track play button click
}
}, 2000);
}
& my very simple HTML play button:
<!-- onclick play audio (if paused), pause audio (if playing) !-->
<div onclick="playPauseButton(this, a2wave, 2);" id="2-ppbutton"></div>
<!-- 2 is the id !-->
I've been trying to figure this out for hours, however, it is still confusing me (I'm not that good at JavaScript)
All help & suggestions are appreciated.
I've tried to comment on everything to help you understand
UPDATE:
Thanks to Vlaz for fixing my issue; really appreciate it! :)
However, if people would still like to make suggestions or edits, you are more than welcome too!
Thanks.
Problem
Your usage of setInterval will launch a new ticker every time the button is pressed. So after three presses, you'd have three of them running. Also, remember that each will be running their own checks, as well. So I believe I know where your problem is, here is an overview
setInterval is called the first time, let's call it intervalPrime. Let's assume the duration of the song is 60 seconds.
The song continues with a check every 2 seconds, eventually ends.
A new setInterval is called when the play button is clicked - this creates a new interval - let's call it intervalSecond. This one will be checking for a new song and new duration, however the details are irrelevant.
The song plays and intervalSecond monitors if it's finished yet.
At the same time intervalPrime is still doing it's check. And since wave.getCurrentTime() likely returns 60 (end of the song), then the check it does is 60 >= 60 which passes, so it clicks the button.
How to avoid it
Remove old intervals
What you could do is ensure you only have one setInterval active at a time. The function returns an ID of the timer, so you could do something akin to this
var currentChecker;
function playPause() {
/* .... */
if (shouldClick) {
clearTimeout(currentChecker);
currentChecker = setInterval( /* ... */ );
}
}
(illustrative)
So, essentially try to maintain a single one by stopping the previous interval before starting a new one.
Keep only one interval
An alternative is to only have one interval active and maintain a state, so you can have something like
var masterLoop = setInterval(function() {
var wave = getCurrentWave(); //fetching it will depend on your application
if(wave.getCurrentTime() >= wave.getDuration()){
/* handle what happens */
}
} , 2000);
Use setInterval when the song finishes.
I'm not familiar with the API you use for playing the sounds, but if it's possible to hook onto the end event, you might be able to use simple setTimeout when that occurs, like so
//assuming the API allows to do something like this
wave.onFinish(function() {
setInterval(playNext, 2000);
})
More than one of these
If the API does not provide a way to hook onto the finished playing event, a better alternative is to combine the last two. Have a master loop that checks the state of the track and when finished, uses setInterval to schedule the next song. The interval delay will probably need to be set lower, but it will lead to a more consistent time between tracks, since a song might end and 0.3 seconds later the interval does it's check and plays the song, or a song might end right after the interval finished, so you'd have a gap of 2 seconds.
Maintain a single setTimeout
It's similar to the first suggestion of clearing old intervals but not exactly the same.
The thing is that you don't need to keep checking if the song has finished playing, because you already know when it will finish. So, when it's played, you can use setTimeout to queue up the next song
//assuming wave returns time in milliseconds
var playNextIn = (wave.getDuration() - wave.getCurrentTime()) + 2000;
nextSongTimer = setTimeout(function() {
/* code to play next song */
}, playNextIn);
So, this way you don't need to keep checking.
However, the only problem would be if a user clicks pause in which case you will need to call clearInterval(nextSongTimer) as it's no longer needed. So this way, you only need to kick off a timer once every time a song is played.
Every time you click the play/pause button, you call setInterval. So you're likely to have several time-based triggers at the same time and the condition probably keeps being true.
What if you replace your call to setInterval with:
var trigger = setInterval(function(){ // check every 2 seconds if the audio is finished playing
if(wave.getCurrentTime() >= waveDuration){ // if it has make the play button, a pause button
button.removeClass("playing");
$(nextTrack + '-ppbutton').click(); // simulate new track play button click
clearInterval(trigger);
}
}, 2000);
I have a user activity on my page. When user is inactive (didnt move mouse) for 30 minutes it prompts user warning that session will expire soon. If user does not click on OK button and stay inactive will be automatically logged out (session destroy).
Now this is being checked in every 25 minutes and everything works fine until user opens multiple tabs of same page. If multiple tabs are opened and user is working on one tab but left the other tab open for 25 minutes it times out.
How do i prevent it from timing out session when multiple tabs are open and user is active in at least one of the tabs meaning user is moving the mouse in at least one of the tabs of the page.
The js code that detects mouse move is below:
timer = 0;
function cIncrement() {
if (timer == 25) {
//25 minutes passed warn user that in 5 minutes it will expire
//here is the code that prompts user with dialog
if (OK clicked on dialog) {
timer = 0;
} else {
//execute logout script.
}
}
if (timer == 30) {
//30 minutes passed log user out
//script to log user out
}
}
$(function() {
var interval = setInterval("cIncrement()", 60000); //increment every minute
//reset timer on mouse move
$(document).mousemove(function(e) {
timer = 0;
});
});
NOTE: the above code works fine when 1 tab is open.
how would i change this so that if 2 or more tabs are open and user is active in any of them should reset timer to 0
Presumably you have a server-side session object. Presumably you also have some kind of expiration time on your server-side session object, so you can reap sessions where users just close their browsers, or just close their laptop lids and go on vacation for a couple of weeks, etc. etc. Presumably activity whichever tab/window has focus resets your server-side activity timeout.
So, in cIncrement, initiate an Ajax request that asks the server how long ago the last activity was, and use the response to reset timer.
If you want to be really aggressive about keeping sessions open even if only mouse movement has been captured, send down your page's current value of timer and use it to move the session refresh time along if it was the most recent activity in that session.
At the moment I am using ajax requests every 10 minutes to update certain content and other time intervals for others.
I do this using jQuery by:
On mouse move, the active page is checked
If the active page has not be updated within the given time interval, the page is updated
I'm doing this because although i want the content to stay up to date, I don't want it to be sending requests in the background (when the user is not using the application). Doing this also means that if the user has not used it for more than the time period, when they start to use it again it will automatically update.
I'm wondering just how efficient this is as whenever the mouse moves the checks are called (and has slowed down performance a bit - especially when trying to click links) - is the a more efficient way to do this?
Thanks!
I would rather activate/reset a timer, on say, 60 seconds, on movement of the mouse, and set your fixed-interval checks to only run if that timer is above zero.
That way, checks aren't made every time the mouse moves, and if the user becomes inactive, update checks stop after 60 seconds.
Another possible solution would be to use the window blur and focus events to determine if the window is active:
var checkForContentUpdates = true;
$(window).focus(function() {
checkForContentUpdates = true;
});
$(window).blur(function() {
checkForContentUpdates = false;
});
Your AJAX routine would then key off of the checkForContentUpdates bool.
I'm sure that there are scenarios where this isn't fool-proof, so you'd likely have to combine this method with other logic.