Pomodoro Clock
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
@import url(https://fonts.googleapis.com/css?family=Maven+Pro:400,500,700);
body { /* the !important necessary to keep Bootstrap fonts from overriding Google fonts */
font-family: 'Maven Pro', sans-serif !important;
font-weight: 400 !important;
font-size: 2em !important;
height: 100%;
background: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/wall_prints.jpg');
background-size: auto;
position: relative;
}
#main_container {
width: auto;
height: auto;
padding: 0;
margin: 0;
}
#container-fluid {
padding: 0;
margin: 0;
}
.text h1 {
font-size: 2.2em !important;
margin-top: 40px;
text-align: center;
color: #0A342B;
font-weight: 500 !important;
text-shadow: 1px 1px 1px #000, 3px 3px 5px blue;
}
.text h3 {
text-align: center;
font-size: 1.1em !important;
color: #89633d;
margin-top: 0;
}
.text h3 a:link {
color: #b54103;
text-decoration: none;
}
.text h3 a:visited {
color: #b54103;
text-decoration: none;
}
.text h3 a:hover {
color: #4a9ca5;
text-decoration: none;
}
.text h3 a:active {
color: #dd8023;
text-decoration: none;
}
#clock_container {
display: inline-block;
width: 100%;
margin-top: 40px;
margin-left: 4px;
}
#liveclock {
margin: 0 auto;
}
#work_length {
text-align: center;
margin: auto;
color: #0A342B;
padding-top: 96px;
font-size: 0.9em !important;
font-weight: bold;
}
#display_work_timer {
color: #ff4500;
}
#display_play_timer {
color: #0000ff;
}
#break_length {
text-align: center;
margin: auto;
color: #0A342B;
padding-top: 96px;
font-size: 0.9em !important;
font-weight: bold;
}
.bold {
font-size: 1.0em !important;
color: #0A342B;
text-shadow: 1px 1px 2px #11342b;
}
#controls {
border-radius: 6px;
background-color:rgba(0, 0, 0, 0.1);
text-align: center;
margin: 20px auto;
width: 260px;
border: solid 1px darkseagreen;
}
#controls #ctrl-play.btn:hover {
border: solid 1px #ff5000;
}
#controls #ctrl-play.btn:active {
border: solid 1px red;
}
#controls #ctrl-pause.btn:hover {
border: solid 1px #ff5000;
}
#controls #ctrl-pause.btn:active {
border: solid 1px red;
}
#controls #ctrl-stop.btn:hover {
border: solid 1px #ff5000;
}
#controls #ctrl-stop.btn:active {
border: solid 1px red;
}
#controls #ctrl-repeat.btn:hover {
border: solid 1px #ff5000;
}
#controls #ctrl-repeat.btn:active {
border: solid 1px red;
}
#controls #ctrl-about.btn:hover {
border: solid 1px #ff5000;
}
#controls #ctrl-about.btn:active {
border: solid 1px red;
}
.pad {
margin: 0 auto;
height: 200px;
}
@media only screen and (max-width : 1200px) {
#break_length {
padding-left: 40px;
}
}
@media only screen and (max-width : 991px) {
#break_length {
padding-top: 0;
padding-left: 16px;
}
#work_length {
padding-top: 0;
}
}
/** CSS for Clock - modified for FCC Pomodoro Clock use **/
.outer_face {
position: relative;
width: 300px; /* width of clock */
height: 300px; /* height of clock */
border-radius: 40px; /* clock round corner radius */
background: #512d17;
box-shadow: inset 0 0 16px #8E664D;
border: 3px solid #ffa100; /* thickness of outer border */
}
.outer_face::before, .outer_face::after, .outer_face .marker { /* time markers style */
content: "";
position: absolute;
width: 6px; /* width of 12-6 and 3-9 markers */
height: 100%;
background: black;
z-index: 0;
left: 50%;
margin-left: -3px; /* set this value of 1/2 marker width */
top: 0;
}
.outer_face::after {
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.outer_face .marker {
background: #9e5e1e;
width: 4px; /* width of all other markers */
margin-left: -2px; /* set this value of 1/2 marker width */
}
.outer_face .marker.oneseven {
-moz-transform: rotate(30deg);
-ms-transform: rotate(30deg);
-webkit-transform: rotate(30deg);
transform: rotate(30deg);
}
.outer_face .marker.twoeight {
-moz-transform: rotate(60deg);
-ms-transform: rotate(60deg);
-webkit-transform: rotate(60deg);
transform: rotate(60deg);
}
.outer_face .marker.fourten {
-moz-transform: rotate(120deg);
-ms-transform: rotate(120deg);
-webkit-transform: rotate(120deg);
transform: rotate(120deg);
}
.outer_face .marker.fiveeleven {
-moz-transform: rotate(150deg);
-ms-transform: rotate(150deg);
-webkit-transform: rotate(150deg);
transform: rotate(150deg);
}
.inner_face {
position: relative;
width: 88%;
height: 88%;
background: #512d17;
-moz-border-radius: 1000px;
-webkit-border-radius: 1000px;
border-radius: 1000px;
z-index: 1000;
left: 6%; /* set this value of 1/2 width value*/
top: 6%; /* set this value of 1/2 height value*/
}
.inner_face:before {
/* clock center circle small */
content: "";
width: 40px; /* width of inner circle */
height: 40px; /* height of inner circle */
border-radius: 18px;
margin-left: -20px; /* set this value of 1/2 width value*/
margin-top: -20px; /* set this value of 1/2 height value*/
background: url(http://images.ticiz.com/2603690_w0_h120_hnn1i...bv9ettdv9dsbugw0py.png);
position: absolute;
top: 50%;
left: 50%;
}
.inner_face:after {
content: "FreeCodeCamp";
position: absolute;
width: 100%;
font: normal 0.6em Arial !important;
color: gray;
text-align: center;
top: 84%;
z-index: 0;
}
.hand, .hand.hour {
position: absolute;
width: 3px; /* width of hour hand */
height: 31%; /* height of hour hand */
top: 20%; /* set top to 50% - height */
left: 50%;
margin-left: -1.5px; /* set this value to 1/2 width */
background: black;
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
-moz-transform-origin: bottom;
-ms-transform-origin: bottom;
-webkit-transform-origin: bottom;
transform-origin: bottom;
z-index: -1;
-moz-box-shadow: 0 0 1px #512d17;
-webkit-box-shadow: 0 0 1px #512d17;
box-shadow: 0 0 1px #512d17;
}
.hand.minute {
height: 45%; /* height of min hand */
top: 5%; /* set top to 50% - height */
width: 3px; /* width of min hand */
margin-left: -1.5px; /* set this value to 1/2 width */
}
.hand.second {
height: 50%; /* height of sec hand */
width: 2px; /* width of sec hand */
margin-left: -1px; /* set this value to 1/2 width */
top: 0;
background: red;
}
.hand.work {
height: 16%; /* height of work hand */
width: 2px; /* width of work hand */
margin-left: -1px; /* set this value to 1/2 width */
top: 90px;
background: #ff4500;
}
.hand.break {
height: 16%; /* height of break hand */
width: 2px; /* width of break hand */
margin-left: -1px; /* set this value to 1/2 width */
top: 90px;
background: #0000ff;
}
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
/**
* Created by Rick Stewart on 11/20/2015.
*/
/* 'exported' statement tells JsHint to ignore 'function never used' warning as they are called externally */
/* exported plusWorkTime */
/* exported minusWorkTime */
/* exported plusBreakTime */
/* exported minusBreakTime */
/* exported playAlarm */
/* exported start */
/* exported stop */
/* exported reset */
/* exported popOpenInfoWindow */
'use strict'; // tells browsers to use strict - a best practice
var workLength = 25; // default of 25 minutes for a pomodoro
var breakLength = 5; // default of 5 minutes for a break
var $hands = $('#liveclock').find('div.hand'); // get reference
var freezeHands = false; // if true pomodoro hands (work, break ) stop advancing
var workAsDegree = 0;
var breakAsDegree = 0;
var frozenWorkAsDegree = 0;
var frozenBreakAsDegree = 0;
var targetDisplayWorkLength = document.getElementById('display_work_timer'); // store HTML page location work length
var targetDisplayBreakLength = document.getElementById('display_play_timer'); // store HTML page location break length
var alarmNotTriggeredFlag = true; // 'true' if alarm was not yet triggered
var timerRunning = false; // 'true' when timer running a pomodoro
var infoWindow;
targetDisplayWorkLength.innerHTML = workLength; // set initial work length
targetDisplayBreakLength.innerHTML = breakLength; // set initial break length
var plusWorkTime = function() { // increment work time value
if(workLength <= 58) {
workLength += 1;
targetDisplayWorkLength.innerHTML = workLength;
}
};
var minusWorkTime = function() { // decrement work length value
if(workLength >= 2) {
workLength -= 1;
targetDisplayWorkLength.innerHTML = workLength;
}
};
var plusBreakTime = function() { // increment break time value
if(breakLength <= 58) {
breakLength += 1;
targetDisplayBreakLength.innerHTML = breakLength;
}
};
var minusBreakTime = function() { // decrement break length value
if(breakLength >= 2) {
breakLength -= 1;
targetDisplayBreakLength.innerHTML = breakLength;
}
};
var playAlarm = function() {
var audioElement = document.createElement('audio');
audioElement.setAttribute('src', 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/tinsha.mp3');
audioElement.play();
};
/***********************************************
* FreeCodeCamp Pomodoro Clock based on:
*
* CSS3 Analog Clock- by JavaScript Kit (www.javascriptkit.com)
* http://www.javascriptkit.com/script/script2/css3analogclock.shtml
***********************************************/
var setFreezeHands = function(bool) {
freezeHands = bool;
};
var setRunning = function(bool) {
timerRunning = bool;
};
var setAlarmTriggered = function(bool) {
alarmNotTriggeredFlag = bool;
};
var setTimeAtStart = function() { // record start time for pomodoro
var currentDate = new Date();
frozenWorkAsDegree = (workLength / 60 * 360) + (currentDate.getMinutes() / 60 * 360);
frozenBreakAsDegree = frozenWorkAsDegree + (breakLength / 60 * 360);
};
/* Control Panel buttons */
var start = function() {
setTimeAtStart();
setRunning(true);
setFreezeHands(true);
};
var stop = function() {
setFreezeHands(false);
setRunning(false);
};
var reset = function() {
workLength = 25; // reset to default values
breakLength = 5;
targetDisplayWorkLength.innerHTML = workLength; // set work length
targetDisplayBreakLength.innerHTML = breakLength; // set break length
setFreezeHands(false);
setRunning(false);
};
var popOpenInfoWindow = function() { // opens information window
var leftValue = (screen.width/2)-(300/2); // centers window on viewport
var topValue = (screen.height/2)-(400/2);
infoWindow = window.open('','infoWindow','height=400px,width=300px,left='+leftValue+',top='+topValue+',menubar=no,resizable=no,status=yes,titlebar=no,location=no,scrollbars=yes');
infoWindow.document.write('<html><head><title>Helpful Information</title>');
infoWindow.document.write('<link rel="stylesheet" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/popupStyle.css">');
infoWindow.document.write('</head><body>');
infoWindow.document.write('<h2>User Guide</h2>');
infoWindow.document.write('<p><a href="https://en.wikipedia.org/wiki/Pomodoro_Technique" target="_blank">Wiki article describing Pomodoro</a></p>');
infoWindow.document.write('<h4>\"Play\"</h4>');
infoWindow.document.write('<p>Starts a countdown equal to the number of minutes set by the Work Duration. A chime will sound when this countdown completes.</p>');
infoWindow.document.write('<p>When a Work Period ends a second countdown begins, this time equal to the set Break Time. Again a chime will sound when this countdown completes.</p>');
infoWindow.document.write('<p>This cycle repeats indefinitely until either the Stop or Reset button is pushed.</p>');
infoWindow.document.write('<p>The short orange hand on the clock face indicates Work Time remaining. When the minute hand reaches the orange hand, work time is up.</p>');
infoWindow.document.write('<p>In the same fashion the short blue colored hand indicates Break Time remaining.</p>');
infoWindow.document.write('<h4>Stop</h4>');
infoWindow.document.write('<p>Pushing Stop ends the countdown, and leaves Work Duration and Break Duration unchanged.</p>');
infoWindow.document.write('<h4>Reset</h4>');
infoWindow.document.write('<p>Pushing Reset ends the countdown, and returns Work Duration and Break Duration to default values.</p>');
infoWindow.document.write('<br/>');
infoWindow.document.write('<p><a href="javascript:self.close()">Close</a> this popup.</p>');
infoWindow.document.write('<br/>');
infoWindow.document.write('</body></html>');
infoWindow.document.close();
};
window.requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (f) {
setTimeout(f, 60);
};
var updateClock = function () {
var theDate = new Date();
var hourAsDegree = ( theDate.getHours() + theDate.getMinutes() / 60 ) / 12 * 360;
var minuteAsDegree = theDate.getMinutes() / 60 * 360;
var secondAsDegree = ( theDate.getSeconds() + theDate.getMilliseconds() / 1000 ) / 60 * 360;
$hands.filter('.hour').css({transform: 'rotate(' + hourAsDegree + 'deg)'});
$hands.filter('.minute').css({transform: 'rotate(' + minuteAsDegree + 'deg)'});
$hands.filter('.second').css({transform: 'rotate(' + secondAsDegree + 'deg)'});
if (freezeHands) {
/** if freezeHands == true, hands 'work' and 'break' do not advance **/
$hands.filter('.work').css({transform: 'rotate(' + frozenWorkAsDegree + 'deg)'});
/** pomodoro work hand **/
$hands.filter('.break').css({transform: 'rotate(' + frozenBreakAsDegree + 'deg)'});
/** pomodoro break hand **/
}
else {
workAsDegree = minuteAsDegree + (workLength / 60 * 360);
breakAsDegree = workAsDegree + (breakLength / 60 * 360);
$hands.filter('.work').css({transform: 'rotate(' + workAsDegree + 'deg)'});
$hands.filter('.break').css({transform: 'rotate(' + breakAsDegree + 'deg)'});
}
if(((frozenWorkAsDegree % 360) === (minuteAsDegree % 360)) && alarmNotTriggeredFlag && timerRunning) { // work time expired?
playAlarm();
setAlarmTriggered(false);
}
if(((frozenBreakAsDegree % 360) === (minuteAsDegree % 360)) && !alarmNotTriggeredFlag && timerRunning) { // break time expired?
playAlarm();
setAlarmTriggered(true);
setFreezeHands(false);
start();
}
requestAnimationFrame(updateClock);
};
$(window).load (function () { // start animation running
requestAnimationFrame(updateClock);
});
FreeCodeCamp Zipline to design and implement a Pomodoro Clock.
http://www.freecodecamp.com/challenges/zipline-build-a-pomodoro-clock
A Pen by HARUN PEHLİVAN on CodePen.
<!-- <!DOCTYPE html> -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Pomodoro Clock</title>
<!-- my stylesheet comes after Bootstrap css so I can override some of it -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/bootstrap.min.css">
<link href='https://fonts.googleapis.com/css?family=Maven+Pro:400,500,700' rel='stylesheet' type='text/css'>
<!-- Javascript library adds needed browser vendor prefixes -->
<!-- to automatically fix compatibility issues in older browsers -->
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/prefixfree_1.0.7.min.js">
<link rel="stylesheet" href="css/main.css">
</script>
</head>
<body>
<div id="main_container">
<div class="container">
<div class="title row">
<span class="col-xs-1 col-sm-3 col-md-3 col-lg-3"></span>
<div class="text col-xs-10 col-sm-6 col-md-6 col-lg-6">
<h1>Pomodoro Clock</h1>
<h3>
<a href="https://www.freecodecamp.org/harunpehlivan" target="_blank">
a FreeCodeCamp Zipline</a>
</h3>
</div>
<span class="col-xs-1 col-sm-3 col-md-3 col-lg-3"></span>
</div>
</div>
<div class="container">
<div id="clock_container" class="row button-container">
<div id="clock_span" class="col-xs-12 col-sm-12 col-md-4 col-lg-4 col-md-push-4">
<div id="liveclock" class="outer_face ">
<div class="marker oneseven"></div>
<div class="marker twoeight"></div>
<div class="marker fourten"></div>
<div class="marker fiveeleven"></div>
<div class="inner_face">
<div class="hand hour"></div>
<div class="hand minute"></div>
<div class="hand second"></div>
<div id="work" class="hand work"></div>
<div id="break" class="hand break"></div>
</div>
</div>
<div id="controls" class="row button-container">
<span id="ctrl-play" class="btn popup" title="Start your Pomodoro" onclick="start()"><img
src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/PlayHS.png"></span>
<span id="ctrl-stop" class="btn popup" title="Stop your Pomodoro" onclick="stop()"><img
src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/StopHS.png"></span>
<span id="ctrl-repeat" class="btn popup" title="Reset to Default" onclick="reset()"><img
src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/RepeatHS.png"></span>
<span id="ctrl-about" class="btn popup" title="Helpful Information" onclick="popOpenInfoWindow()"><img
src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/Task-Inspector-Suggestion.png"></span>
</div>
</div>
<div id="work_length" class="col-xs-12 col-sm-12 col-md-4 col-lg-4 col-md-pull-3">
<p class="bold">Work Duration:</p>
<span id="btn-work-left" class="btn glyphicon glyphicon-chevron-left" onclick="minusWorkTime()"></span>
<span id="display_work_timer"></span>
<span id="btn-work-right" class="btn glyphicon glyphicon-chevron-right" onclick="plusWorkTime()"></span>
<p>minutes</p>
</div>
<div id="break_length" class="col-xs-12 col-sm-12 col-md-4 col-lg-4 col-md-pull-1">
<p class="bold">Break Duration:</p>
<span id="btn-break-left" class="btn glyphicon glyphicon-chevron-left" onclick="minusBreakTime()"></span>
<span id="display_play_timer"></span>
<span id="btn-break-right" class="btn glyphicon glyphicon-chevron-right" onclick="plusBreakTime()"></span>
<p>minutes</p>
</div>
</div> <!-- clock_container -->
</div> <!-- container-fluid -->
</div> <!-- main container -->
<!-- my javascript file comes after Bootstrap and JQuery js so I can override some of it -->
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/jquery-1.11.3.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/bootstrap.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>