Clock
Tags: react, javascript, sideprojects, showdev
Published: 2019-11-03 23:52:49

---
title: Clock
published: true
description: Clocks, clocks everywhere
cover_image: https://thepracticaldev.s3.amazonaws.com/i/snn1g50t5tyvs0v4dtez.png
tags: #react #javascript #sideproject #showdev
---


**TL;DR** Like clocks? I built a clock made of clocks, click below to play with it.

<a href="https://blog.barnettjones.com/clock">
   ![Clock Gif](https://blog.barnettjones.com/public/2019-11-03/clock-demo.gif)
</a>

Or read on for a more in depth look at building clocks out of clocks (with some React).

## Inspiration from strange places

Have you something like this before?

{% instagram BXgLumoBYxg %}

Me too, it's cool huh! I really enjoy the way the time seems to gradually appear and take shape.

Actually, the more I looked at it the more I appreciated the way it was put together, they are not individual clocks in the traditional sense as one arm is not simply following the other. Both arms of the clock are moving freely allowing for the various interesting shapes and movements and, of course, the time.

I bet that wouldn't be too difficult to put together, a RaspberryPi to control the "clocks" with a mechanism to specify an angle for the first and second hands... 

   ![Big Think](https://media.giphy.com/media/3o7TKF7iUJ0VgP9Kpi/giphy.gif)

## Creativity intensifies

Ok, so I don't have the motors to build the physical clocks and I'm not sure what I need to buy or how to wire them into a RaspberryPi. However, what I can do to prototype the idea is build a web app.

The quickest way to get started is to use `create-react-app`, this provides the basic setup for a React app.

The first thing I wanted to do was to create a simple clock, requirements were simple; two hands that can move independently of each other and a face. Throwing together some `div`'s, a bit of CSS and voila, I had the makings of a clock, I can specify the angle in degrees, of each hand using the a CSS transform `rotate` and there's a white face. 

<img width="150px" src="https://blog.barnettjones.com/public/2019-11-03/clock-hands.png" alt="An image of the first clock with its arms at odd angles" title="A clock">

## Making things move

From here I wanted to see what the best way to animating things could be. I spent a bit of time looking into the various ways I could animate components in React. Then I thought, nah, why not just see what I can I achieve without a library, surely I should be able to prototype something just using React and a bit of CSS knowhow.

Using `create-react-app` meant that I get a modern version of React out of the box, which means hooks! I've been looking for an excuse to try out hooks and this seemed a good a time as any to try.

I imagined a basic rendering loop like this:

1. inital state sets start / end positions
2. render clock hands at initial position
3. `setTimeout` or `requestAnimationFrame` to increment and set new position
4. render clock hands at new position
5. repeat

Keeping the hand positions in state meant I could "animate" the hands by updating the state, incrementally, and causing a re-render which would update the hands to their new position. 

```jsx
const [angle, setAngle] = useState({
   hour: getRandomStartingAngle(), 
   minute: getRandomStartingAngle()
});
```

In the new world of React hooks there's a hook perfect for the job of triggering the increment: `useEffect` which, amongst other things, is run after every render (for more details check out the docs).

To increment I needed to create an effect with would trigger at a reasonable rate, for this I used `requestAnimationFrame` which is a suitable API to schedule an update on as it's usually called 60 times per second (generally considered the threshold for smooth animation).

```jsx
useEffect(()=> {
   requestAnimationFrame(()=>{
      const { hour, minute } = angle;
      setAngle({
         hour: hour + 1, 
         minute: minute + 1
      });
   });
}, [angle]);
```

Putting it all together and I had a clock that animated around and around, and around, and around, and never stop. 

<img width="150px" src="https://blog.barnettjones.com/public/2019-11-03/clock-moving.gif" alt="A gif of the first clock with its arms moving around" title="A clock">

It seemed to work pretty well. However, I made a couple of mistakes which won't become apparent until I start trying to create numbers from the clocks.

## Drawing numbers, with clocks

Next was to put a bunch of these little clocks onto the screen and see how they animate, using a small bit of `flexbox` to define rows / columns and create 2x3 grids for a single number. 

<img width="150px" src="https://blog.barnettjones.com/public/2019-11-03/clock-static-2.png"    alt="2x3 grid of little clocks with their hands at random positions"    title="Can you tell what it is yet?">

So it's starting to look a lot more like it could resemble a number. In order to animate to the number I needed to work out all the various positions that could go into a clock number and then tell the smaller clocks to animate to those positions.

The approach to drawing a number was to pass a `targetAngle` to each of the smaller clocks. The basic idea was that for a given target angle the clock would continue increment the position of the hands until they'd reached it, then stop.

```jsx
function getIncrementValue(angle, targetAngle) {
   if(angle === targetAngle){
      return angle;
   } else { 
      return resetAngle(angle + 1);
   }
}
```

Incremental by 1 each time means the target angle would eventually be achieved, however the first mistake I made in the sub clock logic rears its head. 

As the hands increment around they can reach an angle above `360deg` which breaks for situations where the hand has to travel around the whole clock to reach the target angle. This would mean some of the sub clocks would stop at the right place but others would continue rotating, an awkward bug.

To solve the endless rotation bug I added a `resetAngle` function which keeps the numbers between `0 < 359` allowing the target angle to always be reached.

Next was the job of actually figuring out these angles. The approach initially was to write, by hand, each angle, for each number, for each clock in the 2x3 grid... I quickly grew tired of this. Instead it's easier to specify a a number of set positions which are the building blocks of the number. 

```jsx
const createAngleSet = (hour, minute) => ({hour, minute});
const bothLeft = createAngleSet(270, 90);
const bothRight = createAngleSet(90, 270);
const bothTop = createAngleSet(0, 180);
const bothBottom = createAngleSet(180, 0);
const topAndBottom = createAngleSet(0, 0);
const rightAndLeft = createAngleSet(90, 90);
const topLeftCorner = createAngleSet(90, 0);
const topRightCorner = createAngleSet(270, 0);
const bottomLeftCorner = createAngleSet(0, 270);
const bottomRightCorner = createAngleSet(0, 90);
const emptySpace = createAngleSet(225, 45);
```

Above is the list of all the positions needed to "draw" the numbers 0-9 and they're used in a number config that looks something like this:
```jsx
TWO: {
  a1: { ...bothRight },
  a2: { ...topLeftCorner },
  a3: { ...bottomLeftCorner },
  b1: { ...topRightCorner },
  b2: { ...bottomRightCorner },
  b3: { ...bothLeft }
}
```

The result of all this work was the realisation of the numbers. The effect was captured almost exactly as I wanted it, with the number appearing out of the randomness of the single clock faces.

<img width="150px" src="https://blog.barnettjones.com/public/2019-11-03/clock-number-2.gif" alt="2x3 grid of little clocks with their hands at random positions moving to the positions of the number 2" title="Can you tell what it is yet? It's a TWO!">

The full [NumberGrid](https://blog.barnettjones.com/clock#numbergrid) is available for preview and illustrates the whole number set that is used in building the clock. 

## Animations, animations, animations

Earlier I mentioned I had made a mistake when creating the mini-clock, did you catch it?

Well, my first go with `useEffect` was more on feeling than careful study of the documentation. As a result when I first attempted to draw the numbers 0-9, at the same time, there was pretty terrible performance.

Turns out `useEffect` is expected to be triggered and then torn down, as a result it's supposed to provide a `cleanup` function to do any bits of cleanup that are needed if an in progress effect needs to be cancelled. This caused a subtle issue as everything seems to animate smoothly however it slowed way down as I scaled up from the 1 mini-clock to the 54 that I needed in order to display the full 0-9 numbers. 

```jsx
useEffect(()=> {
   const increment = requestAnimationFrame(()=> {
      const { hour, minute } = angle;
      const { hour: targetHour, minute: targetMinute } = targetAngle;
      setAngle({
         hour: getIncrementValue(hour, targetHour, speed), 
         minute: getIncrementValue(minute, targetMinute, speed)
      });
  }
  return () => cancelAnimationFrame(increment);
}, [angle, targetAngle, speed]);
```

I corrected this within my effect with `cancelAnimationFrame` and added a speed value, via `useContext` to give me some control over the mini-clock animations (necessary for building a stopwatch).

## Clock

I now have all the pieces to build the clock. Using the `Date` object and updating the target time every time the hours or seconds changed. The `DigitalClock` would then work out the individual parts of the time string and pass them to the `ClockNumbers` which would, in turn, pass the individual parts to each mini clock.

I am so happy with the result 🕑🕤🕜😬

Thanks for reading and check out the clock below 👇
<a href="https://blog.barnettjones.com/clock">
   ![Clock Gif](https://blog.barnettjones.com/public/2019-11-03/clock-demo.gif)
</a>


> First appeared on [my blog](https://blog.barnettjones.com), published 3rd November 2019