So I made a simple timer in a format like this: MM:SS.MS
You can view it here [removed]
It works fine in chrome, IE, etc. but in Firefox the seconds are like twice as long..
I took a look at some other stopwatches, but I don't quit understand them.
Whats the best way to do it ? Right now I have a 10ms interval which generates the timer.
The function looks like that, I hope it's understandable:
var state = false;
var msTimer = null;
var min = document.getElementById("min");
var sec = document.getElementById("sec");
var ms = document.getElementById("ms");
var minCount = 0;
var secCount = 0;
var msCount = 0;
document.onkeydown = function timer(e) {
if (!e) { e = window.event; }
if (e.keyCode == "32") {
if (state == false) {
state = true;
min.innerHTML = "00";
sec.innerHTML = "00";
ms.innerHTML = "00";
msTimer = window.setInterval(function() {
if (msCount == 99) {
msCount = 0;
secCount++;
// Minutes
if (secCount == 60) {
secCount = 0;
minCount++;
if (minCount <= 9)
{ min.innerHTML = "0" + minCount; }
else
{ min.innerHTML = minCount; }
}
// Seconds
if (secCount <= 9)
{ sec.innerHTML = "0" + secCount; }
else
{ sec.innerHTML = secCount; }
} else { msCount++; }
// Miliseconds
if (msCount <= 9)
{ ms.innerHTML = "0" + msCount; }
else
{ ms.innerHTML = msCount; }
// 1 Hour
if (minCount == 60) {
clearInterval(msTimer);
min.innerHTML = "N0";
sec.innerHTML = "00";
ms.innerHTML = "0B";
state = false;
minCount = 0;
secCount = 0;
msCount = 0;
}
}, 10);
} else if (state == true) {
state = false;
clearInterval(msTimer);
minCount = 0;
secCount = 0;
msCount = 0;
}
}
Thanks for any advices :)
Edit:
And btw, it's much smoother in firefox, if I remove all styles from the timer.
But that can't be the solution..
You shouldn't be relying on the interval of the timer being exactly 10ms. It would be better if you viewed each timer tick as a request to refresh the on-screen timer, but take the measurements from the system clock or something like that.
Then however slow or busy the machine (and JS implementation) is, you'll always see an accurate timer1 - just one which updates less often.
1 This will only be as accurate as the system clock, of course. If Javascript has access to a high-performance timer like .NET's Stopwatch class or Java's System.nanoTime() method, that would be better to use.
Timing in Javascript is not guaranteed. A 10ms interval will only ever be approximately 10ms, most likely it will be delayed a tiny bit each time. The correct way to do a timer in Javascript is to save a starting timestamp upon starting the timer, then each 10ms or so calculate the difference between the starting timestamp and the current time and update an element on the page with the formatted value.
Related
I have a function called pageReload which sets the a timer and variables back on that page to start, when the time is counting down, however when the timer reaches 0 it seems to disable the function even though when the function is called again the time should be set back to 18 as specified in the function.
When it's between 18 and 0 it trigger ok and sets the time back to 18, the other parts seems to work ok (number of tries and matches set back)
I've tried different variations without getting it to work so below if the function together with the other code in the app which might give a bit of context to what I'm doing
"use strict";
//select each card
const cards = document.querySelectorAll('.card');
let isFlipped = false;
let setBoard = false;
let first, second;
let counter = 1;
//add event listeners to each square
for(let i = 0; i < cards.length; i++) {
let element = cards[i];
element.addEventListener('click', flipSquare);
}
function checkForMatch() {
//check for 2 matching squares
let isMatch = first.classList.value === second.classList.value;
$('#counter').html(`The number of tries made is: ${counter++}`);
isMatch ? disable() : unflip();
//check to see if completed - if so, score will be displayed
completed();
}
function checkScore(){
//determing whether a score A, B or unsuccessful were acheived
if(counter <= 15) {
$('#score').html("You got an A");
}
else if(counter > 15 && counter <= 20){
$('#score').html("You got an B");
} else {
$('#score').html("You had too many attempts and were therefore unsuccessful");
}
}
function completed(){
//pop up if all have been disabled
if($('.card:not(.open)').length === 0){
//display modal
$("#myModal").modal('show');
clearInterval(timerId);
clearTimeout(myTimeout);
elemComplete.html(timeComplete + ' seconds comleted in');
}
//check score on completion and output the result
checkScore();
}
let timeLeft = 18;
let timeComplete;
let elem = $('#some_div');
let elemComplete = $('#new_div');
let timerId = setInterval(showClock, 1000);
function shuffleCards() {
//give square random positions
for(let i = 0; i < cards.length; i++) {
let ramdomPos = Math.ceil(Math.random() * 12);
cards[i].style.order = ramdomPos;
}
}
function pageReload(){
shuffleCards();
//loop through any open cards to and remove their open status and add back click function to unflipped card
for(let i = 0; i < cards.length; i++) {
$(".card").removeClass('open');
let element = cards[i];
element.addEventListener('click', flipSquare);
}
isFlipped = false;
setBoard = false;
timeLeft = 18;
counter = 0;
n = 0;
$('#counter').html(`The number of tries made is: ${counter}`);
$('#updated').html(`The number of matches made is: ${n}`);
counter++;
}
I'm not 100% sure as I don't think this is all of the code, but I have a feeling that you are stopping your timer in the completed() function using clearInterval() and never restarting it?
Presuming this is the cause, I would try resetting the timer in your page reload function.
function pageReload(){
shuffleCards();
//loop through any open cards to and remove their open status and add back click function to unflipped card
for(let i = 0; i < cards.length; i++) {
$(".card").removeClass('open');
let element = cards[i];
element.addEventListener('click', flipSquare);
}
isFlipped = false;
setBoard = false;
timeLeft = 18;
counter = 0;
n = 0;
timerId = setInterval(showClock, 1000);
$('#counter').html(`The number of tries made is: ${counter}`);
$('#updated').html(`The number of matches made is: ${n}`);
counter++;
}
This makes the timer code a little fragile, so you could refactor the timer logic out into its own functions and do something like this to make things a little clearer:
let timerId = undefined;
function startTimer() {
if (timerId != undefined) {
stopTimer();
}
timerId = setInterval(showClock, 1000);
}
function stopTimer() {
clearInterval(timerId);
timerId = undefined;
}
You would then remove all of you existing timer code and call startTimer() in pageReloaded() and stopTimer() in completed()
Im wondering what is wrong with this for loop here. I'm trying to make a Pomodoro Study Timer, a study technique that suggests that you break down studying into 25-minute chunks that are followed by 3-5 minute breaks. here I have 2 timers that run in sequence, one after the other. When the first timer reaches zero, the second one starts. For now, i have timers set to 5 seconds and 3 seconds respectively in order to make testing quicker. It all works fine until I put the whole thing into a for loop which then brings some unexpected behaviour. I want to loop the entire function based on user input which informs the code on how many times to loop the counters(this isnt setup yet).
The timers are started by pressing a button on an html page. The button executes the pomo() function at the bottom, which contains a loop that should loop the start() function.
PS, I'm a total ultra noob so apologies if this is just terrible code, I'm really new to this :)
var time25 = 5;
var time5 = 3;
var timeElapsed25 = 0;
var timeElapsed5 = 0; // initializes time elapsed to zero
var time = document.getElementsByClassName("header"); //links to html
time[0].innerHTML = time25; // sets output to html
function convertToMin(s) {
mins = Math.floor(s / 60);
let minsStr = mins.toString();
if (minsStr.length === 1) {
mins = '0' + mins;
}
sec = s % 60;
let secStr = sec.toString();
if (secStr.length === 1) {
sec = '0' + sec;
}
return mins + ':' + sec;
}
function start() {
var timer25 = setInterval(counter25, 1000);
console.log("timer1");
function counter25() {
timeElapsed25++
time[0].innerHTML = convertToMin(time25 - timeElapsed25);
if (timeElapsed25 === time25) {
console.log("timer2")
clearInterval(timer25);
timeElapsed25 = 0;
var timer5 = setInterval(counter5, 1000);
function counter5() { //Counter For 5 minute break
timeElapsed5++;
time[0].innerHTML = convertToMin(time5 - timeElapsed5);
if (timeElapsed5 === time5) {
clearInterval(timer5);
timeElapsed5 = 0;
}
}
}
}
}
function pomo() {
for (j = 0; j < 3; j++) {
start();
}
}
You shouldn't call start() in a loop. setInterval() doesn't wait for the the countdown to complete, it returns immediately, so you're starting all 3 timers at the same time.
What you should do is call start() again when both timers complete. To put a limit on the number of repetitions, use a count parameter, and decrement it each time you call again.
var time25 = 5;
var time5 = 3;
var timeElapsed25 = 0;
var timeElapsed5 = 0; // initializes time elapsed to zero
var time = document.getElementsByClassName("header"); //links to html
time[0].innerHTML = time25; // sets output to html
function pomo() {
start(3);
}
function start(count) {
if (count == 0) { // reached the limit
return;
}
var timer25 = setInterval(counter25, 1000);
console.log("timer1");
function counter25() {
timeElapsed25++
time[0].innerHTML = convertToMin(time25 - timeElapsed25);
if (timeElapsed25 === time25) {
console.log("timer2")
clearInterval(timer25);
timeElapsed25 = 0;
var timer5 = setInterval(counter5, 1000);
function counter5() { //Counter For 5 minute break
timeElapsed5++;
time[0].innerHTML = convertToMin(time5 - timeElapsed5);
if (timeElapsed5 === time5) {
clearInterval(timer5);
timeElapsed5 = 0;
start(count - 1); // Start the next full iteration
}
}
}
}
}
function convertToMin(s) {
mins = Math.floor(s / 60);
let minsStr = mins.toString();
if (minsStr.length === 1) {
mins = '0' + mins;
}
sec = s % 60;
let secStr = sec.toString();
if (secStr.length === 1) {
sec = '0' + sec;
}
return mins + ':' + sec;
}
I have a game that I am making using only pure javascript. Instead of a GUI, It is more like the old command line games and uses a prompt for input.
One of the main components of it is the Clock, which is expressed in hours, and can be checked with the commmand "time" and tells them the value of the variable "time". Here is the code:
var timestrt = 1;
var timer = setInterval(function(){timestrt++;return timestrt;}, 86000); var time = timestrt;
After testing it, I realized that the clock was not changing. So I set it to 10 seconds instead of 86 to be sure that I was waiting long enough, and it still did not want to work
I know that it is probably caused by the prompt and constant alerts, but I am not sure even where to start for a workaround.
Any ideas?
Edit: is it possible to either
1. retrieve the timer from an external page
2. comparing it to an actual clock in real time or 3. Using a animated gif clock in the background and calculating the location of certain pixels as time?
Don't use the native prompts and dialogs, since they stop the script execution time. Instead use simulated ones, for example jQuery IU has prompts and dialog boxes that do not stop execution. Here is an example of that:
$(function() {
$( "#dialog" ).dialog();
var timestrt = 1;
var timer = setInterval(function(){
timestrt++;
var time = timestrt;
$("#time").text(time);
}, 1000);
});
Here is my workaround:
This code is called before the prompt is started:
function initTime() {
var now = new Date();
stS = now.getSeconds();
stM = now.getMinutes();
stH = now.getHours();
}
This is called after the prompt is done:
function computeTime() {
var now = new Date();
var reS = now.getSeconds();
var reM = now.getMinutes();
var reH = now.getHours();
var elapS = reS - stS;
var elapM = reM - stM;
var elapH = reH - stH;
if (elapM < 0) {
reM = reM + 60;
elapM = reM - stM;
}
if (elapS < 0) {
reS = reS + 60;
elapS = reS - stS;
}
Then I convert it to seconds to make it easier to check against:
var finalH = elapH * 3600;
var finalM = elapM * 60;
var finalS = finalM + elapS + finalH;
And check/change the time variable based on how many sets of 86 seconds has passed:
if (finalS > 86 && finalS < 172) {
time = 1;
}
if (finalS > 172 && finalS < 258) {
time = 2;
}
if (finalS > 258 && finalS < 344) {
time = 3;
}
if (finalS > 344 && finalS < 430) {
time = 4;
}
if (finalS > 430 && finalS < 516) {
time = 5;
}
if (finalS > 516) {
time = 6;
alert('5 A.M.');
alert('A clock is chiming...');
alert('6 A.M.');
playing = false;
alert('Thanks for playing! Goodbye!');
}
And that is my alternative to using a setinterval/timer behind multiple prompts and alerts. The last part probably wasn't needed, but since it answered my original question I included it.
I have been searching the entire day for a solution to this problem. I like this Counter I found on StackOverflow, but because I am inexperienced using JavaScript, I am not entirely sure how to stop it.
I figured out how to set the value and when to start counting etc, but now I want to add a maximum value. IE: If the counter reaches 20 million, then stop.
I tried the following, but it doesn't work:
var simplicity = formatMoney(20000000);
if (amount.innerText <= simplicity){
function update() {
var current = (new Date().getTime() - start)/1000*0.36+0;
amount.innerText = formatMoney(current);
}
setInterval(update,1000);
}
else{
amount.innerText = simplicity;
}
Try this
var max = 20000000;
var intervalId = setInterval(function () {
var current = (new Date().getTime() - start)/1000*0.36+0;
if (current > max) {
amount.innerText = formatMoney(max);
clearInterval(intervalId);
} else {
amount.innerText = formatMoney(current);
}
}, 1000);
Use clearInterval(id) to stop intervals.
Here's my code:
tripper = 2;
$("#topheader").mousewheel(function(event, delta) {
if (tripper == 2){
startPlace = $("#content").scrollLeft();
startCounter = something;
tripper = 1;
} else {
currentPlace = $("#content").scrollLeft();
if(startCounter < 100){ // milliseconds
distanceMoved = currentPlace - startPlace;
if(distanceMoved > 100){
slideRight();
} else if(distanceMoved < -100){
slideLeft();
}
} else {
tripper = 2;
}
}
}
What is the proper way to check if 100 milliseconds has passed sense the first time through this function? In the 5th line of code i have the variable "something" which needs to be replaced with a counter of some sort. Or maybe I'm going about this in an entirely wrong way. Suggestions?
You can instantiate a "Date" object like this:
var then = new Date();
Later you can make another one:
var now = new Date();
Subtraction gives the difference in milliseconds:
var elapsed = now - then;
(The coercion from "Date" to "Number" is implicit when the two date values appear on either side of the subtraction operator. The conversion is just like calling "now.getTime()".)
The following code it is untested but basically, after 100 milliseconds, it should reset timeout back to null and ultimately set tripper back to 2;
tripper = 2;
timeout = null;
$("#topheader").mousewheel(function(event, delta) {
if (tripper == 2){
startPlace = $("#content").scrollLeft();
if (!timeout) {
setTimeout(function() {
timeout = null
}, 100);
}
tripper = 1;
} else {
currentPlace = $("#content").scrollLeft();
if(timeout){ // milliseconds
distanceMoved = currentPlace - startPlace;
if(distanceMoved > 100){
slideRight();
} else if(distanceMoved < -100){
slideLeft();
}
} else {
tripper = 2;
}
}
}