Here's a simple countdown timer that counts from 9 down to 0.
The countdown works fine. But what if I want to pause it mid-flow and then restart from where it was paused?
I have tried (see code below) to interrupt the countdown, save the number it was at, and then restart the function from the new number. But the countdown goes haywire, and I can't see why. Any ideas?
PS. I could cut and paste a timer from elsewhere, but I'm doing this for the learning experience. I'm sure there are better ways to code a countdown timer in JS, but it's bugging me that I can't make THIS way work and think I must be missing something obvious.
Many thanks
var currentTimeInt = 10;
var minn = [];
var stop = 0;
// stop
function stopCounter() {
currentTime = document.getElementById('mins').textContent; // grabs the number of minutes at moment of pause.
stop = 1;
}
// restart
function restart() {
stop = 0;
currentTimeInt = parseInt(currentTime, 10); // converts that number into an integer we can use
document.getElementById("mins").innerHTML=currentTimeInt;
newMinutes(); // restarts the newMinutes function with the start time currentTimeInt set to the time the counter stopped at
}
function newMinutes() {
document.getElementById('mins').innerHTML= currentTimeInt; // displays the counter
for (aa = currentTimeInt-1; aa >= 0; aa--) {
minn.push(aa); // builds an array of numbers in descending order
document.getElementById('mins').innerHTML= minn[aa];
for (let bb=1; bb<=currentTimeInt; bb++) {
if (bb<currentTimeInt) {
setTimeout( function timer(){
if (stop == 0) { // checks if "stop!" has been clicked and returns false to stop the function if that is the case
document.getElementById('mins').innerHTML= minn[bb];
console.log(minn[bb]);
}
else {return false;}
}, bb*1000 );
}
}
}
console.log(currentTimeInt + " the end");
}
<span>Minutes: </span><span id= "mins"></span>
<button onclick="newMinutes()">Go!</button>
<button onclick="stopCounter()">Stop!</button>
<button onclick="restart()">Reset!</button>
You may try this as an example:
var timerId;
var counter;
function start() {
console.log('start');
if (!counter) {
reset();
} else {
loop();
}
}
function pause() {
console.log('pause');
if (timerId) {
clearInterval(timerId);
timerId = null;
}
}
function reset() {
console.log('reset');
pause();
counter = 10;
loop();
}
function loop() {
timerId = setInterval(function() {
if (0 >= counter) {
pause();
return;
}
console.log('counter', counter);
counter--;
}, 500);
}
<button onclick='start();'>Start</button>
<button onclick='pause();'>Pause</button>
<button onclick='reset();'>Reset</button>
Here is my little Countdown with START, PAUSE, RESUME, STOP & RESET features:
var jqcd_start_id = 'input#jqcd_start';
var jqcd_time_id = 'input#jqcd_time';
var jqcd_count_id = 'span#jqcd_count';
var jqcd_end_message = 'Time is up!';
var jqcd_countdown = '';
var jqcd_status = 'stopped';
var jqcd_current = '';
function jqcd(action){
if (action == 'start') {
if (jqcd_status == 'stopped') {
jqcd_updtv(jqcd_start_id, 'Pause');
jqcd_status = 'running';
jqcd_current = jqcd_countdown;
jqcd_updtt(jqcd_count_id, jqcd_countdown);
}
else if (jqcd_status == 'running') {
jqcd_updtv(jqcd_start_id, 'Resume');
jqcd_status = 'paused';
}
else if (jqcd_status == 'paused') {
jqcd_updtv(jqcd_start_id, 'Pause');
jqcd_status = 'running';
}
}
else if (action == 'stop') {
jqcd_updtv(jqcd_start_id, 'Start');
jqcd_status = 'stopped';
jqcd_updtt(jqcd_count_id, jqcd_end_message);
}
else if (action == 'reset') {
jqcd_updtv(jqcd_start_id, 'Start');
jqcd_status = 'stopped';
jqcd_updtt(jqcd_count_id, jqcd_countdown);
}
var a = jqcd_current.split(":");
var m = a[0];
var s = (a[1] - 1);
if (s < 0) {
if (parseInt(m) == 0) {
jqcd_updtv(jqcd_start_id, 'Start');
jqcd_status = 'stopped';
jqcd_updtt(jqcd_count_id, jqcd_end_message);
}
else {
m = m - 1;
s = 59;
}
}
if(s >= 0){
setTimeout(function(){
if (jqcd_status == 'running') {
m = (parseInt(m) < 10)? "0" + parseInt(m): m;
s = (parseInt(s) < 10)? "0" + parseInt(s): s;
jqcd_updtt(jqcd_count_id, m + ":" + s);
jqcd_current = m + ":" + s;
jqcd('');
}
}, 1000);
}
}
function jqcd_updtv(selector, value) {
if (selector != '') {
$(selector).val(value);
}
}
function jqcd_updtt(selector, value) {
if (selector != '') {
$(selector).text(value);
}
}
$(document).ready(function() {
jqcd_countdown = $(jqcd_time_id).val();
jqcd_updtt(jqcd_count_id, jqcd_countdown);
$(jqcd_time_id).keyup(function() {
jqcd_countdown = $(jqcd_time_id).val();
jqcd_updtt(jqcd_count_id, jqcd_countdown);
jqcd_updtv(jqcd_start_id, 'Start');
jqcd_status = 'stopped';
});
});
span#jqcd_count {
font-size: 20pt;
font-weight: bold;
}
input#jqcd_start,
input#jqcd_stop,
input#jqcd_reset {
font-size: 12pt;
font-weight: bold;
}
input#jqcd_start,
input#jqcd_stop,
input#jqcd_reset {
width: 100px;
}
span#jqcd_count {
font-family: "Lucida Console", Monaco, "Courier New", Courier, monospace !IMPORTANT;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="jqcd_count">00:30</span><br><br>
<input type="button" id="jqcd_start" value="Start" onClick="jqcd('start')" />
<input type="button" id="jqcd_stop" value="Stop" onClick="jqcd('stop')" />
<input type="button" id="jqcd_reset" value="Reset" onClick="jqcd('reset')" /><br><br>
<input type="text" id="jqcd_time" value="00:10" />
<br><br>
It is pretty simple to customize. The first four variables in the JavaScript code can be adapted to work with your specific HTML.
If you want an action to take place every second, add your lines of code inside of the "jqcd_updtt" function.
The CSS is completely optional, of course.
The Countdown start time is set dynamically by altering the value in the "jqcd_time" field. If, however, you want to set a static value for the Countdown starting point, you can alter the variables inside the "$(document).ready(function() {" function at the end of the JavaScript code.
PS.
This Countdown has no maximum limit for minutes or seconds
What about keeping it KISS!
let i = 9,j
function chrono(){
if (i>=0){
now.innerText = i--
}
}
<h1><div id="now">⏰ Ready!</div>
<button onclick="setInterval(function(){ chrono() }, 1000);this.style.display='none'">Start</button>
<button onclick="i=10">Reset</button>
<button onclick="j=i;i=-1">Pause</button>
<button onclick="i=j">Continue</button>
This is the most basic example ready to be expanded, mostly there is no clearInterval.
The KISS principle states that most systems work best if they are kept
simple rather than made complicated; therefore simplicity should be a
key goal in design and unnecessary complexity should be avoided.
https://en.wikipedia.org/wiki/KISS_principle
Therefore, js incrementation and setInterval seems easy but they hide complex things.
An other approach using date.now() that provide an accurate unix timestamp based on the system clock, and the web audio api for beeping.
i = Date.now();j=i+10000;z.innerText="Target #"+j
function d(){
if(now.innerText < j){
now.innerText = Date.now()
k(3,603,80)
}
if(now.innerText > j){
now.innerHTML = "<b>TIME TRAVEL COMPLETE!</b>"
k(8,728,100)
}
}
setInterval(function(){ d() }, 100)
a=new AudioContext()
function k(w,x,y){
v=a.createOscillator()
u=a.createGain()
v.connect(u)
v.frequency.value=x
v.type="square"
u.connect(a.destination)
u.gain.value=w*0.01
v.start(a.currentTime)
v.stop(a.currentTime+y*0.001)
}
EPOCH: <out id="now"></out><h6 id="z">
The first issue here is that currentTime isn't globally defined, so it can't be accessed from within restart. Just put var currentTime; at the start of your file.
But you have another serious breaking issue in that you're using setTimeout in a really awkward way. You're creating multiple timeouts all at once and giving them a delay based on their relation tocurrentTimeInt. This has two problems. For one the use of two for loops isn't very efficient and also seems redundant as your inner for loop is just going to count up to the currentTimeInt anyway.
Secondly, you never clear (and probably won't be able to clear) the timeouts. That means when you restart your timer after pausing if any timeouts hadn't yet been fired, then your program will run those and make the minutes jump back and forth between the old timeouts and the new ones you create after unpausing.
I know in your comment you said you wanted to get this to work because you basically did the whole thing yourself, but it may not be worth continuing down this road. After looking at it some I think fixing your program would require it to be restructured, or else require it to be hacked in a way that makes it pretty inefficient. And if you're someone who's just learning Javascript, it's probably better to just start over and do it the right way anyway.
Below is an example of a better way using setInterval rather than setTimeout, but feel free to just try and figure it out on your own.
(There are ways you can improve the functionality of the code below, but it should be enough to get you the general idea)
var startTimeInt = 10;
var currentTimeInt = startTimeInt;
var interval = undefined;
// start the timer
function startCounter() {
if(!interval){
document.getElementById('mins').innerHTML = currentTimeInt;
interval = setInterval(newNumber, 1000) // set an interval
}
}
// stop
function stopCounter() {
// clear the interval
clearInterval(interval)
interval = undefined;
}
// reset the timer
function resetCounter(){
currentTimeInt = startTimeInt;
document.getElementById('mins').innerHTML = currentTimeInt;
//stopCounter(); startCounter();
}
// change the time and handle end of time event
function newNumber(){
currentTimeInt--; // decrement the current time
document.getElementById('mins').innerHTML = currentTimeInt;
if(currentTimeInt == 0){
console.log("Done");
stopCounter();
}
}
<span>Minutes: </span><span id= "mins"></span>
<button onclick="startCounter()">Go!</button>
<button onclick="stopCounter()">Stop!</button>
<button onclick="resetCounter()">Reset!</button>
Here is a working Snippet..
var paused = false;
var started = false;
var stopped = true;
var currentCount = 0;
var running = false;
interval = 1000;
maxCount = 10;
function start() {
if (stopped){
started = true;
paused= false;
stopped = false;
currentCount = maxCount;
loop(); running = true;
return;
}
paused= false;
}
function pause() {
paused= true;
}
function stop(){
paused = false;
started = false;
stopped = true;
running = false;
currentCount = 0;
}
function update(item){
document.getElementById("status").innerHTML = item;
//console.log(item);
--currentCount;
if(currentCount < 0){stop()}
}
function reset() {
currentCount = maxCount;
document.getElementById("status").innerHTML = currentCount;
}
function loop(){
if (!stopped){
if (!paused){update(currentCount);}
setTimeout(function(){loop()}, interval)
}
}
<button onclick='start();'>Start</button>
<button onclick='pause();'>Pause</button>
<button onclick='reset();'>Reset</button>
<button onclick='stop();'>Stop</button>
<div id="status"></div>
for anyone who want to re-use the code, simply change the value of timer and the render function to fit your project
var timer= 10;
var intervalID
// pause/stop
function stopTimer() {
clearInterval(intervalID);
intervalID= null;
}
// restart
function restart() {
stopTimer();
timer= 10;
render();
// Go(); //Optional
}
// start/resume
function Go() {
if(intervalID){
//if interval already created previously, exit function
return
}
intervalID = setInterval(
() => {
if(timer< 1){
//escape from interval so that counter dont go below 0
return stopTimer();
}
timer--;
render();
}, 1000); //1000 milisecond == 1 second
}
function render(){
// it is ok to run render redundantly as it does not mutate the data
// feel free to change this to fit your needs
console.log(timer);
document.getElementById("mins").innerHTML=timer;
}
render() //render once on load
<span>Minutes: </span><span id= "mins"></span>
<button onclick="Go()">Go!</button>
<button onclick="stopTimer()">Stop!</button>
<button onclick="restart()">Reset!</button>
Related
I am wondering how I might be able to stop a button clicking if the function it is performing is running. Here is my JS code:
let money = 0;
let running = false;
function start(time, val) {
if (running == false) {
running = true;
console.log(running)
let bar = document.getElementById('progressBar1');
bar.value = time;
time++;
let sim = setTimeout("start(" + time + ")", 30);
if (time == 100) {
bar.value = 0;
let id = val;
money++;
document.getElementById("moneyValue").innerHTML = money;
clearTimeout(sim);
running = false;
}
} else if (running == true) {
console.log("Already Growing!");
};
}
<progress id="progressBar1" value="0" max="100" style="width:150px;"></progress>
<button id="restart-button" class="plantBtn" onclick="start(0, this.id)">Plant Seed</button>
What it does is start a progress bar (progress div). I want the button to alert a message saying already going or something like that.
The issue I am having is that it is jumping to the else if statement, and not running anything. The odd thing is that if I add a console.log into the middle of the if statement it works.
I think it is because the bar takes time to fill, it will never reach full if the user clicks it, because it will jump to the else if statement and cancel out the if function. (It only becomes false again after the bar reaches 100%)
Can anyone help? I am open to JS or Jquery (bit rusty on that tho).
Thanks
You need to prevent the button clicking, not the actual start function that you need to call it from by the timer. So it's better to separate these functions:
let money = 0;
let running = false;
// when clicking the button
function onClickButton(time, val) {
if(running) {
console.log("Already Growing!");
} else {
running = true;
start(time, val);
}
}
// timer function
function start(time, val) {
let bar = document.getElementById('progressBar1');
bar.value = time;
time++;
let sim = setTimeout(() => start(time), 30);
if (time == 100) {
bar.value = 0;
let id = val;
money++;
document.getElementById("moneyValue").innerHTML = money;
clearTimeout(sim);
running = false;
}
}
#moneyValue::before {
content: 'Money: ';
}
<div id="moneyValue">0</div>
<progress id="progressBar1" value="0" max="100" style="width:150px;"></progress>
<button id="restart-button" class="plantBtn" onclick="onClickButton(0, this.id)">Plant Seed</button>
Break out the logic into another function that does the updating. Button that starts it on one method and the logic that updates the UI in another.
let money = 0;
let running = false;
function start(time, val) {
if (running == false) {
running = true;
console.log(running)
runIt(time, val);
} else if (running == true) {
console.log("Already Growing!");
};
}
function runIt(time, val) {
let bar = document.getElementById('progressBar1');
bar.value = time;
time++;
let sim = setTimeout(function () {runIt(time); }, 30);
if (time == 100) {
bar.value = 0;
let id = val;
money++;
document.getElementById("moneyValue").innerHTML = money;
running = false;
}
}
<progress id="progressBar1" value="0" max="100" style="width:150px;"></progress>
<button id="restart-button" class="plantBtn" onclick="start(0, this.id)">Plant Seed</button>
<div id="moneyValue"></div>
You could add an additional parameter that tells the function that the call is coming from the loop, and doesn't need to check if it's already running.
let money = 0;
let running = false;
function start(time, val, isFromTimer) {
if (running == false || isFromTimer == true) { // add check
running = true;
console.log(running)
let bar = document.getElementById('progressBar1');
bar.value = time;
time++;
let sim = setTimeout(() => start(time, val, true), 30); // tell function it's from the timer
if (time >= 100) { // use more than or equal to instead
bar.value = 0;
let id = val;
money++;
//document.getElementById("moneyValue").innerHTML = money;
clearTimeout(sim);
running = false;
}
} else if (running == true) {
console.log("Already Growing!");
};
}
<progress id="progressBar1" value="0" max="100" style="width:150px;"></progress>
<button id="restart-button" class="plantBtn" onclick="start(0, this.id)">Plant Seed</button>
Why don't you just use some CSS manipulation in your function once it is clicked?
document.getElementById('restart-button').disabled = true;
Then at the end of your function:
document.getElementById('restart-button').disabled = false;
I'm quite new to javascript so the answer is probably quite easy but anyways
I'm trying to make a simple click speed test but i cant get the timer to start when the user presses the click me button, so i resorted to just starting it automatically. if anyone can help me to start it on the button press it will be much appreciated
HTML code:
<button id="click2" onclick="click2()">Click Me!</button><br>
<span id="clicksamount">0 Clicks</span><br><br>
<span id="10stimer">10s</span>
JS code:
var click = document.getElementById("click2");
var amount = 0;
var seconds = 10;
var endOfTimer = setInterval(click2, 1000);
function click2() {
seconds--;
document.getElementById("10stimer").innerHTML = seconds + "s";
if (seconds <= 0) {
var cps = Number(amount) / 10;
document.getElementById("clicksamount").innerHTML = "You got " + cps + " CPS!";
document.getElementById("click2").disabled = true;
document.getElementById("10stimer").innerHTML = "Ended";
clearInterval(seconds);
}
}
document.getElementById("click2").onclick = function() {
amount++;
document.getElementById("clicksamount").innerHTML = amount + " Clicks";
}
It looks like you're overwriting your onclick function on the button with id click2 with the lowest 4 lines.
Also, you call clearInterval() with the seconds variable instead of the actual interval, which is referenced by endOfTimer.
I'd suggest to have a separated timer management in a function which you call only on the first click of your button.
See JSFiddle
<button id="clickbutton" onclick="buttonClick()">Click Me!</button><br>
<span id="clicksamount">0 Clicks</span><br><br>
<span id="secondcount">10s</span>
// We will have timerStarted to see if the timer was started once,
// regardless if it's still running or has already ended. Otherwise
// we would directly restart the timer with another click after the
// previous timer has ended.
// timerRunning only indicates wether the timer is currently running or not.
var timerStarted = false;
var timerRunning = false;
var seconds = 10;
var clickAmount = 0;
var timer;
function buttonClick() {
if (!timerStarted) {
startTimer();
}
// Only count up while the timer is running.
// The button is being disabled at the end, therefore this logic is only nice-to-have.
if (timerRunning) {
clickAmount++;
document.getElementById("clicksamount").innerHTML = clickAmount + " Clicks";
}
}
function startTimer() {
timerStarted = true;
timerRunning = true;
timer = setInterval(timerTick,1000);
}
function timerTick() {
seconds--;
document.getElementById("secondcount").innerHTML = seconds + "s";
if (seconds <= 0) {
timerRunning = false;
clearInterval(timer);
var cps = Number(clickAmount) / 10;
document.getElementById("clickbutton").disabled = true;
document.getElementById("clicksamount").innerHTML = "You got " + cps + " CPS (" + clickAmount + "clicks in total)!";
}
}
I made some changes to your code. Effectively, when the user clicks the first time, you start the timer then. The timer variables is null until the first the user clicks.
var click = document.getElementById("click2");
var noOfClicks = 0;
var seconds = 10;
var timer = null;
function doTick(){
seconds--;
if(seconds<=0){
seconds = 10;
clearInterval(timer);
document.getElementById("10stimer").innerHTML= "Ended"
timer=null;
document.getElementById("click2").disabled = true;
}
updateDisplay()
}
function updateClicks(){
if(!timer){
timer=setInterval(doTick, 1000);
clicks= 0;
seconds = 10;
}
noOfClicks++;
updateDisplay();
}
function updateDisplay(){
var cps = Number(noOfClicks) / 10;
document.getElementById("clicksamount").innerHTML = "You got " + cps + " CPS!";
document.getElementById("10stimer").innerHTML =seconds;
}
click.addEventListener('click', updateClicks)
https://jsbin.com/bibuzadasu/1/edit?html,js,console,output
function timer(startEvent, stopEvent) {
let time = 0;
startEvent.target.addEventListener(startEvent.type, () => {
this.interval = setInterval(()=>{
time++;
}, 10); // every 10 ms... aka 0.01s
removeEventListener(startEvent.type, startEvent.target); // remove the listener once we're done with it.
stopEvent.target.addEventListener(startEvent.type, () => {
clearInterval(this.interval); // stop the timer
// your output function here, example:
alert(time);
removeEventListener(stopEvent.type, stopEvent.target); // remove the listener once we're done with it.
});
});
}
Use event listeners rather than onclicks
usage example:
HTML
<button id="mybutton">Click me!</button>
JS
/* ABOVE CODE ... */
let mybutton = document.getElementById("mybutton");
timer(
{target: mybutton, type: "click"},
{target: mybutton, type: "click"}
);
function timer(startEvent, stopEvent) {
let time = 0;
startEvent.target.addEventListener(startEvent.type, () => {
this.interval = setInterval(()=>{
time++;
}, 10); // every 10 ms... aka 0.01s
removeEventListener(startEvent.type, startEvent.target); // remove the listener once we're done with it.
stopEvent.target.addEventListener(startEvent.type, () => {
clearInterval(this.interval); // stop the timer
// your output function here, example:
alert(time);
removeEventListener(stopEvent.type, stopEvent.target); // remove the listener once we're done with it.
});
});
}
let mybutton = document.getElementById("mybutton");
timer(
{target: mybutton, type: "click"},
{target: mybutton, type: "click"}
);
<button id="mybutton">Click me!</button>
//state initialization
var amount = 0;
var seconds = 10;
var timedOut=false;
var timerId=-1;
//counters display
var clicksDisplay= document.getElementById("clicksamount");
var timerDisplay= document.getElementById("10stimer");
function click2(e){
//first click
if(timerId===-1){
//start timer
timed();
}
//still in time to count clicks
if(!timedOut){
amount++;
clicksDisplay.innerText=amount +" Clicks";
}
}
function timed(){
//refresh timer dispaly
timerDisplay.innerText=seconds+"s";
seconds--;
if(seconds<0){
//stop click count
timedOut=true;
}else{
//new timerId
timerId=setTimeout(timed,1000);
}
}
I have a button its disabled and i want to put a counter inside it, what i want to do is when the counter reaches zero it get enabled, how can i do that? in the code below the counter doesn't appear inside the button and i don't want the reset button i just want the button to be enabled when it reaches zero, here is what i have tried so far:
function Countdown()
{
this.start_time = "00:30";
this.target_id = "#timer";
this.name = "timer";
this.reset_btn = "#reset";
}
Countdown.prototype.init = function()
{
this.reset();
setInterval(this.name + '.tick()',1000)
}
Countdown.prototype.reset = function()
{
$(this.reset_btn).hide();
time = this.start_time.split(":");
//this.minutes = parseInt(time[0]);
this.seconds = parseInt(time[1]);
this.update_target();
}
Countdown.prototype.tick = function()
{
if(this.seconds > 0) //|| this.minutes > 0)
{
if(this.seconds == 0)
{
// this.minutes = this.minutes - 1;
this.seconds = 59
} else {
this.seconds = this.seconds - 1;
}
}
this.update_target()
}
Countdown.prototype.update_target = function()
{
seconds = this.seconds;
if (seconds == 0) $(this.reset_btn).show();
else if(seconds < 10) seconds = "0" + seconds;
$(this.target_id).val(this.seconds)
}
timer = new Countdown();
timer.init();
$(document).ready(function(){
$("#reset").click(function(){
//timer = new Countdown();
timer.reset();
});
});
.hidden {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="text" id="timer" disabled>Counter should be inside me, and enable me when it reaches 0</button>
<button id="reset">Reset</button>
This is much simpler than what you've got. Just use window.setTimeout().
Keep in mind that tracking time to a high precision is not super reliable in a browser. You may want to look at moment.js or use performance.now() for an easier API to handle that.
// Get refreence to span and button
var spn = document.getElementById("count");
var btn = document.getElementById("btnCounter");
var count = 5; // Set count
var timer = null; // For referencing the timer
(function countDown(){
// Display counter and start counting down
spn.textContent = count;
// Run the function again every second if the count is not zero
if(count !== 0){
timer = setTimeout(countDown, 1000);
count--; // decrease the timer
} else {
// Enable the button
btn.removeAttribute("disabled");
}
}());
<button id="btnCounter" disabled>Time left: <span id="count"></span></button>
I want to build a button that when I click it, the function in JavaScript associated with it initiates (so a loop inside it start doing something).
If I click it again before the loop inside the function finishes, the loop will terminates.
If I click it again after the loop inside the function has already finished, the loop will just start as usual.
How do I do this with the following code?
Thanks in advance.
HTML:
<button id="startstop" class="btn btn-primary" onclick="count()">
JavaScript:
function count() {
var val = 0;
var loop = setInterval(function(){
val++;
if (val > 1000} {
clearInterval(loop);
}
}, 100);
}
try this code
var loop;
function count() {
var val = 0;
if (loop) {
clearInterval(loop);
loop = null;
}
else{
loop = setInterval(function(){
val++;
console.log(val);
if (val > 1000) {
clearInterval(loop);
loop = null;
}
}, 100);
}
}
I'm not a big fan of doing work for people, but on this occasion I'll succumb...
You need to store the internal ID outside of the function, and base your process on that. If the ID is not set, start the interval, if it is set stop the interval.
Note, that I've massively reduced the length of interval, and the number of times it fires for this example...
var _intervalId = -1;
function count() {
if (_intervalId == -1) {
var val = 0;
_intervalId = setInterval(function(){
val++;
if (val > 200) {
clearInterval(_intervalId);
_intervalId = -1
document.getElementById("output").innerHTML = "stopped automatically";
}
}, 10);
document.getElementById("output").innerHTML = "started";
} else {
clearInterval(_intervalId);
_intervalId = -1;
document.getElementById("output").innerHTML = "stopped manually";
}
}
<button onclick="count();return false">Click Here</button>
<div id="output"></div>
Place loop variable in global scope and everytime the user clicked stop previous loop if it's already started if not start it.
Hope this helps.
var loop=null;
count = function () {
var val = 0;
//Stop previous loop if it's already started
if(loop!=null){
clearInterval(loop);
loop=null;
}else{
loop = setInterval(function(){
val++;
console.log(val);
$('span').text(val);
if (val >= 20) {
clearInterval(loop);
}
}, 100);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="startstop" class="btn btn-primary" onclick="count()">Count</button>
<span>0</span>
I had fun building a small class for this. Feel free to use.
// Counter class
function Counter(callback, speed, max, init){
var loop = null;
this.callback = callback;
this.value = init || 0;
this.max = max;
function count(){
if (this.max && this.value >= this.max) {
clearInterval(loop);
loop = null;
} else {
this.value++;
}
this.callback(this.value);
}
this.start = function(){
if(!this.isStarted){
loop = setInterval(count.bind(this), speed);
}
};
this.stop = function(){
if(this.isStarted){
clearInterval(loop);
loop = null;
}
}
Object.defineProperty(this, "isStarted", { get: function(){
return !!loop;
}});
}
// Usage example.
var result = document.getElementById("counter");
var button = document.getElementById("startstop");
// Create the counter and the callback.
var counter = new Counter(function(val){
result.innerHTML = val;
}, 100, 1000);
// Init the result value.
result.innerHTML = counter.value;
// Listen for click events on the button.
button.addEventListener("click", function(){
if(counter.isStarted){
counter.stop();
} else {
counter.start();
}
});
<div id="counter"></div>
<button id="startstop">Toggle</button>
I would like to know how to change the speed of setInterval in real time e.g:
if (score < 10)
repeater = setInterval(function() {
spawnEnemy();
}, 1000);
if (score => 10)
repeater = setInterval(function() {
spawnEnemy();
}, 500);
I know this method doesn't work, but is there a way that I can achieve this some other way?
jsFiddle Demo
There is no way to change the interval speed itself once running. The only way to do it is to have a variable for the speed, and then clear the interval and start a new one with the new speed.
var speed = 500;
var changeSpeed = speed;
repeater = setInterval(repeaterFn, speed);
function repeaterFn(){
spawnEnemy();
if( changeSpeed != speed ){
clearInterval(repeater);
speed = changeSpeed;
repeater = setInterval(repeaterFn, speed);
}
}
function changeRepeater(){
changeSpeed = 700;
}
Another way would be to just use setTimeout rather than setInterval. Do the check every time so you can keep your speed logic in a seperate function.
var game_over = false;
var score = 0;
function getSpeedFromScore(score)
{
if (score > 20) {
game_over = true;
}
if (score < 10) {
return 1000;
} else {
return 500;
}
}
function spawnEnemyThenWait() {
if (!game_over) {
spawnEnemy();
var speed = getSpeedFromScore(score);
setTimeout(spawnEnemyThenWait, speed);
}
}
JS Fiddle http://jsfiddle.net/bq926xz6/
You can use clearInterval:
if (score < 10) {
clearInterval(repeater);
repeater = setInterval(spawnEnemy, 1000);
}
if (score => 10) {
clearInterval(repeater);
repeater = setInterval(spawnEnemy, 500);
}
But it depends on the context. If this snippet is executed more often, than it has to be, you will need some kind of mechanism to prevent it from resetting your interval all the time.
But there is (as I wrote in the comment to the question) no way to use clearInterval and change the interval itself. At least not without replacing it by a new interval as shown above.
You can use a game loop and track the spawn state in an enemy class:
// press f12 so see console
function Enemy() {
this.spawned = false;
this.spawnOn = 20;
this.tick = function () {
this.spawnOn = this.spawnOn - 1;
if (this.spawnOn == 0) {
this.spawned = true;
}
}
this.goBackToYourCage = function () {
this.spawnOn = Math.floor(Math.random() * 50) + 1;
this.spawned = false;
}
}
var enemy = new Enemy();
window.setInterval(function () {
enemy.tick();
if (enemy.spawned) {
console.log('spawned');
enemy.goBackToYourCage();
console.log('Next spawin in :' + enemy.spawnOn);
}
}, 100);
http://jsfiddle.net/martijn/qxt2fe8y/2/