Jump to content

Button to terminate script


SerenityNetworks

Recommended Posts

I'm stuck on terminating my script, which right now just counts seconds. I can click the 'start' button, the script runs, and the seconds elapsed are displayed in the form. But I need to be able to stop the script using the 'stop' button and I can't figure out how to do so. (Note: When the script stops, I wish for the last elapsed value to remain displayed in the form.)

 

What is the code I need to have the script stop as desired?

 

Thanks in advance,

Andrew

	<form id="myTimer" action="#">		<fieldset>			<label>				<span>Seconds:</span>				<input type="text" name="secCounter" />			</label>		</fieldset>		<fieldset>			<button type="submit">Start</button>			<button type="reset">Stop</button>		</fieldset>	</form>	<script type="text/javascript">			// timer		function timer(form, stop)		{			if(stop) {exit();}			else {				var start = new Date().getTime(),				    time = 0,				    elapsed = '0.0';								function instance()				{				    time += 100;								    elapsed = Math.floor(time / 100) / 10;				    if(Math.round(elapsed) == elapsed) { elapsed += '.0'; }									form.secCounter.value = elapsed;									    var diff = (new Date().getTime() - start) - time;				    window.setTimeout(instance, (100 - diff));				}				window.setTimeout(instance, 100);			}					function exit() {			alert("This is not working.  The script still runs.");			return;}		};					// start timer		document.getElementById('myTimer').onsubmit = function()		{			timer(this);			return false;		};				// stop timer		document.getElementById('myTimer').onreset = function()		{			timer(this, stop);			return false;		};	</script>
Link to comment
Share on other sites

You should call clearTimeout() when you want to stop an existing timer.

 

Here's how it works:

var timeout = setTimeout(callback, time);// When you want to stop the timer:clearTimeout(timeout);

With your current code, you'll have to watch carefully for the scope of the variables you're using. If you use var timeout right inside the function it won't be accessible to clearTimeout() outside the function.

Link to comment
Share on other sites

Okay, sorry, I've made several attempts to understand and apply, but I'm not getting how to use what you've shown. (I'm just a noob hobbyist.) Would you please provide me with a bit more guidance?

 

Thanks,

Andrew

Link to comment
Share on other sites

When I look at your code I am confused by the stop variable that is passed below. Where is stop declared and set equal to true?

// stop timer		document.getElementById('myTimer').onreset = function()		{			timer(this, stop);			return false;		};
Link to comment
Share on other sites

  1. Indent your code properly
  2. Don't use <form> tags if you're not submitting anything to the server
  3. Keep track of all your timers
  4. You have to use proper DOM methods to access elements like getElementById() and getElementsByTagName(). formName.elementName is non-standard and may not work properly in all browsers.
  5. Check the Javascript reference for any functions that may help you. Number.toFixed() simplifies the code a lot.
  6. Try to keep your code as short and simple as possible.

Read this and try to understand how it works. It should be easy because I've cut out a whole lot of stuff from it and made it really short:

<fieldset>  <label>    <span>Seconds:</span>    <input type="text" id="counter">  </label></fieldset><fieldset>  <button id="start">Start</button>  <button id="stop">Stop</button></fieldset><script type="text/javascript">// HTML elements we're going to usevar startButton = document.getElementById("start");var stopButton = document.getElementById("stop");var display = document.getElementById("counter");var timeout; // Global variable for clearTimeout();var startTime; // Global variable to remember when the timer started// Event handlersdocument.getElementById('start').onclick = start;document.getElementById('stop').onclick = stop;// Start the timerfunction start() {  startTime = (new Date()).getTime();  instance();} // Stop the timer function stop() {  if(timeout) {    clearTimeout(timeout);    timeout = null;  }}// Call this on each intervalfunction instance() {  elapsed = ((new Date()).getTime() - startTime) / 1000;  display.value = elapsed.toFixed(1); // Remember that "display" was defined at the beginning of the script  timeout = window.setTimeout(instance, 50);}</script>
Link to comment
Share on other sites

Thank you very much. I will not have the opportunity to examine the scripting until late tomorrow, but for sure I will study it. I just didn't want to wait until tomorrow to reply.

 

Thank you again. I learn a lot by studying the differences between code that's simply (or partially) working and code that's been optimized.

 

Andrew

Link to comment
Share on other sites

I've been playing with this, and it certainly does seem to be tricky to use a closure in this manner. Here is some code...

