Link to home
Start Free TrialLog in
Avatar of FrankTech
FrankTech

asked on

Modify JS Script to Treat Timer as Object, and Interact with Other Timers on Page

  How would the following script (thanks to Expert hielo) be modified to easily have any number of these stopwatches running at once on a form page?
     The goal is to allow multiple projects to be timed (but only one at a time), so clicking the Start button on any of the clocks would automatically make any other clock stop running.
     For example, if stopwatch 1 is running, and then I click "Start" on Stopwatch 2, then clock #1 should automatically stop and the button for # 1 should automatically change to say "Start" so it can be started later.  Meanwhile, # 2 runs until some other clock's button is clicked.
<html>
<head>
<title>Javascript Stopclock</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script LANGUAGE="JavaScript">
 var timerRunning = false;
 var timerID = null;
// create instance of Date object representing current time
 var initial = new Date();
 
// start timer
 function start_clock() {      
        // set the button's label to "stop"     
                document.forms['clock'].general.value = "stop";        
        // assign the stop function reference to the button's onClick event handler     
                document.forms['clock'].general.onclick = stop;        
       
		initial=new Date();
		if( document.forms['clock'].displayScreen.value )
		{
			var t1 = 
 
String(document.forms['clock'].displayScreen.value).split(".");
			var t2 = t1[0].split(":");
			initial.setSeconds( initial.getSeconds() - parseInt(t2[2]) );
 
			t1=t2=null;
		}	
        // assign milliseconds since 1970 to global variable    
                startTime = initial.getTime();   
        // make sure the timer is stopped       
                stopTimer(); 
        // run and displayScreen timer        
                showTimer();
}
 
// set button to initial settings
function stop() {
        // set the button's label to "start"    
                document.forms['clock'].general.value = "start";       
        // assign the start_clock function reference to the button's onClick event handler   
 
 
                document.forms['clock'].general.onclick = start_clock;       
        // stop timer   
                stopTimer();
}
        // stop timer
function stopTimer() {  
        // if the timer is currently running    
                if (timerRunning)               
        // clear the current timeout (stop the timer)           
                clearTimeout(timerID)   
        // assign false to global variable because timer is not running 
                timerRunning = false
}
 
function showTimer() {  
        // create instance of Date representing current timer   
               var current = new Date(); 
 
        // assign milliseconds since 1970 to local variable     
                var curTime = current.getTime(); 
        // assign difference in milliseconds since timer was cleared    
                var dif = curTime - startTime;           
        // assign difference in seconds to local variable       
                var result = dif / 1000; 
        // is result is not positive    
                if (result < 1)         
        // attach an initial "0" to beginning           
                result = "0" + result;           
        // convert result to string     
                result = result.toString();
			 var hrs = parseInt(result/3600);
			 var mins = parseInt(result/60);
			 var secs = (result%1000);
			 hrs = (hrs < 10) ? "0" + hrs: hrs;
			 mins = (mins < 10) ? "0" + mins: mins;
			 secs = String(secs).split(".");
			 var secs = (parseInt(secs[0]%60) < 10) ? "0" + secs[0]%60 : 
 
secs[0]%60;
        // place result in text field   
                document.forms['clock'].displayScreen.value = hrs+":"+mins+":"+secs;   
 
        // call function recursively immediately (must use setTimeout to avoid overflow)     
 
   
                timerID = setTimeout("showTimer()", 0);  
        // timer is currently running   
                timerRunning = true;
}
</script>
</head>
 
<body bgcolor="#FFFFFF" text="#000000">
<form name="clock">
 <input TYPE="text" NAME="displayScreen" value="00:00:00"
 onFocus="this.blur()" size="20">
 <input TYPE="button" NAME="general" VALUE="start"  onClick="start_clock();">
</form>
 
</body>
</html>

Open in new window

Avatar of HonorGod
HonorGod
Flag of United States of America image

Each timer would require it's own object.
I would have each object know the associated page "display" element, as well as its own timer handle (analagous to a thread id).

Does this make sense?
Avatar of FrankTech
FrankTech

ASKER

HonorGod,
   Yes, that makes sense, and there's actually a script here on EE that uses that idea with a different  stopwatch routine. ( http:Q_21223865.html ID 12703291) I'm looking to do something similar with the script posted in my code snippet (instead of the routine in ID 12703291).
      I also need help to apply this to all buttons (for each of the multiple timers): lines 14, 16, 40, 44, etc. of the script posted in my question, where the script programatically changes the label and function of the button.
      If it's running, the button says "Stop" and has a Stop function; but if it's stopped, the button says "Start" and has a Start function.  
      I need to apply that concept to any/all timers on the page, so starting any one will automatically pause any/all of the others.  There should never be more than one running; and any clock that is paused should be able to restart at the time where it left off. When the new clock's Start button is clicked, the other running clock would stop.

   (By the way,  Expert "hielo" might be planning to help with this, as  hielo  had already provided a solution to another question about this script, to add a pause function.  But if not, I would appreciate your help. Thanks.)
