Stopwatch Widget - Full Build Description

Note: I am not a software developer, I am a new user to custom widgets too, there are certainly opportunities to improve this widget. Feel free to download and play with this widget, but use it at your own risk-

Hey All,

Just kicking off this category with a widget I’ve wanted for years. Threw it together this morning in about an hour, so its a little quick and dirty, but it is functional. (feel free to download my widget below, and import it into your instance)

The goal was a stopwatch widget where users could start, stop, reset a running timer, and access the value of that stopwatch.

You can see, there is a ton of opportunity to make it prettier, but its a start. I will walk you through how I approached making this widget.

My usual process is:

  1. Setup dummy HTML
  2. Format CSS
  3. Write Javascript to make it dynamic

So let’s go through those steps!

Setup Dummy HTML
When thinking about my HTML, I know I basically want 3 rows, the top being the title above the measurement, the middle being the value, and the bottom row having all my buttons.

I will match this in my HTML. As a default, I always use a body tag around all of my html, and a div with id = container to contain all of my elements, neither of these is strictly required.

You can see, I have 3 div’s, each with the class row (having a class will help with formatting later).

The first two divs are very simple, just some text. The third div contains all of our buttons, each has a type, and an Id, this will help is in both CSS and JS to find each element

<body>
    <div id='container'>
        <div id='label' class='row'>
            Stopwatch
        </div>
        <div id='value' class = 'row'>
            0.00
        </div>
        <div id='buttons' class = 'row'>
            <button type="button" id="start"> Start</button>
            <button type="button" id="stop"> Stop</button>
            <button type="button" id="reset"> Reset</button>
        </div>
    </div>
</body>

Sweet, HTML done - Now CSS

I have found the CSS side to be the trickiest part of custom widgets thus far, its just tricky. Lots of trial and error (and google searching).

Below you can see the CSS I used for this widget-

  • For the body type, I set the background to transparent, this will make it so we can see the rest of our application behind our widget.
  • For the container id, I set the display type to grid, this will allow us to have multiple elements on the same line within this element (which is where all our content is). I find display types the most confusing part of CSS
  • For the value field (check out the html, that the stopwatch value) I set the text size to 50% of the viewport height, which effectively is our widget height. I also set the font and set it to weight 700, which is semi-bold. 100-900 is the range for most fonts (must be a multiple of 100, 100/200/300, etc)
  • I follow largely the same process for the title element and the buttons, font size, font, etc.
body{
    background: transparent;
}
#container{
    display: grid;
    
}
#value{
    font-size: 50vh;
    font-family: Arial;
    font-weight: 700;
}
#label{
    font-size: 15vh;
    font-family: Arial;
}
button{
    font-size: 15vh;
}

BOOM, CSS done, now onto the fun stuff

  • First, I declare 2 variables. elapsedTime will be the variable to track the time on our timer. The loop variable will be used for the continuous loop. If I declared this within one of our functions, I wouldn’t be able to stop our loop from any other function.
let elapsedTime = 0;
let loop;
  • Next, I add event listeners to each of our buttons, and assign what functions they should call. Event listeners do something when a user interacts with that element, so in this case I am doing something on a user click. I use Jquery here for my element selectors, because I find it a little more readable, but any of these could have been replace with: document.getElementById(“start”).addEventListener(‘click’,function() {start()}
$("#start").click(function() {start()});
$("#stop").click(function() {stop()});
$("#reset").click(function() {reset()});
  • From here, I need to make each of the functions by buttons are calling. First, Lets do the start function, its by far the most complicated.
  • First, I clear any intervals running in our loop variable (that we declared at the top). This is basically looking to see if the loop is already running, and if it is, it stops that loop. This catches a case where a user clicks start again while the stopwatch is already running (which causes tons of odd behavior).
  • Next, I declare how often the loop will run to update the stopwatch, I set it to 75 miliseconds, which seems to be a sweetspot when it comes to our stopwatch updating quickly.
  • I then set my interval function, all of this code will run every 75 miliseconds. It takes the elapsed time and adds 75 milliseconds. I then set the html in the #value element to our elapsed time. Finally, I use the setValue function to pass the current value back to our “Current Time” prop, this will make it accessable in our app.
function start(){
    clearInterval(loop)
    let loopLen = 75;
    loop = setInterval(function() {
        elapsedTime = round(elapsedTime + (loopLen/1000))
        console.log(elapsedTime);
        $("#value").html(elapsedTime);
        setValue('Current Time',elapsedTime);
    },loopLen)
    
}
  • Second, lets make the stop function. This guy is way easier. All it does is stop our loop.
function stop(){
    clearInterval(loop)
}
  • Finally, lets make the reset function. This sets the html of our #value item to zero, and sets the elapsed time to 0.
function reset(){
    $("#value").html(0)
    elapsedTime = 0
}

So if we put all of that together, we get our final JS!

let elapsedTime = 0;
let loop;

$("#start").click(function() {start()});
$("#stop").click(function() {stop()});
$("#reset").click(function() {reset()});
function start(){
    clearInterval(loop)
    let loopLen = 75;
    loop = setInterval(function() {
        elapsedTime = round(elapsedTime + (loopLen/1000))
        console.log(elapsedTime);
        $("#value").html(elapsedTime);
        setValue('Current Time',elapsedTime);
    },loopLen)
    
}
function stop(){
    clearInterval(loop)
}
function reset(){
    startTime = null;
    $("#value").html(0)
    elapsedTime = 0
}
function round(num){
    return Math.round(num * 100) / 100;
}

I did throw together a quick rounding function too, it just rounds the time to 2 decimal places.

Below is the attached finished widget, feel free to import it into your instance and play with it, edit it, make it better!

Pete
customWidget-Stopwatch (3).json (1.8 KB)