So I created a stopwatch in JavaScript and HTML for a project, it's just a generic stopwatch, and for the start_timer() function I used the setTimeout() function to determine the speed. But when I run the files in my browser they appear to be counting too slowly as the seconds are out of sync. Video here to illustrate how slow the clock is: https://drive.google.com/file/d/1mqB4w5ZX7YqW8C57HhgWtIC63eyfKaGe/view?usp=sharing
I feel like this is a really dumb question but help much appreciated ;) I was wondering if I need to use a web worker or something (this is my first full-scale javascript project so I'm new to some things) Code below
var isTiming = false; //as mentioned in the Design, this is to determine whether the stopwatch IS counting or IS NOT
var speed = 10; //10 milliseconds count allowing for hundredths of a millisecond for better accuracy
var binaryTrue = 0; //checks to see if the stopwatch is paused
function start_stopwatch() { //function to start the counting
if (isTiming == true) {
var stopwatch = document.getElementById("TimeTable").innerHTML; //set the stopwatch to the digital clock in the HTML
//use of an array to display elapsed time in the format hh:mm:ss:lll
//each chronological place value is at a different spot in the array from left to right (numeric values)
var arr = stopwatch.split(":");
/*splits the array by separating each value (seconds, minutes, etc.) everytime there is a ":"
when a button is pressed */
var hr = arr[0]; //first position :hr: at the first space of the array
var min = arr[1]; //seccond position :mm at the second space of the array
var sec = arr[2]; //third position :ss at the third space of the array
var millisec = arr[3]; //fourth position :lll at the fourth space of the array
//Counting up in normal digital clock format, executes every 10 milliseconds which allows for hundredths of a second
//returns next value after 10 milliseconds are up
millisec++;
if (millisec < 10) {
millisec = "0" + millisec;
}
if (millisec / 100 === 1) {
millisec = 0;
millisec = "0" + millisec;
if (sec / 59 === 1) {
sec = 0;
sec = "0" + sec; //added in after the place value displayed as "0" and not "00"
if (min / 59 === 1) {
hr++;
min = 0;
min = "0" + min; //added in after the place value displayed as "0" and not "00"
sec = 0;
sec = "0" + sec; //added in after the place value displayed as "0" and not "00"
} else {
min++;
if (min < 10) {
min = "0" + min;
}
}
} else {
sec++;
if (sec < 10) {
if (sec < 1) {
sec = "0" + "0" + sec;
} //added in after it was displayed as "0" not "00"//
else {
sec = "0" + sec;
}
} else {
if (sec < 1) {
sec = "0" + sec;
}
}
}
}
//update the HTML digital time
document.getElementById("TimeTable").innerHTML = hr + ":" + min + ":" + sec + ":" + millisec; //modify the array to the updated time
setTimeout(start_stopwatch, (speed /* * ((6/7)/1.072)*/ )); //THIS TENDS TO BE OUT OF SYNC AS IT IS SLOWER THAN A NORMAL CLOCK. SO * ((6/7)/1.072) TO IMPROVE SPEED.
document.getElementById("control").innerHTML = "Pause";
}
}
//function to allow the user to change the speed of counting as desired, and as many times as they like
//
function change_speed() {
speedInput = window.prompt("Enter speed, where '1' = 1 second or '2' counts twice as fast, or '0.5' counts slower.");
//Input validation/verification as the user should only input an actual number, whether a float or an integer.
//isNaN is a useful function here where NaN means "Not a Number"
if (isNaN(speedInput)) { //if the value that the user puts in to change the speed into isn't actually (only) a number
speedInput = window.prompt("Enter speed AS A NUMBER where '1' = 1 second or '2' counts twice as fast, or '0.5' counts slower. Numbers only.");
}
speedLength = speedInput.length; //defensive design in the form of input validation - minimum length
speedInputHolder = speedInput;
speedInput = 1 / speedInputHolder; //converts speed requested by the USER into counting length (e.g. 2x speed = 0.5 second length, which is 2x faster, so accessible user interface)
if (speedInput === null) { // "Cancel" button pressed
speed = speed;
} else {
if (speedLength > 0) {
speedInputInMilliseconds = (speedInput * 10); //not * 1000 as tenth-seconds are included too
speed = (speedInputInMilliseconds /** ((60/7)/1.072)*/ ); //need to make sure the 4.275 method still syncs*/
}
}
if (speedInputHolder == 1) {
var indicateSpeed = document.getElementById("speedIndicator").innerHTML = "Counting speed: " + "(" + (1 / speedInput) + "x speed" + ")";
var indicateInterval = document.getElementById("FractionalIndicator").innerHTML = "Counting frequency: " + speedInput + " second."
} else {
var indicateSpeed = document.getElementById("speedIndicator").innerHTML = "Counting speed: " + "(" + (1 / speedInput) + "x speed" + ")";
var indicateInterval = document.getElementById("FractionalIndicator").innerHTML = "Counting frequency: " + speedInput + " seconds."
}
}
function change_state() { //function to change from start to pause or pause to start
if (isTiming == false) {
isTiming = true;
binaryTrue = 1;
start_stopwatch();
var started = document.getElementById("control").innerHTML = "Pause";
console.log("Timer started.");
} else {
stop_stopwatch();
console.log("Timer stopped.");
}
}
function reset() {
if (binaryTrue == 1) {
var reset = document.getElementById("TimeTable").innerHTML = "00" + ":" + "00" + ":" + "00" + ":" + "00";
if (isTiming == false) {
var started = document.getElementById("control").innerHTML = "Start";
}
console.log("Timer reset.");
} else {
if (binaryTrue == 0) {
var reset = document.getElementById("TimeTable").innerHTML = "00" + ":" + "00" + ":" + "00" + ":" + "00";
if (isTiming == false) {
var started = document.getElementById("control").innerHTML = "Start/Pause";
console.log("Timer reset.");
}
}
}
}
//Pausing the stop watch, so STOPPING it from continuing counting
//Set the isTiming variable as FALSE which controls the start_timer function from continuing
function stop_stopwatch() {
isTiming = false;
document.getElementById("control").innerHTML = "Resume";
console.log("Timer stopped.");
}
//the same as stop_stopwatch but also RESETS the stopwatch
/* if isTiming is already FALSE and so the timer is paused
change button label into "Start/Pause"
otherwise make isTiming to be FALSE and reset the timer to 00:00:00:00
and reset the label to "start"
(leave the label as "Start/Pause" if the stopwatch isn't used at least once yet so that the user can still see the original instructions")*/
function stop_and_reset_stopwatch() {
if (binaryTrue == 0) { //if the timer hasn't been used at least once
if (isTiming == false) {
document.getElementById("control").innerHTML = "Start/Pause"; //the user won't have knowledge of the instructions yet
}
} else {
isTiming = false;
document.getElementById("TimeTable").innerHTML = "00" + ":" + "00" + ":" + "00" + ":" + "00";
if (binaryTrue == 0) { //if the stopwatch HASN'T been used yet at least once, meaning that binaryTrue is still 0
document.getElementById("control").innerHTML = "Start/Pause";
} else { //if the stopwatch HAS been used at least once, meaning that binaryTrue is 1
document.getElementById("control").innerHTML = "Start";
}
}
console.log("Timer stopped and reset.");
}
<link href="https://fonts.googleapis.com/css2?family=Dosis:wght@600&display=swap" rel="stylesheet">
<div class="Stopwatch">
<div class="SpeedIndicator">
<div class="IntervalIndicator">
<div class="CountTable">
<p><span id="TimeTable" style="color: #00ffbf; font-size: 200px;">00:00:00:00</span></p>
<div class="Controllers">
<button id="control" onclick="change_state();">Start/Pause </button>
<button id="reset" onclick="reset();">Reset </button>
<button id="stop" onclick="stop_and_reset_stopwatch();">Stop and Reset</button>
<button id="speed" onclick="change_speed();">Change speed</button>
<script type="text/javascript" src="timer.js"></script>
<p><br><span id="Label" style="color: #00ffbf; font-size: 100px; font-weight: bold; font-family: Arial, Helvetica, sans-serif">hr:min:sec:hundredth</span></br>
</p>
<heading id="speedIndicator" style="color: #00aba3; font-size: 20px; font-family: Arial">Stopwatch speed: 1 second (default) </heading>
<br>
<heading id="FractionalIndicator" style="color: #00aba3; font-size: 10px; font-family: Arial"></heading>
</br>