Related to this previous Question: How to stop a Javascript Timer after the second countdown?
I figured out a way for my Pomodoro clock to function properly, but my code is pretty repetitive. I couldn't figure out a way to not recreate the same (or very similar function) without the second break timer continuously running. Any ideas?
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
var countdown = setInterval(function () {
minutes = parseInt(timer / 60, 10)
seconds = parseInt(timer % 60, 10);
//minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
$(".startClock").click(function () {
clearInterval(countdown);
});
if (--timer < 0) {
clearInterval(countdown);
breakClock();
}
}, 500);
}
function breakTimer(duration, display) {
var timer = duration, minutes, seconds;
var countdown = setInterval(function () {
minutes = parseInt(timer / 60, 10)
seconds = parseInt(timer % 60, 10);
//minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
$(".startClock").click(function () {
clearInterval(countdown);
});
if (--timer < 0) {
clearInterval(countdown);
}
}, 500);
$("body").css("background-color", "#E13F86");
$("#title").text(function(i, text){
return text === 'Breaktime' ? 'Productive Countdown' : 'Breaktime'
});
}
var display = document.querySelector('#time');
function startClock() {
var twentyfiveMinutes = 60 * .25;
startTimer(twentyfiveMinutes, display);
}
function breakClock() {
var fiveMinutes = 60 * .05;
breakTimer(fiveMinutes, display);
}
$(".startClock").on("click", function() {
startClock();
});
Here's my codepen as well: http://codepen.io/cenjennifer/pen/pjzBVy?editors=101
Your code is fine. jfriend00 is right, this code does belong on the code review page.
But since I'm here, I will give some feedback. Make an object (using function(){}), and put all of your functions inside of the object.
Instead of recreating all your variables in each function, make them properties inside of the object, so that they are accessible to all of the functions, and so that you don't need to keep recreating them. (Variables like timer, hour, minutes, should be moved as object properties).
Also, don't use global variables, they can interfere with libraries you may find to be useful later on. You should namespace, so that the code is more organized, and does not get overwritten by other globals.
The easy way to reuse the function, is to share the timer returned by setInterval and provide a callback in the startTimer function (used for both start and break). The callback, if provided, takes care of the code to run after the timer finishes. Therefore the specific code can be omitted from startTimer. Also since the timer is shared, no matter when started, the original loop can be stopped when called again (the button is clicked again), so that too can be omitted from the startTimer function, thus making it ready for reusability. The whole would look something like:
var currentcountdown;
var display = document.querySelector('#time');
function startTimer(duration, callback) {
var timer = parseInt(duration), minutes, seconds;
clearInterval(currentcountdown);
currentcountdown = setInterval(function () {
minutes = Math.floor(timer / 60);
seconds = Math.floor(timer % 60);
//minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if (--timer < 0) {
clearInterval(currentcountdown);
if(callback)
callback();
}
}, 500);
}
function startClock() {
$("body").css("background-color", "black");
$("#title").text('Productive Countdown');
var twentyfiveMinutes = 60 * .25;
startTimer(twentyfiveMinutes, breakClock);
}
function breakClock() {
$("body").css("background-color", "#E13F86");
$("#title").text('Breaktime');
var fiveMinutes = 60 * .05;
startTimer(fiveMinutes);
}
$(".startClock").on("click", function() {
startClock();
});
As mentioned in the other post, synthetic sugar would be to put all values into objects (such as duration/background/title) and optionally put the timer and its variables (display/timer) into an object, but for straight forward re-usability of the function the above should provide a good start.
Related
I'm very new to Javascript and I found myself stuck with this issue. I want to make this countdown repeat after the time runs out, however I'm not really sure how to do it, and my attempts to make it work failed. Would appreciate help how to do it, Thanks.
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
setInterval(function () {
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if (--timer < 0) {
// here's the problem. not sure how to make it repeat
}
}, 1000);
}
window.onload = function () {
var fiveMinutes = 60 * 5,
display = document.querySelector('#time');
startTimer(fiveMinutes, display);
};
Tried using clearInterval() and setTimeout() but instead of it working the countdown either went past 00:00 (00:0-1 and so on) or just didn't work at all.
You can reset timer:
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
setInterval(function () {
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if (--timer < 0) {
timer = duration;
}
}, 1000);
}
What you're describing is a forever countdown.
Note that eventhough you specify 1000 in the setInterval(). The timer isn't precise, so the callback may fire less than or greater than 1000ms. It is much safer to capture the startTime and then calculate the currentTime when the callback fires and measure the elapsedTime. This will give a true indication of elapsed time regardless of whether the timer is running slow or fast.
Because of the reset requirement. I actually infer that the timer is an infinite loop. We run it forever. There is no description as to when the timer is aborted, so, we just continue measuring currentTime and note elapse.
I use elapsedTime = (currentTime - startTime) / 1000 to calculate the elapsed time in seconds. Then, I elapsed % duration to make the counter stop at the duration and reset. Finally, I flip the math countdown = duration - 1 - (elapsedTime % duration) so instead of counting up, it counts down.
We then break down countdown into the minutes and seconds components.
Below is a fully working example that uses jQuery.
function startTimer(duration, display) {
let startTime = Date.now();
setInterval(function() {
let currentTime = Date.now();
let elapsedTime = Math.floor((currentTime - startTime) / 1000);
let countdown = duration - 1 - (elapsedTime % duration);
let minutes = Math.floor(countdown / 60).toString().padStart(2, "0");
let seconds = (countdown % 60).toString().padStart(2, "0");
display.text(minutes + ":" + seconds);
}, 1000 );
}
let fiveMinutes = 60 * 5;
let display = $("#time");
startTimer(fiveMinutes, display);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<label id="time">mm:ss</label>
I need help or idea for use a countdown inside a setInterval.
heres my countdown timer on js (pretty obvious):
function startTimer(duration) {
var timer = duration, minutes, seconds;
setInterval(function () {
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
document.getElementById('minuteDrag').innerText = minutes;
document.getElementById('secondDrag').innerText = seconds;
if (--timer < 0) {
timer = duration;
}
}, 1000);
}
When i call this function outside the second setinterval, that works pecfectly (as expected).
But when i tried to run this function in the code below, the function for time countdown gets bugged, i guess it's because the countdown timer is called within another setinterval.
Any ideas for a solution here? (i can't get out the "main setinterval").
var api = new Lolesports_API();
api.get_event_details('pt-BR', '105562529627228920')
.then(result_games => {
var game_id
result_games.event.match.games.forEach(game => game_id = game.id)
api.get_teams('pt-BR')
.then(result_teams =>{
var teams_dict = {}
result_teams.teams.forEach(team => {teams_dict[team.id] = team.code})
setInterval(function(){
api.get_window(game_id, get_lastest_date())
.then(result_window => {
var last_frame = result_window.frames[result_window.frames.length - 1];
var game_state = last_frame.gameState;
startTimer(60*5)
if (game_state == 'in_game') {
document.getElementById("gameState").style.backgroundColor = '#33cc33';
stopwatch_game.start();
} else if (game_state == 'paused') {
document.getElementById("gameState").style.backgroundColor = '#66a3ff';
stopwatch_game.pause();
} else {
document.getElementById("gameState").style.backgroundColor = '#ff8080';
stopwatch_game.pause();
}
//stopwatch_game.start();
})
}, 500)
})
})
PS: this is not the full code, i remove a large part in order not to pollute the question.
Right now you're starting a new CountDown Interval every half second.
Why not return the value from the setInterval in startTimer so that it can be stopped as necessary by the outer loop?
e.g.
startTimer = (duration) => {
let timer = duration, minutes, seconds;
return setInterval(function () {
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
document.getElementById('minuteDrag').innerText = minutes;
document.getElementById('secondDrag').innerText = seconds;
if (--timer < 0) {
timer = duration;
}
}, 1000);
}
Then in your main loop you can use clearInterval to stop the timer... or at least check if it exists:
let foo = undefined;
if (foo === undefined) {
foo = startTimer(60*5);
}
So i am writing a simple javascript timer, and at 30 seconds it prompts the user with an alert box if they would like to reset the count down or let it continue.
I am able to reset the timer however I get stuck when the user clicks cancel on the alert box.
I tried letting the timer just resume at its current time but that doesn't help as the alert box just keeps reappearing
I am still very new to javascript so I would like to stay using vanilla js till I get a deeper understanding of the fundamentals!
Any guidance would be greatly appreciated!
Heres my code:
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
setInterval(function () {
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if(timer<30){
var message = confirm("Would you like to extend timer?");
if (message == true) {
timer = 60 * 1;
}
else{
timer = timer;
}
}
if (--timer < 0) {
timer = duration;
}
}, 1000);
}
function resetTimer() {
timer = 60 * 1;
}
window.onload = function () {
var fiveMinutes = 60 * 1,
display = document.querySelector('#time');
startTimer(fiveMinutes, display);
};
just put if(timer==30) instead of if(timer<30) so that exactly at count of 30 units of time, you get asked once for confirmation at that instance (However be aware that until the confirmation is done, prompts will keep popping up every second). if you extend it, it will again wait till your timer goes down to 30 unit, else it will simply go down to 0 and break out.
function startTimer(duration, display) {
var timer = duration,
minutes,
seconds;
function timerFunc() {
timer -= 1;
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if (timer == 30) {
var message = confirm("Would you like to extend timer?");
if (message == true) {
timer = 60;
} else return alert("Your timer has been stopped.")
}
setTimeout(timerFunc, 1000);
}
timerFunc();
}
I have PHP page, where I added a countdown for 30 min. and as it ticks when I refresh the page or perform a query of 'insert' and redirect back to that page, the timer gets reset.
I want the timer to be constant and continue count without any interruptions when the page gets refreshed.
My code goes as:
function startTimer(duration, display) {
var timer = duration,
minutes, seconds;
setInterval(function() {
minutes = parseInt(timer / 60, 10)
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if (--timer < 0) {
timer = duration;
}
}, 1000);
}
window.onload = function() {
var fiveMinutes = 60 * 30,
display = document.querySelector('#time');
startTimer(fiveMinutes, display);
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="timer">
<div>Section</div>
<div class="time">
<strong>Time left: <span id="time">30:00</span></strong>
</div>
</div>
Any Help Is Appreciated..
Use html5 local storage to update the timer value and when page load occurs read the timer value from local storage. I guess no other way.
Whenever your PHP page loads, the javascript is loaded with it. So
window.onload = function () {
var fiveMinutes = 60 * 30,
display = document.querySelector('#time');
startTimer(fiveMinutes, display);
};
is called and the timer starts at 5 minutes.
One solution would be to do an Ajax request in window.onload and get the remaining time.
Another solution would be to set the fiveMinutes variable (obviously it should be renamed more appropriately) via PHP, if the javascript code is inside your PHP file, like
<script>
...
var timeLeft = <?php echo $timeLeft ?>;
...
</script>
The first solution is the standard way to go and the second one is the easy way to go.
As others have pointed out, you could use local storage (if the your target clients support this feature see here)
<script>
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
setInterval(function () {
minutes = parseInt(timer / 60, 10)
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
timer = --timer;
if (timer >= 0) {
localStorage.setItem('time', timer);
//timer = duration;
}
}, 1000);
}
window.onload = function () {
var countDown = 60 * 30;
var oldVal = localStorage.getItem('time');
if (oldVal && oldVal > 0) {
countDown = oldVal;
}
var display = document.querySelector('#time');
startTimer(countDown, display);
};
</script>
edit: of course one must not forget to check whether the stored value is below zero.
As already pointed out, you could store the current time with localStorage.
To do so you would save both minutes and seconds in each interval tick:
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
setInterval(function () {
minutes = parseInt(timer / 60, 10)
seconds = parseInt(timer % 60, 10);
localStorage.setItem("minutes", minutes); // <--
localStorage.setItem("seconds", seconds); // <--
And in the load function you'd read from them and set the starting value appropriately. It's important to note that values are always stored as strings, and as such, it would be necessary to parse them back to numbers before passing them through:
window.onload = function () {
var timeLeft = 60 * 30,
display = document.querySelector('#time');
var minutes = localStorage.getItem("minutes"); //read minutes
var seconds = localStorage.getItem("seconds"); //read seconds
if (minutes && seconds){
timeLeft = Number(minutes) * 60 + Number(seconds); //set time with val from storage
}
startTimer(timeLeft, display);
};
I changed the name of your fiveMinutes to timeLeft to better reflect what it holds, and parsed both values to numbers with Number().
It's also important to mention that while this does keep the value after refreshes, it doesn't "count" the time while the page was closed. So keep that in mind.
Instead of refreshing the whole page try to use Ajax for communication and modify your html page using javascript.
I have a timer script but I am having a few issues with it. Just a day ago, it was working perfectly fine, as intended. Now, the timer no longer hides the div class when it ends. Didn't change the HTML or JavaScript code at all, but for whatever reason it no longer removes the div class.
Here is the JavaScript code:
function startTimer(duration, display) {
var timer = duration,
minutes,
seconds;
setInterval(function() {
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? '0' + minutes : minutes;
seconds = seconds < 10 ? '0' + seconds : seconds;
display.textContent = minutes + ' ' + ' ' + seconds;
if (--timer < 0) {
display.textContent = 'OFFER HAS EXPIRED.';
$('.formme').css('visibility', 'hidden');
}
console.log(parseInt(seconds));
window.localStorage.setItem('seconds', seconds);
window.localStorage.setItem('minutes', minutes);
}, 1000);
}
window.onload = function() {
sec = parseInt(window.localStorage.getItem('seconds'));
min = parseInt(window.localStorage.getItem('minutes'));
if (parseInt(sec) == 0 && parseInt(min) == 0) {
$('#time').text('OFFER HAS EXPIRED.');
$('.formme').css('visibility', 'hidden');
} else {
var start = 5 * 60;
if (sec > 0 || min > 0) {
start = parseInt(min * 60) + sec;
}
// var start = 60 * 5;
display = document.querySelector('#time');
startTimer(start, display);
}
};
On top of that, I used localStorage to prevent the timer from resetting when the webpage is refreshed. However, when the timer is finished, instead of going straight to the "OFFER HAS EXPIRED" text, it counts down from 00:01 then displays the text. Can anyone help me out? Thanks in advance!