Not quite right... I'll take a look at it when I get home...
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Javascript Stopclock</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script type='text/javascript'>
  //------------------------------------------------------------------
  // Name: start_clock()
  // Role: Used to start the specified timer
  //------------------------------------------------------------------
  function start_clock( id ) {
    var field = document.getElementById( id );
    if ( field ) {
      began = new Date();
      var t1  = field.value.split(".");
      var t2  = t1[0].split(":");
      began.setSeconds( began.getSeconds() - parseInt( t2[ 2 ] ) );
      field.setAttribute( 'began', began );
      showTimer( id );
    } else {
      alert( 'Expected field not found.  id = "' + id + '"' );
    }
  }
 
  //------------------------------------------------------------------
  // Name: stop_clock()
  // Role: Used to stop the specified timer
  //------------------------------------------------------------------
  function stop_clock( id ) {
    var field = document.getElementById( id );
    if ( field ) {
      var tid = field.getAttribute( 'timerID' );
      if ( tid ) {
        clearTimeout( tid );
        field.removeAttribute( 'timerID' );
      }
    } else {
      alert( 'Expected field not found.  id = "' + id + '"' );
    }
  }
 
  //------------------------------------------------------------------
  // Name: showTimer()
  // Role: Used to update the specified timer field
  //------------------------------------------------------------------
  function showTimer( id ) {
    var field = document.getElementById( id );
    if ( field ) {
      var current = new Date();        // current Date/Time object
      var curTime = current.getTime(); // # milliseconds since 1970
      var startTime = field.getAttribute( 'began' );
      var dif = curTime - startTime;   // Elapsed milliseconds
      var result = dif / 1000;         // difference in seconds ...
      if ( result < 1 )                // is result is not positive
        result = '0' + result;         // prepend "0"
        result = result.toString();    // convert to string
        var hrs = parseInt( result / 3600 );
        var mins = parseInt( result / 60 );
        var secs = ( result % 1000 );
        hrs  = ( hrs < 10 ) ? '0' + hrs : hrs;
        mins = ( mins < 10 ) ? '0' + mins : mins;
        secs = parseInt( String( secs ).split(".")[ 0 ] ) % 60;
        secs = ( secs < 10 ) ? '0' + secs : secs;
        field.value = hrs + ':' + mins + ':' + secs; // display result
          // call function recursively immediately (must use setTimeout to avoid overflow)
        var tid = setTimeout( 'showTimer("' + id + '")', 0 );
        field.getAttribute( 'timerID', tid );
    } else {
      alert( 'Expected field not found.  id = "' + id + '"' );
    }
  }
</script>
</head>
 
<body>
<form name='clock' action=''>
  <table border='1'>
    <tr>
      <td>
        <input type='text'   id='clock1' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_clock("clock1");'>
      </td>
      <td>
        <input type='button' value='stop'  onClick='stop_clock("clock1");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock1");'>
      </td>
    </tr>
    <tr>
      <td>
        <input type='text'   id='clock2' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_clock("clock2");'>
      </td>
      <td>
        <input type='button' value='stop'  onClick='stop_clock("clock2");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock2");'>
      </td>
    </tr>
  </table>
</form>
 
</body>
</html>

Open in new window

Didn't see your update until just now...  I have to leave, but I will get back to it.
OK. Thanks.
HonorGod (and  hielo  if you will be commenting):
     Sorry, please use this revised version of the script that I had posted in the code snippet of my question.  Hielo improved it after I posted my question.  (This one should display the hours:minutes:seconds properly when counting past 1 hour.)
   
     I just discovered an issue, though.  Once the time goes past 1 hour, the time is not accurate when resuming after a pause.  For example:
     -  I stopped it at 01:05:17.   When I resumed, it started at 01:05:06  instead of 01:05:18.
      -  When stopped at 01:17:23, it resumed at 01:17:43 instead of 01:17:44.
      -  When stopped at 1:17:45, it restarted at 01:17:05.

Examples of another problem:

     -  When running at  01:18:59, the next number was  01:18:00  instead of  01:19:00.

     -  When running from 01:19:59, it went to 01:19:00 , and counted up to 01:19:20 ; then it changed to 01:20:21.

      As part of this question, I hope you can help solve this issue.
  Thanks.
<html>
<head>
<title>Javascript Stopclock</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script LANGUAGE="JavaScript">
 var timerRunning = false;
 var timerID = null;
// create instance of Date object representing current time
 var initial = new Date();
 
// start timer
 function start_clock() {      
        // set the button's label to "stop"     
                document.forms['clock'].general.value = "stop";        
        // assign the stop function reference to the button's onClick event handler     
                document.forms['clock'].general.onclick = stop;        
       
		initial=new Date();
		if( document.forms['clock'].displayScreen.value )
		{
			var t2 = String(document.forms['clock'].displayScreen.value).split(":");
			//var t2 = t1[0].split(":");
			initial.setHours( initial.getHours() - parseInt(t2[0]) );
			initial.setMinutes( initial.getMinutes() - parseInt(t2[1]) );
			initial.setSeconds( initial.getSeconds() - parseInt(t2[2]) );
 
			t1=t2=null;
		}	
        // assign milliseconds since 1970 to global variable    
                startTime = initial.getTime();   
        // make sure the timer is stopped       
                stopTimer(); 
        // run and displayScreen timer        
                showTimer();
}
 
