patternjavascriptMinor
jQuery stopwatch
Viewed 0 times
stopwatchjquerystackoverflow
Problem
Here is the link to the jsFiddle and below is the code:
JS:
```
$(function() {
var hours = minutes = seconds = milliseconds = 0;
var prev_hours = prev_minutes = prev_seconds = prev_milliseconds = undefined;
var timeUpdate;
// Start/Pause/Resume button onClick
$("#start_pause_resume").button().click(function(){
// Start button
if($(this).text() == "Start"){ // check button label
$(this).html("Pause");
updateTime(0,0,0,0);
}
// Pause button
else if($(this).text() == "Pause"){
clearInterval(timeUpdate);
$(this).html("Resume");
}
// Resume button
else if($(this).text() == "Resume"){
prev_hours = parseInt($("#hours").html());
prev_minutes = parseInt($("#minutes").html());
prev_seconds = parseInt($("#seconds").html());
prev_milliseconds = parseInt($("#milliseconds").html());
updateTime(prev_hours, prev_minutes, prev_seconds, prev_milliseconds);
$(this).html("Pause");
}
});
// Reset button onClick
$("#reset").button().click(function(){
if(timeUpdate) clearInterval(timeUpdate);
setStopwatch(0,0,0,0);
$("#start_pause_resume").html("Start");
});
// Update time in stopwatch periodically - every 25ms
function updateTime(prev_hours, prev_minutes, prev_seconds, prev_milliseconds){
var startTime = new Date(); // fetch current time
timeUpdate = setInterval(function () {
var timeElapsed = new Date().getTime() - startTime.getTime(); // calculate the time elapsed in milliseconds
// calculate hours
hours = parseInt(timeElapsed / 1000 / 60 / 60) + prev_hours;
// calculate minutes
minutes = parseInt(timeElapsed / 1000 / 60) + prev_minutes;
if (minutes > 60) minutes %= 60;
// calculate s
JS:
```
$(function() {
var hours = minutes = seconds = milliseconds = 0;
var prev_hours = prev_minutes = prev_seconds = prev_milliseconds = undefined;
var timeUpdate;
// Start/Pause/Resume button onClick
$("#start_pause_resume").button().click(function(){
// Start button
if($(this).text() == "Start"){ // check button label
$(this).html("Pause");
updateTime(0,0,0,0);
}
// Pause button
else if($(this).text() == "Pause"){
clearInterval(timeUpdate);
$(this).html("Resume");
}
// Resume button
else if($(this).text() == "Resume"){
prev_hours = parseInt($("#hours").html());
prev_minutes = parseInt($("#minutes").html());
prev_seconds = parseInt($("#seconds").html());
prev_milliseconds = parseInt($("#milliseconds").html());
updateTime(prev_hours, prev_minutes, prev_seconds, prev_milliseconds);
$(this).html("Pause");
}
});
// Reset button onClick
$("#reset").button().click(function(){
if(timeUpdate) clearInterval(timeUpdate);
setStopwatch(0,0,0,0);
$("#start_pause_resume").html("Start");
});
// Update time in stopwatch periodically - every 25ms
function updateTime(prev_hours, prev_minutes, prev_seconds, prev_milliseconds){
var startTime = new Date(); // fetch current time
timeUpdate = setInterval(function () {
var timeElapsed = new Date().getTime() - startTime.getTime(); // calculate the time elapsed in milliseconds
// calculate hours
hours = parseInt(timeElapsed / 1000 / 60 / 60) + prev_hours;
// calculate minutes
minutes = parseInt(timeElapsed / 1000 / 60) + prev_minutes;
if (minutes > 60) minutes %= 60;
// calculate s
Solution
Chess clock anyone? :D
HTML:
CSS:
JS:
HTML:
:
:
::
Start
Reset
CSS:
/*
Always prefix your styles with a unique selector your widget has
to prevent your styles from affecting other elements of the same
selector pattern. In this case, only those under .stopwatch gets
affected.
*/
.stopwatch .controls {
font-size: 12px;
}
/* I'd rather stick to CSS rather than JS for styling */
.stopwatch .controls button{
padding: 5px 15px;
background :#EEE;
border: 3px solid #06C;
border-radius: 5px
}
.stopwatch .time {
font-size: 150%;
}JS:
$(function () {
// Never assume one widget is just used once in the page. You might
// think of adding a second one. So, we adjust accordingly.
$('.stopwatch').each(function () {
// Cache very important elements, especially the ones used always
var element = $(this);
var running = element.data('autostart');
var hoursElement = element.find('.hours');
var minutesElement = element.find('.minutes');
var secondsElement = element.find('.seconds');
var millisecondsElement = element.find('.milliseconds');
var toggleElement = element.find('.toggle');
var resetElement = element.find('.reset');
var pauseText = toggleElement.data('pausetext');
var resumeText = toggleElement.data('resumetext');
var startText = toggleElement.text();
// And it's better to keep the state of time in variables
// than parsing them from the html.
var hours, minutes, seconds, milliseconds, timer;
function prependZero(time, length) {
// Quick way to turn number to string is to prepend it with a string
// Also, a quick way to turn floats to integers is to complement with 0
time = '' + (time | 0);
// And strings have length too. Prepend 0 until right.
while (time.length < length) time = '0' + time;
return time;
}
function setStopwatch(hours, minutes, seconds, milliseconds) {
// Using text(). html() will construct HTML when it finds one, overhead.
hoursElement.text(prependZero(hours, 2));
minutesElement.text(prependZero(minutes, 2));
secondsElement.text(prependZero(seconds, 2));
millisecondsElement.text(prependZero(milliseconds, 3));
}
// Update time in stopwatch periodically - every 25ms
function runTimer() {
// Using ES5 Date.now() to get current timestamp
var startTime = Date.now();
var prevHours = hours;
var prevMinutes = minutes;
var prevSeconds = seconds;
var prevMilliseconds = milliseconds;
timer = setInterval(function () {
var timeElapsed = Date.now() - startTime;
hours = (timeElapsed / 3600000) + prevHours;
minutes = ((timeElapsed / 60000) + prevMinutes) % 60;
seconds = ((timeElapsed / 1000) + prevSeconds) % 60;
milliseconds = (timeElapsed + prevMilliseconds) % 1000;
setStopwatch(hours, minutes, seconds, milliseconds);
}, 25);
}
// Split out timer functions into functions.
// Easier to read and write down responsibilities
function run() {
running = true;
runTimer();
toggleElement.text(pauseText);
}
function pause() {
running = false;
clearTimeout(timer);
toggleElement.text(resumeText);
}
function reset() {
running = false;
pause();
hours = minutes = seconds = milliseconds = 0;
setStopwatch(hours, minutes, seconds, milliseconds);
toggleElement.text(startText);
}
// And button handlers merely call out the responsibilities
toggleElement.on('click', function () {
(running) ? pause() : run();
});
resetElement.on('click', function () {
reset();
});
// Another advantageous thing about factoring out functions is that
// They are reusable, callable elsewhere.
reset();
if(running) run();
});
});Code Snippets
<!--
Never assume just one. Prepare for more than one always.
With that, we use classes
-->
<div class="stopwatch" data-autostart="false">
<div class="time">
<span class="hours"></span> :
<span class="minutes"></span> :
<span class="seconds"></span> ::
<span class="milliseconds"></span>
</div>
<div class="controls">
<!-- Some configurability -->
<button class="toggle" data-pausetext="Pause" data-resumetext="Resume">Start</button>
<button class="reset">Reset</button>
</div>
</div>/*
Always prefix your styles with a unique selector your widget has
to prevent your styles from affecting other elements of the same
selector pattern. In this case, only those under .stopwatch gets
affected.
*/
.stopwatch .controls {
font-size: 12px;
}
/* I'd rather stick to CSS rather than JS for styling */
.stopwatch .controls button{
padding: 5px 15px;
background :#EEE;
border: 3px solid #06C;
border-radius: 5px
}
.stopwatch .time {
font-size: 150%;
}$(function () {
// Never assume one widget is just used once in the page. You might
// think of adding a second one. So, we adjust accordingly.
$('.stopwatch').each(function () {
// Cache very important elements, especially the ones used always
var element = $(this);
var running = element.data('autostart');
var hoursElement = element.find('.hours');
var minutesElement = element.find('.minutes');
var secondsElement = element.find('.seconds');
var millisecondsElement = element.find('.milliseconds');
var toggleElement = element.find('.toggle');
var resetElement = element.find('.reset');
var pauseText = toggleElement.data('pausetext');
var resumeText = toggleElement.data('resumetext');
var startText = toggleElement.text();
// And it's better to keep the state of time in variables
// than parsing them from the html.
var hours, minutes, seconds, milliseconds, timer;
function prependZero(time, length) {
// Quick way to turn number to string is to prepend it with a string
// Also, a quick way to turn floats to integers is to complement with 0
time = '' + (time | 0);
// And strings have length too. Prepend 0 until right.
while (time.length < length) time = '0' + time;
return time;
}
function setStopwatch(hours, minutes, seconds, milliseconds) {
// Using text(). html() will construct HTML when it finds one, overhead.
hoursElement.text(prependZero(hours, 2));
minutesElement.text(prependZero(minutes, 2));
secondsElement.text(prependZero(seconds, 2));
millisecondsElement.text(prependZero(milliseconds, 3));
}
// Update time in stopwatch periodically - every 25ms
function runTimer() {
// Using ES5 Date.now() to get current timestamp
var startTime = Date.now();
var prevHours = hours;
var prevMinutes = minutes;
var prevSeconds = seconds;
var prevMilliseconds = milliseconds;
timer = setInterval(function () {
var timeElapsed = Date.now() - startTime;
hours = (timeElapsed / 3600000) + prevHours;
minutes = ((timeElapsed / 60000) + prevMinutes) % 60;
seconds = ((timeElapsed / 1000) + prevSeconds) % 60;
milliseconds = (timeElapsed + prevMilliseconds) % 1000;
setStopwatch(hours, minutes, seconds, milliseconds);
}, 25);
}
// Split out timer functions into functions.
// Easier to read and write down responsibilities
function run() {
running = true;
runTimer();
toggleElement.text(pauseText);
}
function pause() {
running = false;
clearTimeout(timer)Context
StackExchange Code Review Q#48383, answer score: 8
Revisions (0)
No revisions yet.