Multiple JS Stopwatches on One Page: Accurate Pause of Timers; and Automatic Stop of Others When Any One Is Started

This JS object in the code snippet makes it easy to have multiple Javascript stopwatches on a page.
     But there is a timing problem.  It loses several seconds when restarting after a pause.
     For example, when I paused this one at 36 seconds, it restarted at only 21 seconds.
    When I stopped it at 2:02 , it restarted at 1:43.
(By the way, there is another JS stopwatch script that seems to have accurate pause/resume display, at http:Q_23109318.html ID:20756902, but it is not designed as an object to easily make multiple stopwatches on one page. But there might be some technique in it useful for fixing the timing problem in the script here.)

    Also, it is possible to make all other clocks stop (and their buttons change to say "Start") when any one clock is started?  For example, if Clock 1 is running, and then I click "Start" for Clock 3, then Clock 1 should pause and its button should turn to "Start". (And although there should never be multiple clocks running, it probably should check to make sure *all* other clocks are stopped and their buttons say "Start", when any one clock's Start button is clicked.)
<html>
<head>
<title>Multiple Javascript Stopwatches</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script>
function Timer(name,box){
 function startTimer(){
  this.d=new Date
  this.interval=setInterval(this.name+'.displaytimer()',1000)
 }
 
 function displaytimer(){
  now=new Date()
  secs=Math.round((now.getTime()-this.d.getTime())/1000)+this.seconds
  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.seconds=0
  document.getElementById(this.box).value=0
 }
 
 function stop(){
  this.seconds=Math.round((now.getTime()-this.d.getTime())/1000)
  clearInterval(this.interval)
  this.interval='null'
 }
 
 function restart(){
  if (this.interval=='null'){
   this.d=new Date
   this.interval=setInterval(this.name+'.displaytimer()',1000)
 }
}
 
 this.start=startTimer
 this.displaytimer=displaytimer
 this.stop=stop
 this.reset=reset
 this.restart=restart
 this.seconds=0
 this.name=name
 this.box=box
}
 
timer1=new Timer('timer1','timer1box')
//timer2=new Timer('timer2','timer2box')
//timer3=new Timer('timer3','timer3box')
</script>
 
<body>
 
 <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 type="button" value="start" 
 onclick="if (this.value=='start') { timer1.start(); this.value='stop'} else {timer1.stop(); this.value='start'}">
 <input type="button" value="reset" onclick="timer1.reset();"><br><br> 
 
 
 <input id="timer2boxMins" value="0" size="3" style="font-size:16;border:2px solid red;text-align:right">:
 <input id="timer2boxSecs" value="0" size="3" style="font-size:16;border:2px solid red;text-align:right"><br>
 <input type="button" value="start" 
 onclick="if (this.value=='start') { timer2.start(); this.value='stop'} else {timer2.stop(); this.value='start'}">
 <input type="button" value="reset" onclick="timer2.reset();"><br><br>  
 
 
 <input id="timer3boxMins" value="0" size="3" style="font-size:16;border:2px solid red;text-align:right">:
 <input id="timer3boxSecs" value="0" size="3" style="font-size:16;border:2px solid red;text-align:right"><br>
 <input type="button" value="start" 
 onclick="if (this.value=='start') { timer3.start(); this.value='stop'} else {timer3.stop(); this.value='start'}">
 <input type="button" value="reset" onclick="timer3.reset();"><br><br> 
 
</body>
</html>

Open in new window

FrankTechAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

HonorGodSoftware EngineerCommented:
0
HonorGodSoftware EngineerCommented:
By "apparent duplicate" I mean that the answer that I provided in that other question appears to resolve/answer the things specifically requested here.

Does that count as a duplicate, or not?
0
FrankTechAuthor Commented:
Yes, this seems to be a duplicate, for all practical purposes, although the underlying script was different. But the script underlying http:Q_23117375.html is better, and so far your solution looks good (I'm still testing.)
    So this question could be treated as a duplicate, so I'll probably ask CS to delete it.
0
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

FrankTechAuthor Commented:
b0lsc0tt,
    I did not intend to post a duplicate. It actually is a different question (and it was posted about 10 hours earlier than the one HonorGod answered).  Although similar to the 2nd, it dealt with modifying a different JS script.
    Although the underlying scripts were different, the solution that HonorGod provided in http:Q_23117375.html has the practical effect of solving this one also - because they achieve the same overall goal.
      So I don't mind if HonorGod posts the other solution here because the questions are different but the answer could work in both. Thanks.
0
HonorGodSoftware EngineerCommented:
ok, you asked for it... :-)
<!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'>
<style type='text/css'>
.white {font:10pt arial; color:#505050; background:white}
.yellow {font:10pt arial; color:#000000; background:yellow;}
</style>
 
<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
  var eTimer    = null;                // Reference to Timer 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';
          eTimer.className = 'white';
        }
 
        eButton = obj;
        obj.value = 'stop';            // change button from start -> stop
        eTimer  = field( id );
        eTimer.className = 'yellow';
        //------------------------------------------------------------
        // 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;
        eTimer.className = 'white';
        eTimer  = 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'   class='white' 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'   class='white' 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'   class='white' 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'   class='white' 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'   class='white' 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'   class='white' 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'   class='white' 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'   class='white' 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'   class='white' 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'   class='white' 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

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
FrankTechAuthor Commented:
Thanks!
0
FrankTechAuthor Commented:
b0lsc0tt,
  I'm trying to accept HonorGod's answer, but the sysem says I can't accept it. Please help. Thanks.
0
FrankTechAuthor Commented:
b0lsc0tt,
  Sorry; disregard my last comment. I guess it has already been accepted. Thanks.
0
HonorGodSoftware EngineerCommented:
Thanks Frank.  I appreciate the grade / points.

I hope that you find this information useful.

Have a great day.
0
Ziggie013Commented:
This freakin rocks.  Thanks HonorGod!  I wish I could give you points for this solution too!!!
0
HonorGodSoftware EngineerCommented:
Ziggie013...   Thanks
0
b0lsc0ttIT ManagerCommented:
>> I wish I could give you points for this solution too!!! <<
Did you click the Yes button/link in the "Was this helpful" part of the comment HonorGod posted?  It won't give points but does have an effect and will help recognize the expert's contribution.  Just one click please (*L*) but it is a great way to reward him.
bol
0
Ziggie013Commented:
I didn't know about that button, thank you.

Clicked and Rated.  Excellant!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
JavaScript

From novice to tech pro — start learning today.