// set button to initial settings
function stop() {
        // set the button's label to "start"    
                document.forms['clock'].general.value = "start";       
        // assign the start_clock function reference to the button's onClick event handler    
                document.forms['clock'].general.onclick = start_clock;       
        // stop timer   
                stopTimer();
}
        // stop timer
function stopTimer() {  
        // if the timer is currently running    
                if (timerRunning)               
        // clear the current timeout (stop the timer)           
                clearTimeout(timerID)   
        // assign false to global variable because timer is not running 
                timerRunning = false
}
 
function showTimer() {  
        // create instance of Date representing current timer   
               var current = new Date(); 
 
        // assign milliseconds since 1970 to local variable     
                var curTime = current.getTime(); 
        // assign difference in milliseconds since timer was cleared    
                var dif = curTime - startTime;           
        // assign difference in seconds to local variable       
                var result = dif / 1000; 
        // is result is not positive    
                if (result < 1)         
        // attach an initial "0" to beginning           
                result = "0" + result;           
        // convert result to string     
                result = parseFloat(result.toString());
			 var hrs = parseInt(result/3600);
			 var mins = parseInt(result/60);
			 var secs = (parseInt(result)%1000);
			 hrs = (hrs < 10) ? "0" + hrs: hrs;
			 mins = ((mins%60) < 10) ? "0" + mins%60: mins%60;
			 secs = String(secs).split(".");
			 var secs = (parseInt(secs[0]%60) < 10) ? "0" + secs[0]%60 : secs[0]%60;
        // place result in text field   
                document.forms['clock'].displayScreen.value = hrs+":"+mins+":"+secs;   
 
        // call function recursively immediately (must use setTimeout to avoid overflow)        
                timerID = setTimeout("showTimer()", 0);  
        // timer is currently running   
                timerRunning = true;
}
</script>
</head>
 
<body bgcolor="#FFFFFF" text="#000000">
<form name="clock">
 <input TYPE="text" NAME="displayScreen" value="00:00:00"
 onFocus="this.blur()" size="20">
 <input TYPE="button" NAME="general" VALUE="start"  onClick="start_clock();">
</form>
 
</body>
</html>

Open in new window

More on the timing problem past 1 hour:
    20 seconds  seems to be a key factor.
It seems to always lose 20 seconds when restarting after a pause.
    Example:   Paused at 01:39:47 , and it restarts at  01:39:27 (20 seconds less).
   
The strange thing is, so far it seems to be working OK after it reaches 01:40:xx .
Update:   I'm up in the  01:57:00  area, and it's acting up again.  Paused at 01:56:29 or so, and it resumed at  01:56:09.  Then counted up to 01:56:20, then skipped to 01:57:21, or something like that.
    When paused at  01:57:25,  it resumed at 01:57:45 (gained 20 seconds).
    What paused at 01:57:50, it resumed at  01:57:10 (lost 40 seconds).
Ah..  Lots of additional information.  I hadn't realized that you only wanted 1 timer running at a time.

Do you want a reset mechanism (e.g., button)?