<div>	<fieldset>		<label>			<span>Seconds:</span>			<input type="text" id="secCounter" />		</label>	</fieldset>	<fieldset>		<button id="startbtn">Start</button>		<button id="stopbtn">Stop</button>	</fieldset></div><script type="text/javascript">	'strict';		function starttimer()		{			var start,			   time,			   elapsed,			   itimer;			function restarttimer(){				if (itimer==undefined || itimer==null){					start = new Date().getTime();					time = 0;					elapsed = '0.0';					itimer = setTimeout(instance, 100);				}			}			function stoptimer(){								clearTimeout(itimer);				itimer = null;				console.log('stop');			}					function instance()			{				if (itimer != null){			   		time += 100;							 		elapsed = Math.floor(time / 100) / 10;					if(Math.round(elapsed) == elapsed) { 						elapsed += '.0'; 					}									document.getElementById('secCounter').value = elapsed;					var diff = (new Date().getTime() - start) - time;					itimer = setTimeout(instance, (100 - diff));				}                        	console.log('time='+time+' elapsed='+elapsed+' start='+start+' diff='+diff); 			}						document.getElementById('stopbtn').onclick = function() { stoptimer(); }			document.getElementById('startbtn').onclick = function() { restarttimer(); }			restarttimer();		} // end of starttimer							document.getElementById('startbtn').onclick = function(){ starttimer(); }				</script>
Link to comment
Share on other sites

I wouldn't use a closure for that. If I wasn't trying to keep the code similar to his original idea I would have created an object Timer and given it properties and methods.

Link to comment
Share on other sites

I haven't yet had a chance to look at the scripts you have provided. I've got two projects I'm working on that use timers. What I'm trying to do with this script is avoid the slow drift from real time that we get if the JavaScript timer is used exclusively. So I'm trying to keep the time 'real' by referencing the host's system clock.

 

For this particular project I'm making a metronome that I can use to keep a steady pace when running. I'll have a field where I can enter the pace I want to run and then the script will play a sound at that pace (ex: 180 beats/sounds per minute). I'll have a couple other features, such as displaying the elapsed time, but simply playing a sound at 'n' beats per minute is the main function. (Yes, the accuracy of the JavaScript timer would be fine for this metronome purpose, but I'm trying to learn how to keep sync with real time for use in my other project where I need a timer that syncs with video playback.)

 

Does knowing any of this help with how that solution would be coded?

 

Thanks again,

Andrew

Link to comment
Share on other sites

Creating a metronome in Javascript might be difficult. I couldn't find the audio play() function but it exists. (Foxy: I don't know why the overly paranoid closure approach seems to be so heavily promoted.)

Link to comment
Share on other sites

You're going to have an error of anything up to 100 milliseconds if you use Javascript's traditional timers setInterval() and setTimeout().

If you use requestAnimationFrame() you can reduce the error to under 16 milliseconds.

 

The script from my post will have these tiny errors in the exact moment a beat is played, but it will be generally synchronized because it's using the Date() object. I chose an interval of 50 milliseconds because your timer only needed a precision of 100 milliseconds.

 

From my experience, these are not enough for music playback. Recently I have been working on a music application in Javascript and during my search for perfect timing I came across this great article:

http://www.html5rocks.com/en/tutorials/audio/scheduling/

Link to comment
Share on other sites

For the metronome project, I'm just wanting to play a short (< 1 second) sound. For temporary (experimentation) use I've just been using what I've put in the 1st code block below. It works on a Windows machine, but I'm sure I'll have to change it up to reference a regular sound file for use on my phone. Perhaps something like I have in the second code block.

function beep() { var snd = new Audio("data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=");   snd.play();}
<audio id="sound1" src="images/this.wav"></audio><audio id="sound2" src="images/that.wav"></audio><button onclick="playSound1()">Sound 1</button><br /><button onclick="playSound2()">Sound 2</button><br /><script type="text/javascript">var audio1 = document.getElementById('sound1');var audio2 = document.getElementById('sound2');function playSound1(){    audio1.play();	}function playSound2(){    audio2.play();    }</script>
Link to comment
Share on other sites

Just for the sake of avoiding giving the garbage collector too much work, I would move the var snd = new Audio() line outside the function so that it can be reused over and over.

 

I think mobile devices should be able to accept data URLs, but I haven't tested before.

Link to comment
Share on other sites

Thanks for the tip (on the var snd = new Audio() line). I'll do so.

 

