-
Notifications
You must be signed in to change notification settings - Fork 340
Zipline Build a Pomodoro Clock
Created by Rafase282
Github | FreeCodeCamp | CodePen | LinkedIn | Website | E-Mail
Build a CodePen.io app that successfully reverse-engineers this: http://codepen.io/GeoffStorbeck/full/RPbGxZ/.
- Don't look at the example project's code on CodePen. Figure it out for yourself.
- You may use whichever libraries or APIs you need.
- Reverse engineer the example project's functionality, and also feel free to personalize it.
In software development and product management, a user story is a description consisting of one or more sentences in the everyday or business language of the end user or user of a system that captures what a user does or needs to do as part of his or her job function.
- As a user, I can start a 25 minute pomodoro, and the timer will go off once 25 minutes has elapsed.
- As a user, I can reset the clock for my next pomodoro.
- As a user, I can customize the length of each pomodoro.
Do not use templates for this zipline.
CodePen.io overrides the Window.open()
function, so if you want to open windows using jQuery, you will need to target invisible anchor elements like this one: <a target='_blank'>
.
The HTML part is very simple, nothing complicated. I keep using the same style I have used since my portfolio which is 90%of view point for the main section and the rest for the footer. I like adding a footer to all my pages. So far I keep it simple.
This is the whole html file. I have a label and an interface to configure the break-time and work-time so you can setup the timer.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Pomodoro Clock v2</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel='stylesheet prefetch' href='http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css'>
<link rel='stylesheet prefetch' href='https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css'>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<section class='container-fluid'>
<div class="row">
<div class="col-xs-12">
<h1 class='text-primary'>Pomodoro Clock V2!</h1>
</div>
</div>
<div class="row top-row">
<div class="col-xs-6 text-primary">
<h3>Break Length</h3>
</div>
<div class="col-xs-6 text-primary">
<h3>Session Length</h3>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<button type="button" class="btn btn-link btn-sm" id="minus">-</button>
<button type="button" class="btn btn-link btn-lg" id="break-time">5</button>
<button type="button" class="btn btn-link btn-sm" id="plus">+</button>
</div>
<div class="col-xs-6">
<button type="button" class="btn btn-link btn-sm" id="minus2">-</button>
<button type="button" class="btn btn-link btn-lg" id="work-time">25</button>
<button type="button" class="btn btn-link btn-sm" id="plus2">+</button>
</div>
</div>
<div class="row top-row text-primary">
<h2 id="status">Work!</h2>
<canvas id="progress"></canvas>
<div id="timer"></div>
</div>
<div class="row top-row text-primary bottom">
<button type="button" id="start"> Start
</button>
<button type="button" id="pause"> Pause
</button>
<button type="button" id="reset"> Reset
</button>
</div>
</section>
<footer>
<p>Copyright © Rafael J. Rodriguez 2015. All Rights Reserved</p>
</footer>
<script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src='http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js'></script>
<script src="js/index.js"></script>
</body>
</html>
The CSS is also simple, a background color with things centered.
h1, p, .row {
text-align: center;
font-size: 130%;
}
section {
min-height: 90vh;
}
footer {
min-height: 10vh;
padding-top: 30px;
padding-bottom: 1px;
background-color: black;
color: #e4f1fe;
}
body {
position: relative;
background-color: #ACECF7;
}
.top-row {
margin-top: 50px
}
.bottom {
margin-bottom: 50px;
}
This is where the magic happens!
Firs I setup my global variables for jQuery:
$workT = $('#work-time');
$breakT = $('#break-time');
$status = $('#status');
Might not be much but is a way to practice how to make variables using jQuery and also to shorten the things I have to type.
Next is to add code to control the minutes that will be added or removed.
// Controls for Break Length
$('#minus').click(function() {
$status.text('Break!');
if (+$breakT.text() > 1) {
$breakT.text(+$breakT.text() - 1);
}
});
$('#plus').click(function() {
$status.text('Break!');
$breakT.text(+$breakT.text() + 1);
});
// Controls for Session Length
$('#minus2').click(function() {
$status.text('Work!');
if (+$workT.text() > 1) {
$workT.text(+$workT.text() - 1);
}
});
$('#plus2').click(function() {
$status.text('Work!');
$workT.text(+$workT.text() + 1);
});
I didn't want to have zero minutes as that would be silly so I made sure to check when removing time to make sure that it cannot be set to zero or anything lower than one minute.
As for the alarm part, I used HTML5 to take care of that.
var audio = new Audio('http://soundbible.com/grab.php?id=1377&type=mp3');
function beep() {
audio.play();
}
It is important to have the new audio outside the function, before I had it inside and it was creating a new sound every time it function was called which was not needed.
Then because I wanted double digits all the time I had to create a function to keep double digits no matter what.
function pad(val) {
return ('00' + val).slice(-2);
}
The I'm creating a function to update the display with the right time. This needs to be used together with the update function.
var el = document.getElementById('timer');
function updateDisplay(t) {
var hours = Math.floor(t / 3600);
t -= hours * 3600;
var minutes = Math.floor(t / 60);
t -= minutes * 60;
var seconds = Math.floor(t);
el.innerHTML = pad(hours) + ':' + pad(minutes) + ':' + pad(seconds);
}
Before anything, lets setup the timer:
time = 0;
updateDisplay(time);
var running = true;
var tlast = (new Date()).getTime();
using new Date()
is crucial!
NOw, the update function is very meaty as most of the code is here, given that it is the core of the program.
function update() {
if (time <= 0.0) { // Already done
return;
}
var tnow = (new Date()).getTime();
var dt = (tnow - tlast) / 1000.0;
tlast = tnow;
time -= dt;
This part is to get the right color for the specific timer running for the progress animation.
if ($status.text() === 'Work!') {
totalTime = ($workT.text() * 60);
water = 'rgba(25, 139, 201, 1)';
}
if ($status.text() === 'Break!') {
totalTime = ($breakT.text() * 60);
water = 'rgba(255, 0, 0, 1)';
}
Takes the time and turns it into a value between 0 and 1 for the progress circle animation.
`fraction = 1 - (time / totalTime);``
Calls the updated animation.
$('#progress').waterbubble({
data: fraction,
animation: false,
waterColor: water,
});
If the time has finished then we need to switch to the other timer and also change the label and sound the alarm.
if (time <= 0.0) {
if ($status.text() === 'Work!') {
beep();
$status.text('Break!');
time = $breakT.text() * 60;
} else {
beep();
$status.text('Work!');
time = $workT.text() * 60;
}
}
Then we keep things goin on!
updateDisplay(time);
if (running) {
requestAnimationFrame(update);
}
}
The run function is what gets the timer to start up and work things. I use requestAnimationFrame
for this version. I have another version that is not quited finished with regards to the animations but the functionality is there using setinterval
function run() {
$status.text('Work!');
if (time <= 0.0) {
time = $workT.text() * 60;
}
tlast = (new Date()).getTime();
running = true;
requestAnimationFrame(update);
}
The easiest part due the the way the code works is to pause the timer.
function pause() {
running = false;
}
When stopping the timer, I want to reset everything so I have to take care of many things like the displayed time, the labels, and then default timers along with resetting the animation.
function stop() {
running = false;
time = 0;
el.innerHTML = '00:00:00';
$status.text('Work!');
$workT.text(25);
$breakT.text(5);
$('#progress').waterbubble({
data: 0.0,
animation: false,
waterColor: 'rgba(25, 139, 201, 1)',
});
}
We are almost done, I just have to set the buttons with their onclick call.
var bStart = document.getElementById('start');
var bPause = document.getElementById('pause');
var bReset = document.getElementById('reset');
bStart.onclick = run;
bPause.onclick = pause;
bReset.onclick = stop;
There is one last thing, setting up the progress bar animation. The first part was linking the files which I did on the html part, now we need the manual configuration.
$('#progress').waterbubble(
{
// bubble size
radius: 100,
// border width
lineWidth: undefined,
// data to present
data: 0.0,
// color of the water bubble
waterColor: 'rgba(25, 139, 201, 1)',
// text color
textColor: 'rgba(06, 85, 128, 0.8)',
// custom font family
font: '',
// show wave
wave: true,
// custom text displayed inside the water bubble
txt: undefined,
// enable water fill animation
animation: false,
});
If you want to check my previous version I will provide a link here however, I will not go on and explain he code.
I received help from many people, in particular @mutantspore with the progress bar that I got from here Liquid Bubble
The base for this code was thanks to @noob247365 who showed me how to implement the requestAnimationFrame
Thanks for visiting, if you like this please feel free to star my repo, follow me or even contact me about contributing as it will be a lot of work and having help would be cool.
- HTML5 and CSS
- Responsive Design with Bootstrap
- Gear up for Success
- jQuery
- Basic JavaScript
- Object Oriented and Functional Programming
- Basic Algorithm Scripting
- Basic Front End Development Projects
- Intermediate Algorithm Scripting
- JSON APIs and Ajax
- Intermediate Front End Development Projects
- Claim Your Front End Development Certificate
- Upper Intermediate Algorithm Scripting
- Automated Testing and Debugging
- Advanced Algorithm Scripting
- AngularJS (Legacy Material)
- Git
- Node.js and Express.js
- MongoDB
- API Projects
- Dynamic Web Applications
- Claim Your Back End Development Certificate
- Greefield Nonprofit Project 1
- Greefield Nonprofit Project 2
- Legacy Nonprofit Project 1
- Legacy Nonprofit Project 2
- Claim your Full Stack Development Certification
- Whiteboard Coding Interview Training
- Critical Thinking Interview Training
- Mock Interview 1
- Mock Interview 2
- Mock Interview 3