How does this look?

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title> Javascript Stopclock </title>
<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
<script type='text/javascript'>
  //------------------------------------------------------------------
  // Name: D2()
  // Role: Prepend a '0' (if necessary) to make a two digit number
  //------------------------------------------------------------------
  function D2( val ) {
    return ( val < 10 ) ? '0' + val : val;
  }
 
  //------------------------------------------------------------------
  // Name: field()
  // Role: Look for document element having specified ID attribute
  //------------------------------------------------------------------
  function field( id ) {
    var obj = document.getElementById( id );
    if ( !obj ) {
      alert( 'Specified element not found: id = "' + id + '"' );
    }
    return obj;
  }
 
  //------------------------------------------------------------------
  // Name: Hours()
  // Role: Extract the hours portion of a HH:MM:SS value
  //------------------------------------------------------------------
  function Hours( val ) {
    var d = val.split( ':' );
    return parseInt( d[ 0 ], 10 );
  }
 
  //------------------------------------------------------------------
  // Name: Minutes()
  // Role: Extract the minutes portion of a HH:MM:SS value
  //------------------------------------------------------------------
  function Minutes( val ) {
    var d = val.split( ':' );
    return parseInt( d[ 1 ], 10 );
  }
 
  //------------------------------------------------------------------
  // Name: Seconds()
  // Role: Extract the minutes portion of a HH:MM:SS value
  //------------------------------------------------------------------
  function Seconds( val ) {
    var d = val.split( ':' );
    return parseInt( d[ 2 ], 10 );
  }
 
  //------------------------------------------------------------------
  // Name: reset_clock()
  // Role: Reset timer field value
  //------------------------------------------------------------------
  function reset_clock( id ) {
    var obj = field( id );
    if ( obj ) {
      obj.value = '00:00:00';
    }
  }
 
  //------------------------------------------------------------------
  // Name: HMS2s()
  // Role: Convert HH:MM:SS time to seconds
  //------------------------------------------------------------------
  function HMS2s( val ) {
    return ( ( ( Hours( val ) * 60 ) + Minutes( val ) ) * 60 ) + Seconds( val );
  }
 
  var timerID   = null;
  var startTime = null;                // When did/does timer begin?
  
  //------------------------------------------------------------------
  // Name: start_stop()
  // Role: Used to start/stop the specified timer
  //------------------------------------------------------------------
  function start_stop( obj, id ) {
    var val = field( id ).value;       // Current HH:MM:SS value
    if ( obj && obj.type == 'button' ) {
      if ( obj.value == 'start' ) {
        obj.value = 'stop';            // change button from start -> stop
        //------------------------------------------------------------
        // Adjust timer based upon current HH:MM:SS value
        //------------------------------------------------------------
        var began = new Date();        // Current date/time
        began.setHours( began.getHours() - Hours( val ) );
        began.setMinutes( began.getMinutes() - Minutes( val ) );
        began.setSeconds( began.getSeconds() - Seconds( val ) );
        
        startTime = began.getTime();        
        showTimer( id );
        
      } else {
        obj.value = 'start';           // Change button from stop -> start
        clearTimeout( timerID );
      }
    } else {
      alert( 'specified element missing, or of wrong type' );
    }
  }
 
  //------------------------------------------------------------------
  // Name: showTimer()
  // Role: Used to update the specified timer field
  //------------------------------------------------------------------
  function showTimer( id ) {
    var obj = field( id );
    if ( obj ) {
      var current = new Date();        // current Date/Time object
      var curTime = current.getTime(); // # milliseconds since 1970
      var dif = curTime - startTime;   // Elapsed milliseconds
      var sec = dif / 1000;            // difference in seconds ...
      var hrs = parseInt( sec / 3600 );
      sec %= 3600;
      var min = parseInt( sec / 60 );
      sec = parseInt( sec % 60 );
      obj.value = D2( hrs ) + ':' + D2( min ) + ':' + D2( sec );
      timerID = setTimeout( 'showTimer("' + id + '")', 500 );
    }
  }
</script>
</head>
 
<body>
<form name='clock' action=''>
  <table border='1'>
    <tr>
      <td>
        <input type='text'   id='clock1' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock1");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock1");'>
      </td>
    </tr>
    <tr>
      <td>
        <input type='text'   id='clock2' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock2");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock2");'>
      </td>
    </tr>
  </table>
</form>
<div id='debug'></div>
</body>
</html>

Open in new window

Well, one question that comes to mind is

- What else is going on on your computer at the time?

The updated value is based upon the current system clock, so if somehow the browser doesn't get to execute (and it takes awhile for the showTimer() method to get called, then the computed "elapsed time" may hesitate.  At least if your system is "too busy".

Does this make sense?
HonorGod,
   Regarding ID:20764914, it looks good, and seems to work well, although it's been running for only a few seconds.
   I probably won't need the reset button, but I can take it out later.

   On the timing issue, no unusual activity or memory load is on my computer. There is no lag in showing the clock starting to run after pause; it's just that the wrong numbers show up (usually the number shown is minus 20 seconds, or plus 20 seconds). So it's not delaying in starting to count, it's just loosing track of time while paused (or that's how it seems to me).

   The main additional feature (as mentioned in my original question), is for any running clock to stop when another clock is started.
    For example, say Clock 1 is running. When I click "Start" for Clock 2,  six things should happen:
    a) Clock 1 should pause.
    b) Clock 1's button should change to say "Start"
    c) Clock 1's button function should change to the start function.
    d) Clock 2 should begin running.
    e) the button for Clock 2 should change to "Stop"
    f) the function of Clock 2's button should become the stop function;

Currently, the last 3 are happening (d, e, & f). How can we make a, b, & c  happen also, no matter which clock is running (e.g., there could be 10 clocks, and clicking any one should stop whatever one is running.) How would that be coded?
Well, the code that I provided doesn't have a whole lot in common with what was provided earlier.  So, I'm curious to see if the same issue occurs.

That's for pointing out my oversight.  One moment please... :-)

Here's a question for you though..

Timer #1 - I press the "Start" button.
  According to your request, the value of that button is supposed to be changed to "Stop".

Timer #2 - I now press this "Start" button.
  What is supposed to happen to the value of Timer #1?  Since the timer is being stopped, shouldn't the button value be reset to Start?
