Pomodoro clock project

Last we spoke, I was just finishing up the third of four projects required by the Free Code Camp curriculum in the Basic Front End Development section.  The JavaScript calculator I built was by far the most complicated programming I’d done as part of Free Code Camp.  Project #4, the Pomodoro Clock, seemed like a step back, complexity-wise, but was an interesting challenge as I’d not done much with time-based callbacks.

That was almost two weeks ago, about twice the time it took me to build the calculator.  Conceptually, I still don’t think the project was as complicated as the calculator, but there were things with this project that stumped me for days.

FCC Pomodoro Clock - bigger

The first challenge, obviously, was getting the timers to increment…OK, maybe that wasn’t what you’d attack first, but I wanted to make sure my JQuery click event skills were still sharp.  I created a control of sorts,

Rest Time
5
</div>

I had two of these, each with an increment and decrement control, and a value displayed in the middle.  I wanted them side by side, so a <span> tag seemed appropriate, and worked wonderfully.  Of course, I had the usual challenge with vertical centering, which I solved with the <div class=”vert-center”>.   Here’s the CSS, with the “display: table-cell;” being the key bit:

.vert-center {
  display: table-cell;
  vertical-align: middle; 
  ...
}

The clicks were handled with JQuery event handlers, which directly modified the text in the middle span.  The tricky part was that I wanted to use the same event handlers for both “controls” (or sets of elements).  This was solved by adding the class “value” to both middle spans, which had the ids “focus-length” and “rest-length” (this is the one shown above) , which allowed me to target the increment or decrement change to that element.  Here’s the code:

$(".increment-value").click( function () {
  var value = parseInt($(this).siblings(".value").text());
  if (value < 99)
    value++;
  $(this).siblings(".value").text(value.toString());
});

The key bit I had never used before was the “.siblings()” selector, which selects all the siblings, or HTML elements that are contained in the same parent element.  Looking at the HTML snipit above, this would be the <br> tag and the three <span> tags enclosed by the <div class=”vert-center”> tag.  The passed in filter – “.value” – allowed me to select only the element with the “.value” class, and store the freshly modified value inside.

Another minor but new (to me) concept used in these controls were the CSS selectors “:before” and “:after”.  You’ll notice that the HTML above has no text for the up or down arrows used in the increment/decrement controls.  I used font-awesome gliphs for the actual arrows, but instead of adding font-awesome classes to the spans, I applied the characters using the following CSS:

.ui-button {
  font-family: FontAwesome;
  ...
}

.increment-value:before {
  content: "\f0d8";
}

.decrement-value:before {
  content: "\f0d7";
}

I used the ui-button class to apply the FontAwesome font (loaded in a <link> tag in the <head> section of the HTML file) and then applied a specific character  using the “content” property.

The other problem I needed to solve was how to add a “min” suffix to each number without having to parse it out each time I needed to use the value (such as in the above click() handler.)  This was solved similarly, using the “:after” selector:

.value:after {
  content: " min";
}

Of course, the critical bit of logic for any clock is the timer.  I was a bit worried about this, not having any experience with JavaScript timers, but in the end I was able to implement a super-simple timer using setTimer().  I stored the number of seconds, calculated from the value stored in the appropriate HTML element (e.g., the HTML above shows the “rest-length” element, and the default value of the rest timer,) multiplied by 60 so get seconds, in a variable.  Then, I call a function – updateTimeRemaining() – which decrements the time, and then, assuming we’re not paused, schedules another updateTimeRemaining() call with setTimer():

function updateTimeRemaining() {
  if (currentTime >= 0) {
      drawTimer(...);
      currentTime -= intervalInSeconds;
    if (!paused) {
      currentTimeout = setTimeout(updateTimeRemaining, intervalInSeconds * 1000);
    }
  } 
  else {
    playAlarmSound();
    ...
  }
}

Once the timing code was in place and the clock was working, I needed to make some audio and visual enhancements.  Playing audio in JavaScript was pretty simple:

function playAlarmSound() {
var audio = new Audio(focusSound);
audio.play();
}

The variable “focusSound” is just a text string containing a URL to an audio file, but that was by far the biggest challenge of this part of the project – finding  appropriate hosted audio files.  I spent a huge chunk of time looking for usable audio files, finding many I could download and host myself, but none that were available to link to as-is.

Eventually, I gave up and broke “Rule #1: Don’t look at the example project’s code.”  I knew the person creating the example project had found something, as their clock played a sound.  I figured a quick glance at their source would tell me if they had a personal server they were using, or if they’d found a  side hosting audio.

Fortunately for me, it turned out to be the latter.  They were linking to a file from oringz.com, a site which hosts all sorts of free sound files.  I did a quick search, and found a couple of audio clips that I felt were appropriate (I think you’ll wake up and want to get back to work after hearing my rest sound…)

That left me with the minor task of adding a look and feel.

I’ll admit it, I’m not a UI designer.  Fortunately, there are plenty of great UI designers out there to copy from, and that’s what I did with my clock UI.  In this case, I turned to the Apple iPad countdown timer.  I took a screen shot, and used paint.NET to capture the background color, and the red for the clock.  I also decided to copy the basic circular design of the timer.

The critical challenge of this design was getting the timer animation to look good – in my case, a red or green circular line getting shorter as the timer runs down.  In looking for a way to draw that circular line, I was led (via some stackoverflow answers) to the JQuery knob control by Anthony Terrien.

If you click on that link, you’ll see a bunch of circular controls that look almost exactly like my final clock.  What you won’t see, however, is multiple lines of text in any of those controls.  As you can see in my final clock, I wanted to show both the active clock (Focus or Rest), the current clock time, and the next-up clock time.  I looked around for some examples using multiple lines, and while I found some suggestions, nothing really workable turned up.

I resumed my search, eventually finding some code that used the HTML <canvas> element, and the arc() function, to draw a smooth circular line.  I then simply added additional text drawing functions as part of drawing the canvas-based control.  This was a great example of discovering that rolling your own control (or doing the drawing yourself) was a better fit than using someone’s pre-built control.

In the end, I felt pretty good about the clock, and about the other Free Code Camp projects I’d built so far.  Much of what I’d learned didn’t come from Free Code Camp, and other than suggestions for interesting projects, I’d begun to have concerns about whether Free Code Camp was actually helping my learning, or simply getting in the way.  I need to take another look at what resources are available.  It may be time for another course correction.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s