I created a little script in Javascript, which is supposed to show to all the clients connected on the page some informations, actually an image every 90 seconds. This function is working perfectly fine on my computer, but as soon as I have to reload the page, all the process restart.
I don't know if there is a way to make the server calling this function, like this
//This should be a "server" variable in which users should be able to add their own image :
var images = [
['Canyon', 'https://www.w3schools.com/css/img_fjords.jpg'],
['Car Jumping', 'http://www.gettyimages.fr/gi-resources/images/Embed/new/embed2.jpg'],
['Birds Flying', 'http://ekladata.com/qWGncUdJ7U5k2vvmc1au-ZLnjlc.jpg'],
];
function Display (imagesarray) {
var rnd = Math.floor((Math.random() * imagesarray.length - 1) + 1);
document.getElementById("image").src = imagesarray[rnd][1];
}
function Timer(countDownDate) {
var x = setInterval(function() {
// Get todays date and time
var now = new Date().getTime();
// Find the distance between now an the count down date
var distance = countDownDate - now + 2;
// Time calculations for days, hours, minutes and seconds
var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
var seconds = Math.floor((distance % (1000 * 60)) / 1000);
// Output the result in an element with id="demo"
document.getElementById("countdown").innerHTML = ("0" + minutes).slice(-2) + ":" + ("0" + seconds).slice(-2);
// If the count down is over, write some text
if (distance < 0) {
clearInterval(x);
document.getElementById("countdown").innerHTML = "FINISHED !";
Display(images);
}
}, 1000);
}
//This will call the Timer() function to end it in 01:30, and launch it again 10 seconds after the end of the previous call.
var y = setInterval(Timer(new Date().getTime() + 10000), 500);
p {
text-align : center;
font-size : 48px;
margin : 0px;
}
#note {
text-align : center;
font-size : 12px;
margin : 0px;
}
#image {
display : block;
margin : auto;
width : 150px;
height : 150px;
}
<p id="note">Counting only 10 seconds for example</p>
<p id="countdown">00:10</p>
<img id="image" src="http://vignette4.wikia.nocookie.net/destinypedia/images/b/b9/Unknown_License.png/revision/latest?cb=20130810221651">
Does anyone know how this could be managed by the server, so everybody have the same timer and the same picture displayed at the same time ?
Thanks a lot for your help !
[EDIT 1] The backend language I am using is PHP on this project
Breaking news: Time passes the same way all around the world :-D.
So there is no real need of "persistent connection" or so, as long as the users have set-up the time correctly on their computer. You just need to use the same base date for every user. Timestamps are very good at this because there is no time-zone problem with them.
Also note that it might be a better idea not using setTimeout setInterval for measuring time, because setTimeout could be renamed as runAfterAtLeastThatTimeIfYouDontHaveBetterToDo(). In deed, putting a setIterval(()=>{},1000) does not guarantee it will run every 1s, and you might experience desynchronization if the user switch tabs while browsing. You'd better run the interval function more than every seconds -every 10ms for example- if you want it to be accurate.
Usualy, I use requestAnimationFrame for displaying timer.
code :
In this code, I use the same base date for every users (I didn't put any 10s chill-time because I am lazy, but you can see the idea) :
const startDate = 0; // Unix epoch
const interval = 90000; // 90 seconds
var now = Date.now();
var count = (now - startDate) / interval; // should have run {{count}} times since Unix epoch
var next = Math.ceil(count) * interval + startDate; // so the next time it should run is at timestamp {{next}}
function timer() => {
var now = Date.now();
distance = next - now;
if (now >= next) {
document.getElementById("image").src = "http://domain.tld/my-script.php?now=" + now; // the query string parameter is just to avoid browser caching the image
next += interval;
} else {
var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))
var seconds = Math.floor((distance % (1000 * 60)) / 1000);
document.getElementById("countdown").innerHTML = ("0" + minutes).slice(-2) + ":" + ("0" + seconds).slice(-2);
}
}
var requestID = window.requestAnimationFame(timer);
// use window.cancelAnimationFrame(requestID) to cancel the timer
A note on the img.src part:
this is the only part where the server is mandatory, you must implement a script that will send the image based on time. I added a queryString ?now=timestamp to avoid browser caching the image, and not keeping it up to date, but the server should rely on it's own date/time to display the image, not the one sent by the user.
PS : Note that I don't have anything against persistent connection via websocket or so, but that sounds a bit overkill for just displaying a timer and an image on a regular basis. If you think all your user have set their computer's time correctly and that it's not a big deal if some are not synched, use this solution. Otherwise, go for websocket.
You need to keep a persistent connection with the server possibly through websockets OR you can easily just send a variable from the server which tells the clients in how many seconds the next appearance should start.
Related
I am creating a website for students which will be used to assign exams and I am having difficulties with the timer. The one I am using is made on the frontend in javascript and whenever the page is refreshed the timer startsover. Tried to store the start and end date by converting to epoch and back to datetime but I cannot think of a way to get the timer to the frontend and start counting. The idea is to count 60 minutes and call the submit button as well as to show the countdown without the option to restart the counter.
This is how I store the start and end time in nodejs.
var myDate = new Date();
var startTimeEpoch = myDate.getTime()/1000.0;
var endTimeEpoch = startTimeEpoch + 5400 // Adding 90 minutes to the timer
var startTimeBackToDate = new Date(startTimeEpoch *1000)
var endTimeBackToDate = new Date(endTimeEpoch *1000)
This is the javascript timer I am using and I am wondering if I should use one in the first place.
function startTimer(duration, display) {
var start = Date.now(),
diff,
minutes,
seconds;
function timer() {
diff = duration - (((Date.now() - start) / 1000) | 0);
minutes = (diff / 60) | 0;
seconds = (diff % 60) | 0;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if (diff <= 0) {
start = Date.now() + 1000;
}
}
timer();
setInterval(timer, 1000);
}
window.onload = function () {
var fiveMinutes = "<%= scenario.time %>" * 60,
display = document.querySelector('#time');
startTimer(fiveMinutes, display);
}
As a general response and with the additional information provided, i could propose a solution to make this work.
If your students all have a specific exam entity attached to them, when they register/start an exam, you could retrieve the start date of this exam(add a mongo createdAt Date field) and use it as the starting date.
If each exam has a time limit, then you could simply do the math to know how much time is left. Something that will look like this:
const getExamRemainingTime = (exam) => {
// assuming that start is a js date object
// and timeLimit is an number representing the duration hours of your exam
const { start, timeLimit } = exam;
let end = (start.getHours() + timeLimit);
end = end.setHours(end);
const remainingTime = (+end) - (+start)
if (remainingTime > 0) {
// duration not finished, exam still in progress
return new Date(remainingTime);
} else {
// exam finished
return 0;
}
}
Then in your frontend, if it's plain javascript, you need to refresh your timer component, use setInterval in last ressort because it's very heavy on performance and format the date you got the way you want to show it.
Ref: casting js Date object to timestamp - How do you get a timestamp in JavaScript?.
I don't think a timer that a student with Javascript knowledge can modify should be used for serious tests, but for anything more light-hearted it should be fine.
The best system I can think of for this would be to have the test length stored in the mongodb and when a signed-in user starts the test, have the current time logged for that user. That way, you can calculate time remaining using user.testStart + test.length - Date.now().
I have several web pages that use " " as a placeholder for javascript function output to display a button label. For example, the following is the html that displays the output if the 'clock()' function,
<div id="clock" class="sidebar"> </div>
This one displays 'Login' until the 'log()' function is called, then changes the label to 'Logout',
<div id="login" class="sidebar"> </div>
The javascript references the IDs to direct the output to the labels. Both of these were working until a few days ago, but now are just blank. No label is displayed. Nothing obvious has changed. No updates to the system, etc. The server is running Ubuntu 16.04 lts and apache2 web server.
I have no idea why these would just quit working or where to begin looking for the problem. I have similar code running on a separate server that still works. Are there any workarounds / alternative methods that would produce the output I want?
edit:
Here is the javascript as requested:
function clock() {
var time = new Date(); //get the date
//find what day of the year it is
var start = new Date(time.getFullYear(), 0, 0);
var day = Math.floor((time - start) / (1000 * 60 * 60 * 24));
var offset = time.getTimezoneOffset() / 60;
if ((time.getHours() + offset) > 23) { day + 1; }
//get the fraction part of the day
var hour = time.getUTCHours() / 24;
var minute = time.getUTCMinutes() / 1440;
var sec = time.getUTCSeconds() / 86400;
var fraction = hour + minute + sec;
//display
$('#clock a').html((day + fraction).toFixed(4));
//change clock fontsize to fit well
var width = $('#clock').css('width');
var size = parseInt(width) / 4.75;
size = size + 'px';
$('#clock').css({'font-size':size});
}
/*makes either a login popout or logs someone out*/
function log() {
if ($('#login').html() == "Login") {
window.open("./login.html", "_blank","width=1000,height=500");
}
else { logout(); }
}
I'm trying to learn the basics of jQuery by building certain things and now it's my turn for a stopwatch (which will be used by mobile visitors).
I currently have this: codepen
html
<span id="hours"></span> u |
<span id="minutes"></span> m |
<span id="seconds"></span> s
<button onclick="tickTock()">Start</button>
js
function tickTock () {
var start = -1;
function pad(val) { return val > 9 ? val : "0" + val; }
setInterval(function () {
$("#seconds").html(pad(++start % 60));
$("#minutes").html(pad(parseInt(start / 60, 10) % 60));
$("#hours").html(pad(parseInt(start / 3600, 10)));
}, 1000);
}
After testing for a while I've noticed that after a certain period the time shown isn't correct anymore without closing the tab or browser. I want to achieve maximum reliability regarding the time shown and the time which has passed. The deviation only seems to appear on mobile devices.
Since I'm a beginner I don't know where to start. Is it even possible using js/jQuery?
If you could point me in the right direction that would be appreciated.
The set interval is only semi accurate and does not guarentee you the function runs exactly at 1 second intervals. You could start by taking the timestamp of when the function started and then using your ticktock function to subtract the previous timestamp from the current timestamp and then perform the necessary updates to the ui. I'll leave the padding and rounding out to make the example easy to follow.
function ticktock(){
var start = new Date().valueOf();
setInterval(function(){
var now = new Date().valueOf();
var elapsed = (now - start) / 1000;
var seconds = elapsed % 60;
var minutes = (elapsed / 60) % (60);
var hours = (elapsed / (60 * 60)) % (60);
$("#seconds").html(seconds);
$("#minutes").html(minutes);
$("#hours").html(hours);
}, 1000);
}
Your code can be reworked to store the start time, then to display the difference between the current time and the start time, rather than manually incrementing every second.
This way, if your code gets shelved because it's in the background, the correct time will be calculated.
function tickTock () {
var startTime = new Date();
function pad(val) { return val > 9 ? val : "0" + val; }
setInterval(function () {
var currTime = new Date();
var elapsedMs = currTime.getTime() - startTime.getTime();
var elapsedSeconds = elapsedMs * 1000;
$("#seconds").html(pad(elapsedSeconds % 60));
$("#minutes").html(pad(parseInt(elapsedSeconds / 60, 10) % 60));
$("#hours").html(pad(parseInt(elapsedSeconds / 3600, 10)));
}, 1000);
}
I am trying to make a small question/answer quiz game using react, and I want to show a timer that counts down every second. Each game will last 10, 15, or 30 minutes at most, so I want to show a timer that updates every second in the bottom of the screen (in big font, of course!), something like 15:00, 14:59, 14:58, and so on until it hits 00:00.
So, given a start time such as 2016-04-25T08:00:00Z, and an end time after adding 15 min of 2016-04-25T08:15:00Z, I want to start the countdown.
My issue is that I am not understanding how to use setIntervals to keep calling my method to find the remaining time.
timeLeft = Math.round(timeLeft/1000) * 1000;
const timer = new Date(timeLeft);
return timer.getUTCMinutes() + ':' + timer.getUTCSeconds();
EDIT: You've edited your question. You will need the time padding, and the method below will be faster than what you are using, but to answer your question about setInterval:
First, define your function to run your timer and decrement each time it's called:
var timeLeft; // this is the time left
var elem; // DOM element where your timer text goes
var interval = null; // the interval pointer will be stored in this variable
function tick() {
timeLeft = Math.round(timeLeft / 1000) * 1000;
const timer = new Date(timeLeft);
var time = timer.getUTCMinutes() + ':' + timer.getUTCSeconds();
elem.innerHTML = time;
timeLeft -= 1000; // decrement one second
if (timeLeft < 0) {
clearInterval(interval);
}
}
interval = setInterval(tick, 1000);
OG Answer:
No, I do not believe there is a built-in way to display time differences.
Let's say you have two date objects:
var start = Date.now();
var end = Date.now() + 15 * 60 * 1000; // 15 minutes
Then you can subtract the two Date objects to get a number of milliseconds between them:
var diff = (end - start) / 1000; // difference in seconds
To get the number of minutes, you take diff and divide it by 60 and floor that result:
var minutes = Math.floor(diff / 60);
To get the number of seconds, you take the modulus to get the remainder after the minutes are removed:
var seconds = diff % 60;
But you want these two padded by zeros, so to do that, you convert to Strings and check if they are two characters long. If not, you prepend a zero:
// assumes num is a whole number
function pad2Digits(num) {
var str = num.toString();
if (str.length === 1) {
str = '0' + str;
}
return str;
}
var time = pad2Digits(minutes) + ':' + pad2Digits(seconds);
Now you have the time in minutes and seconds.
I've a problem when running this script for my JavaScript countdown (using this plugin). What it should do is take the starting time, the current time and the end time and display the remaining time.
If I set these values with normal numbers in epoch time everything works just fine, but my question is: How do I set the current time and the start to be the real current one so that the countdown will be dynamic?
I've found this line: Math.round(new Date().getTime()/1000.0);
But I don't know how to make it work, considering I'm running this script at the bottom of my HTML file, before the </html> tag.
This is the script:
<script>
$('.countdown').final_countdown({
start: '[amount Of Time]',
end: '[amount Of Time]',
now: '[amount Of Time]'
});
</script>
This is how I tried to solve it, but it's not working:
//get the current time in unix timestamp seconds
var seconds = Math.round(new Date().getTime()/1000.0);
var endTime = '1388461320';
$('.countdown').final_countdown({
start: '1362139200',
end: endTime,
now: seconds
});
It sounds like you would like to count down from the current time to some fixed point in the future.
The following example counts down and displays the time remaining from now (whenever now might be) to some random time stamp within the next minute.
function startTimer(futureTimeStamp, display) {
var diff;
(function timer() {
// how many seconds are between now and when the count down should end
diff = (futureTimeStamp - Date.now() / 1000) | 0;
if (diff >= 0) {
display(diff);
setTimeout(timer, 1000);
}
}());
}
// wait for the page to load.
window.onload = function() {
var element = document.querySelector('#time'),
now = Date.now() / 1000,
// some random time within the next minute
futureTimeStamp = Math.floor(now + (Math.random() * 60));
// format the display however you wish.
function display(diff) {
var minutes = (diff / 60) | 0,
seconds = (diff % 60) | 0;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
element.innerHTML = minutes + ":" + seconds;
}
startTimer(futureTimeStamp, display);
};
<span id="time"></span>
Also Math.round(new Date().getTime()/1000.0); will give you the number of seconds since the epoch, however it may be a little disingenuous to round the number. I think you would be better served by taking the floor:
var timestamp = Math.floor(Date.now() / 1000)); is probably a better option.
In addition I am not sure why you need the start time, current time and end time. In order to find the remaining number of second you just need to know when the timer should end and the current time.