Like this?
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title> Javascript Stopclock </title>
<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
<script type='text/javascript'>
  //------------------------------------------------------------------
  // Name: D2()
  // Role: Prepend a '0' (if necessary) to make a two digit number
  //------------------------------------------------------------------
  function D2( val ) {
    return ( val < 10 ) ? '0' + val : val;
  }
 
  //------------------------------------------------------------------
  // Name: field()
  // Role: Look for document element having specified ID attribute
  //------------------------------------------------------------------
  function field( id ) {
    var obj = document.getElementById( id );
    if ( !obj ) {
      alert( 'Specified element not found: id = "' + id + '"' );
    }
    return obj;
  }
 
  //------------------------------------------------------------------
  // Name: Hours()
  // Role: Extract the hours portion of a HH:MM:SS value
  //------------------------------------------------------------------
  function Hours( val ) {
    var d = val.split( ':' );
    return parseInt( d[ 0 ], 10 );
  }
 
  //------------------------------------------------------------------
  // Name: Minutes()
  // Role: Extract the minutes portion of a HH:MM:SS value
  //------------------------------------------------------------------
  function Minutes( val ) {
    var d = val.split( ':' );
    return parseInt( d[ 1 ], 10 );
  }
 
  //------------------------------------------------------------------
  // Name: Seconds()
  // Role: Extract the minutes portion of a HH:MM:SS value
  //------------------------------------------------------------------
  function Seconds( val ) {
    var d = val.split( ':' );
    return parseInt( d[ 2 ], 10 );
  }
 
  //------------------------------------------------------------------
  // Name: reset_clock()
  // Role: Reset timer field value
  //------------------------------------------------------------------
  function reset_clock( id ) {
    var obj = field( id );
    if ( obj ) {
      obj.value = '00:00:00';
    }
  }
 
  //------------------------------------------------------------------
  // Name: HMS2s()
  // Role: Convert HH:MM:SS time to seconds
  //------------------------------------------------------------------
  function HMS2s( val ) {
    return ( ( ( Hours( val ) * 60 ) + Minutes( val ) ) * 60 ) + Seconds( val );
  }
 
  var timerID   = null;
  var startTime = null;                // When did/does timer begin?
  var eButton   = null;                // Start/Stop button element
  
  //------------------------------------------------------------------
  // Name: start_stop()
  // Role: Used to start/stop the specified timer
  //------------------------------------------------------------------
  function start_stop( obj, id ) {
    var val = field( id ).value;       // Current HH:MM:SS value
    if ( obj && obj.type == 'button' ) {
      if ( obj.value == 'start' ) {
        //------------------------------------------------------------
        // It is possible for multiple buttons to exist on the page,
        // however, we only want 1 timer to be actively counting.
        //------------------------------------------------------------
        if ( timerID ) {
          clearTimeout( timerID );
          timerID = null;
          eButton.value = 'start';
        }
 
        eButton = obj;
        obj.value = 'stop';            // change button from start -> stop
        //------------------------------------------------------------
        // Adjust timer based upon current HH:MM:SS value
        //------------------------------------------------------------
        var began = new Date();        // Current date/time
        began.setHours( began.getHours() - Hours( val ) );
        began.setMinutes( began.getMinutes() - Minutes( val ) );
        began.setSeconds( began.getSeconds() - Seconds( val ) );
        
        startTime = began.getTime();        
        showTimer( id );
        
      } else {
        obj.value = 'start';           // Change button from stop -> start
        clearTimeout( timerID );
        timerID = null;
        eButton = null;
      }
    } else {
      alert( 'specified element missing, or of wrong type' );
    }
  }
 
  //------------------------------------------------------------------
  // Name: showTimer()
  // Role: Used to update the specified timer field
  //------------------------------------------------------------------
  function showTimer( id ) {
    var obj = field( id );
    if ( obj ) {
      var current = new Date();        // current Date/Time object
      var curTime = current.getTime(); // # milliseconds since 1970
      var dif = curTime - startTime;   // Elapsed milliseconds
      var sec = dif / 1000;            // difference in seconds ...
      var hrs = parseInt( sec / 3600 );
      sec %= 3600;
      var min = parseInt( sec / 60 );
      sec = parseInt( sec % 60 );
      obj.value = D2( hrs ) + ':' + D2( min ) + ':' + D2( sec );
      timerID = setTimeout( 'showTimer("' + id + '")', 500 );
    }
  }
</script>
</head>
 
<body>
<form name='clock' action=''>
  <table border='1'>
    <tr>
      <td>
        <input type='text'   id='clock1' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock1");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock1");'>
      </td>
    </tr>
    <tr>
      <td>
        <input type='text'   id='clock2' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock2");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock2");'>
      </td>
    </tr>
  </table>
</form>
</body>
</html>

Open in new window

OK, here's an example:

a. Page loads, 10 clocks all have  00:00:00

b.  I click "Start" on clock 1. (Clock starts running, and its button changes to say "Stop")

c.  I decide to use clock 5.  I click "Start" on Clock 5.

d.  Clock 1 stops/pauses (and holds the time that it reached, say 00:23:47 or whatever). Clock 1's button changes to say "Start" because it is paused.

e.  Clock 5 begins running, and its button changes to say "Stop."

f.  I decide to use clock 3.  I click "Start" on Clock 3.