(Not sure that I'm going to get to look at all the code provided now until maybe tomorrow night. It might not be until late this week. My granddaughter is in town and time is precious. I don't want anyone to think I'm blowing off the advice if I don't get back for a while.)

Link to comment
Share on other sites

I'm stumped on triggering the sound. I set a global variable ("interval") to remember the previous time value. With the next iteration of the instance function I subtract the current time from the previously calculated time and if it equals 1 then I play the beep. But it's not working as I need.

 

If I set the calculation to be performed on whole numbers ("interval = elapsed.toFixed(0)") then it works, but due to rounding the beeps are noticeably irregular. But if I set the calculation to be performed at toFixed(1) or toFixed(2) then I never get a beep. I'd think with the instance function being recalculated every 50 milliseconds that I should be able to play a beep accurate to 1/100 second without any problems.

 

What am I missing &/or is there a better way to call the beep?

 

Thanks again,

Andrew

// Call this on each interval	function instance() {	  elapsed = ((new Date()).getTime() - startTime) / 1000;	  if (elapsed.toFixed(1) - interval == 1) {	  	beep();	  }	  display.value = elapsed.toFixed(1); 	// Remember that "display" was defined at the beginning of the script	  interval = elapsed.toFixed(1);		//Global variable	  timeout = window.setTimeout(instance, 50);	}
Link to comment
Share on other sites

Have you checked the error console?

 

toFixed() turns the number into a string, you should only do that if you want to display the value in a readable format.

 

It would be best if you operate in milliseconds instead of dividing by 1000. You only divide by 1000 to show a more understandable number to the user, but it's far more efficient to operate in the environment Javascript uses.

// Global variablesvar timeSinceLastBeep;var timeStarted;// Function to be called on each framefunction instance() {  // What time is it?  var now = (new Date()).getTime();  // Make sure the timing variables have a value  if(!timeStarted) timeStarted = now;  if(!timeSinceLastBeep) timeSinceLastBeep = now;  // Determine how much time has passed since the last beep  var elapsed = now - timeSinceLastBeep;  // If the amount of time that has passed is one second or longer then play a beep and remember when the beep was played.  if(elapsed >= 1000) {    beep();    // Set "timeSinceLastBeep" to the time when the beep should have played to prevent synchronization errors    then = now - (timeSinceLastBeep % 1000);  }  // Show the amount of time that has passed  var timeSinceStart = (now - timeStarted) / 1000;  display.value = timeSinceStart.toFixed(1);  // Call the next frame  timeout = window.setTimeout(instance, 50);}
Link to comment
Share on other sites

  • 10 months later...

 

  • Indent your code properly
  • Don't use <form> tags if you're not submitting anything to the server
  • Keep track of all your timers
  • You have to use proper DOM methods to access elements like getElementById() and getElementsByTagName(). formName.elementName is non-standard and may not work properly in all browsers.
  • Check the Javascript reference for any functions that may help you. Number.toFixed() simplifies the code a lot.
  • Try to keep your code as short and simple as possible.

Read this and try to understand how it works. It should be easy because I've cut out a whole lot of stuff from it and made it really short:

<fieldset>  <label>    <span>Seconds:</span>    <input type="text" id="counter">  </label></fieldset><fieldset>  <button id="start">Start</button>  <button id="stop">Stop</button></fieldset><script type="text/javascript">// HTML elements we're going to usevar startButton = document.getElementById("start");var stopButton = document.getElementById("stop");var display = document.getElementById("counter");var timeout; // Global variable for clearTimeout();var startTime; // Global variable to remember when the timer started// Event handlersdocument.getElementById('start').onclick = start;document.getElementById('stop').onclick = stop;// Start the timerfunction start() {  startTime = (new Date()).getTime();  instance();} // Stop the timer function stop() {  if(timeout) {    clearTimeout(timeout);    timeout = null;  }}// Call this on each intervalfunction instance() {  elapsed = ((new Date()).getTime() - startTime) / 1000;  display.value = elapsed.toFixed(1); // Remember that "display" was defined at the beginning of the script  timeout = window.setTimeout(instance, 50);}</script>

Actually , I am searching for Posts that contain 'requestAnimationFrame' .

 

Just curious , why do people show code all on one line ?

To me it is downright unpleasant , to have to copy/paste ,

then edit code into one statement per line .

Or is there a way to unravel code into multilines ,

that I don't know about ?

Thanks

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...