g.  Clock 5 stops/pauses (and holds the time that it reached, say 00:34:51 or whatever). Clock 5's button changes to say "Start" because it is paused.

h.  Clock 3 begins running, and its button changes to say "Stop."

i.   I decide to go back to Clock 1. I click "Start."  It should resume at the time that it left off before (say 00:23:48 - see paragraph d, above).
Yup, that's what this code does, let me add some more clocks...

Seems to work just fine...
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title> Javascript Stopclock </title>
<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
<script type='text/javascript'>
  //------------------------------------------------------------------
  // Name: D2()
  // Role: Prepend a '0' (if necessary) to make a two digit number
  //------------------------------------------------------------------
  function D2( val ) {
    return ( val < 10 ) ? '0' + val : val;
  }
 
  //------------------------------------------------------------------
  // Name: field()
  // Role: Look for document element having specified ID attribute
  //------------------------------------------------------------------
  function field( id ) {
    var obj = document.getElementById( id );
    if ( !obj ) {
      alert( 'Specified element not found: id = "' + id + '"' );
    }
    return obj;
  }
 
  //------------------------------------------------------------------
  // Name: Hours()
  // Role: Extract the hours portion of a HH:MM:SS value
  //------------------------------------------------------------------
  function Hours( val ) {
    var d = val.split( ':' );
    return parseInt( d[ 0 ], 10 );
  }
 
  //------------------------------------------------------------------
  // Name: Minutes()
  // Role: Extract the minutes portion of a HH:MM:SS value
  //------------------------------------------------------------------
  function Minutes( val ) {
    var d = val.split( ':' );
    return parseInt( d[ 1 ], 10 );
  }
 
  //------------------------------------------------------------------
  // Name: Seconds()
  // Role: Extract the minutes portion of a HH:MM:SS value
  //------------------------------------------------------------------
  function Seconds( val ) {
    var d = val.split( ':' );
    return parseInt( d[ 2 ], 10 );
  }
 
  //------------------------------------------------------------------
  // Name: reset_clock()
  // Role: Reset timer field value
  //------------------------------------------------------------------
  function reset_clock( id ) {
    var obj = field( id );
    if ( obj ) {
      obj.value = '00:00:00';
    }
  }
 
  //------------------------------------------------------------------
  // Name: HMS2s()
  // Role: Convert HH:MM:SS time to seconds
  //------------------------------------------------------------------
  function HMS2s( val ) {
    return ( ( ( Hours( val ) * 60 ) + Minutes( val ) ) * 60 ) + Seconds( val );
  }
 
  var timerID   = null;
  var startTime = null;                // When did/does timer begin?
  var eButton   = null;                // Start/Stop button element
  
  //------------------------------------------------------------------
  // Name: start_stop()
  // Role: Used to start/stop the specified timer
  //------------------------------------------------------------------
  function start_stop( obj, id ) {
    var val = field( id ).value;       // Current HH:MM:SS value
    if ( obj && obj.type == 'button' ) {
      if ( obj.value == 'start' ) {
        //------------------------------------------------------------
        // It is possible for multiple buttons to exist on the page,
        // however, we only want 1 timer to be actively counting.
        //------------------------------------------------------------
        if ( timerID ) {
          clearTimeout( timerID );
          timerID = null;
          eButton.value = 'start';
        }
 
        eButton = obj;
        obj.value = 'stop';            // change button from start -> stop
        //------------------------------------------------------------
        // Adjust timer based upon current HH:MM:SS value
        //------------------------------------------------------------
        var began = new Date();        // Current date/time
        began.setHours( began.getHours() - Hours( val ) );
        began.setMinutes( began.getMinutes() - Minutes( val ) );
        began.setSeconds( began.getSeconds() - Seconds( val ) );
        
        startTime = began.getTime();        
        showTimer( id );
        
      } else {
        obj.value = 'start';           // Change button from stop -> start
        clearTimeout( timerID );
        timerID = null;
        eButton = null;
      }
    } else {
      alert( 'specified element missing, or of wrong type' );
    }
  }
 
  //------------------------------------------------------------------
  // Name: showTimer()
  // Role: Used to update the specified timer field
  //------------------------------------------------------------------
  function showTimer( id ) {
    var obj = field( id );
    if ( obj ) {
      var current = new Date();        // current Date/Time object
      var curTime = current.getTime(); // # milliseconds since 1970
      var dif = curTime - startTime;   // Elapsed milliseconds
      var sec = dif / 1000;            // difference in seconds ...
      var hrs = parseInt( sec / 3600 );
      sec %= 3600;
      var min = parseInt( sec / 60 );
      sec = parseInt( sec % 60 );
      obj.value = D2( hrs ) + ':' + D2( min ) + ':' + D2( sec );
      timerID = setTimeout( 'showTimer("' + id + '")', 500 );
    }
  }
</script>
</head>
 
<body>
<form name='clock' action=''>
  <table border='1'>
    <tr>
      <td>Clock #0</td>
      <td>
        <input type='text'   id='clock0' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock0");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock0");'>
      </td>
    </tr>
    <tr>
      <td>Clock #1</td>
      <td>
        <input type='text'   id='clock1' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock1");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock1");'>
      </td>
    </tr>
    <tr>
      <td>Clock #2</td>
      <td>
        <input type='text'   id='clock2' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock2");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock2");'>
      </td>
    </tr>
    <tr>
      <td>Clock #3</td>
      <td>
        <input type='text'   id='clock3' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock3");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock3");'>
      </td>
    </tr>
    <tr>
      <td>Clock #4</td>
      <td>
        <input type='text'   id='clock4' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock4");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock4");'>
      </td>
    </tr>
    <tr>
      <td>Clock #5</td>
      <td>
        <input type='text'   id='clock5' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock5");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock5");'>
      </td>
    </tr>
    <tr>
      <td>Clock #6</td>
      <td>
        <input type='text'   id='clock6' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock6");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock6");'>
      </td>
    </tr>
    <tr>
      <td>Clock #7</td>
      <td>
        <input type='text'   id='clock7' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock7");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock7");'>
      </td>
    </tr>
    <tr>
      <td>Clock #8</td>
      <td>
        <input type='text'   id='clock8' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock8");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock8");'>
      </td>
    </tr>
    <tr>
      <td>Clock #9</td>
      <td>
        <input type='text'   id='clock9' value='00:00:00' onFocus='this.blur()' size='10' readonly>
      </td>
      <td>
        <input type='button' value='start' onClick='start_stop(this,"clock9");'>
      </td>
      <td>
        <input type='button' value='reset' onClick='reset_clock("clock9");'>
      </td>
    </tr>
  </table>
</form>
<div id='debug'></div>
</body>
</html>

Open in new window

I don't know if you had noticed that in showTimer(), that I set the the setTimeout delay to be 500 milliseconds (instead of 0).  This allows other things on the systems to have a chance at getting a little processor time.  There is no reason for code to be checking so often for a change in "timer ticks".  Since the resolution is seconds, a delay of 1/2 second (i.e., 500 milliseconds) should be adequate...
Yes, that's excellent.
    My detailed example was posted before I saw your solution in ID:20765161.  I think you captured exactly what I was describing.  Thank you!
     Now I'm testing with 5 clocks on the page, and I'm going to let it run for over an hour so I can see if any display problems come up after it reaches an hour.  That's the only time I saw problems before. (Before it got to an hour, it all worked fine.)  So give me some time to test it for over an hour, and I'll get back to you.  Thanks again.
btw, the code (as written) handles times up to 99:99:59, after that, you are going to see 3 digit hours, which "might " mess things up.  Let me take a look at the code to see how big a problem that might be...
It may be alright.  I guess that it depends upon how wide your output fields are to hold the HH:MM:SS values (and the font being used to display these values).
re: 20765241

Not at all.  Let me know.  I don't know for how much longer I'll be up tonight.  If I don't see an update before going to bed, I'll check it first thing in the morning.

Good luck
Hi people.

Hi was working on a different angle, but I have such a bad flu I cannot think straight...
Perhaps someone will think it is an idea to continue

Basically the idea was this:

function startGlobalTimer() {
  then = new Date().getTime();
  globalSecs=0;
}
function runTimer() {
  now = new Date().getTime();
  if (now-then >= 1000) {
    globalSecs++;
    then=now;
    updateTimers();
  }
//  document.getElementById('global').innerHTML=globalSecs;
}
tId = setInterval('runTimer()',100);// change if too heavy

then when you start a timer, you just copy the current value of global timer to timer.seconds and in updateTimers you show the values of globalTimer-timer.seconds for each timer unless timer.pause is true.
As you can see the seconds count on in pause mode, but I cannot see where I get the 0 when clicking restart

<html>
<head>
<title>Multiple Javascript Stopwatches</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script>
var globalSecs=0;
var now,then;
var tId="";
function startGlobalTimer() {
  then = new Date().getTime();
  globalSecs=0;
}
function runTimer() {
  now = new Date().getTime();
  if (now-then >= 1000) {
    globalSecs++;
    then=now;
  }
  document.getElementById('global').innerHTML=globalSecs;
}
tId = setInterval('runTimer()',100);// change if too heavy 
 
function Timer(name,box){
 
 function displaytimer(){
  var secs = globalSecs-this.seconds;
  if (this.pause) {
    this.seconds+=secs;
    return;
  }
  mins = parseInt(secs/60)
  secs -=(mins*60);
  document.getElementById(this.box+'Mins').value=(mins<10)?"0"+mins:mins;
  document.getElementById(this.box+'Secs').value=(secs<10)?"0"+secs:secs;
 }
 
 function reset(){
  clearInterval(this.interval)
  this.pause=false;
  document.getElementById(this.box+'Mins').value="00"
  document.getElementById(this.box+'Secs').value="00"
 }
 
 function stop(){
  this.pause=true;
 }
 
 function restart(){
   this.pause=false;
 }
 function startTimer(){
   this.pause=false;
   this.interval=setInterval(this.name+'.displaytimer()',1000)
 }
 
 this.start=startTimer
 this.displaytimer=displaytimer
 this.stop=stop
 this.reset=reset
 this.restart=restart
 this.name=name
 this.box=box
}
function toggle(theBut) {
  if (theBut.value=='start') { 
    eval(theBut.id+".seconds=globalSecs");
    eval(theBut.id+".start()"); 
    theBut.value='pause'
  } 
  else if (theBut.value=='pause') {
    eval(theBut.id+".stop()"); 
    theBut.value='restart'
  }
  else if (theBut.value=='restart') {
    eval(theBut.id+".restart()"); 
    theBut.value='start'
  }
}
 
startGlobalTimer(); 
timer1=new Timer('timer1','timer1box')
//timer2=new Timer('timer2','timer2box')
//timer3=new Timer('timer3','timer3box')
</script>
 
<body>
<span id="global"></span>
 <form>
 <input id="timer1boxMins" value="0" size="3" style="font-size:16;border:2px solid red;text-align:right">:
 <input id="timer1boxSecs" value="0" size="3" style="font-size:16;border:2px solid red;text-align:right"><br>
 <input id="timer1" type="button" value="start" 
 onclick="toggle(this)">
 <input type="button" value="reset" onclick="timer1.reset();"><br><br> 
 
 
</body>
</html>

Open in new window

mplungjan,
   I think your comment probably was intended for my other question at http:Q_23115854.html (which was asking how to extend a script that you had helped me with earlier, like the one you posted here), if you want to re-post it there. Thanks.
HonorGod,
    I've tested your http:#20765203 quite thoroughly, stopping and pausing the different clocks over a 5-hour period. Even the one with the most accumulated time (currently 05:06:54 ) seems to restart very accurately from pause. I have not noticed any inaccuracies.  Seems like it's always right.  That's great!

    I have noticed, though, my computer has been running slowly since this page of 5 stopwatches has been open. (Things like opening a new browser window, switching between windows, or opening a new program, are taking about 4 times longer, and the hard-drive activity light has been lit most of the time, even when idle).  I realize it could be purely a coincidence; maybe some other program like a disk defragmenter or virus checker or something was running.  I'm going to restart my computer and see how it works while running this script after restart.
      Does this kind of script, with multiple clocks, involve a processor-intensive or memory-intensive task, or might the slowness be a coincidence?
No I meant it here since I was concerned that the timers did not work and the browser was impeeded so I wanted to give the experts here an idea for a less intensive and more precise timer
mplungjan,
   OK.  I will take a look at your script. Thanks.
HonorGod,
    One related request:  where in your script would I plug in some statements like  
    . . . . className='yellow'  
or    . . . . className='white'  
so the active running clock will have a yellow display, and all the stopped/paused ones will have a white display, using this CSS in my page head:

<style>
.white {font:10pt arial; color:#505050; background:white}
.yellow {font:10pt arial; color:#000000; background:yellow;}
</style>
mplungjan,
   I appreciate your contribution in ID:20766448.     When I tested, I got an error for the Reset button ("object doesn't support this property or method"). Also I got a timing problem when resuming after a pause (as you mentioned, it went back to zero or started at the wrong time). But I appreciate your posting it here for the Experts to consider, as you mentioned. Maybe they can use something in it, as you suggested. Thank you.
ASKER CERTIFIED SOLUTION
Avatar of HonorGod
HonorGod
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
As far as system slowdown is concerned, the page as written shouldn't have that issue (see my comment (20765228) above.

- Open a Task Manager
- Click on the Processes tab
- Move the slider to the top of the display
- Click on the "CPU" column heading so that the entries will be sorted (descending) based upon CPU utilization

  This should help you see what process is consuming your CPU.
  If it is the browser, then we may have an issue.
I just tried that, and I have 87 processes active.
My browser never showed up near the top of the list during my 2 minute test...
HonorGod,
   The white/yellow css works great. Thanks!
I tested the processes and ram and I agree the script seems to have only a very minimal impact on cpu usage or memory, so last night's slowdown might have been a coincidence, probably some disk utility running in the background.
    I think your solution is read to accept as the answer. It's excellent.
    (By the way, please feel free to post your answer as an answer to http:Q_23115854.html , since b0lsc0tt left a note saying that would be appropriate since it's a different question based on a different script, even though your answer here would resolve that question, too.)

    However, there is one related issue I need help with:  I need another textbox that will display the time of day when each clock first started to run (and that display must not be affected by any subsequent starts or stops of that clock.)  
    It's easy enough to send the current time to the value of a textbox upon clicking the "Start" button of any clock, but I don't know how to prevent it from changing every time I click the button later on.  I'm opening a new question ( http:Q_23119442.html ) on that issue. Please take a look: http:Q_23119442.html
Thanks for the grade/points, and interesting question.

I'll take a look at the new question.

Good luck, and have a great day