All Posts

Drawing SVG clocks in React Native

In this article, I’m going to look at how to draw a nice-looking analog clock face with by using

There’s not that much complex geometry stuff, so we are going to implement those ourselves, although I think libraries such as D3 might also contain these.

Getting started

Let’s start by initing a new project. You could very well do this with Expo, but I prefer to use the ejected version of so React Native, so we are going to use the react-native-cli and the TypeScript example project to get started:

npx react-native init helloClock --template react-native-template-typescript

after that, let’s install the only external library, we need: react-native-svg.

npm install react-native-svg

Then we need to navigate to ios folder and install required pods:

cd ios & pod install cd -

Folder structure

I’m going to structure the project in the following way:

- index.js
- App.tsx

/ Components
- Clock # The clock component itself
- Hand # Clock hour, minute and second hand
- Ticks # Minute and hour tick component

/ Helpers
- Geometry # Polar to coordinate conversion
- Time # Time manipulation
- Hooks # useInterval hook

Polar and cartesian coordinates

Now to the bread and butter of this article so how to convert time to coordinates on SVG.

We can think of clock times in degrees, i.e., 12 am and 12 pm clock being the same as 0° and 6 pm and 6 am being 180°. We could, of course, use radians as well, but for me, at least degrees feel more familiar. A coordinate system which uses angle and reference point to determine a point on a plane is Polar coordinate system.

Converting time to Polar coordinate systems is relatively simple. Let’s say we, for example, want to determine the angle of the minute hand on a clock in degrees when we know the number of minutes to be 30. If one full revolution is 60 minutes and one complete revolution is 360°, then dividing 30 minutes with 60 and multiplying that with 360 gives the same number of minutes in degrees, which is 180. Let’s implement that with code into the time file:

Converting time to Polar coordinate systems is not enough by itself as that is not the coordinate system that

export function polarToCartesian(
  centerX: number,
  centerY: number,
  radius: number,
  angleInDegrees: number
) {
  const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0;

  return {
    x: centerX + radius * Math.cos(angleInRadians),
    y: centerY + radius * Math.sin(angleInRadians)
  };
}

The clock component

Let’s start the UI stuff by cleaning up the App.tsx file so that it only has a centered ScrollView, StatusBar, SafeAreView the <Clock>-component:

import React from "react";
import { SafeAreaView, StyleSheet, ScrollView, StatusBar } from "react-native";

import Clock from "./components/Clock";

const App = () => {
  return (
    <>
      <StatusBar barStyle="light-content" />
      <SafeAreaView style={{ flex: 1, backgroundColor: "black" }}>
        <ScrollView
          centerContent={true}
          contentInsetAdjustmentBehavior="automatic"
          style={styles.scrollView}
        >
          <Clock />
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

const styles = StyleSheet.create({
  scrollView: { flex: 1, backgroundColor: "black" }
});

export default App;

Let’s not save the file just yet, but instead, start working on the Clock-component. Import Dimensions from react-native and Svg-component from react-native-SVG and make the Clock return a square SVG with the side of the squares being the same as the width of the mobile phones screen by using the Dimensions helper

import React from "react";
import Svg from "react-native-svg";
import { Dimensions } from "react-native";

const { width } = Dimensions.get("window");

const Clock = () => {
  return <Svg height={width} width={width}></Svg>;
};

export default Clock;

Now when we save, nothing should appear on the screen. This is because SVG itself has no visible parts. Let’s continue by adding the ClockTicks to communicate the minutes and hours. Create a new file ClockTicks

import React from "react";
import { G, Line, Text } from "react-native-svg";
import { polarToCartesian } from "../Helpers/Geometry";

interface Props {
  radius: number;
  center: number;
  minutes: number;
  hours: number;
}

const ClockTicks = (props: Props) => {
  return (
    <G>
      {minuteSticks}
      {hourSticks}
    </G>
  );
};

export default ClockTicks;

Making the clock tick

export function to12hClock(hour: number) {
  return hour > 12 ? hour - 12 : hour;
}

export const getTime = () => {
  const date = new Date();
  const hours = (to12hClock(date.getHours()) / 12) * 360;
  const minutes = (date.getMinutes() / 60) * 360;
  const seconds = (date.getSeconds() / 60) * 360;
  return { hours, minutes, seconds };
};

Let’s go over what the other functions do. The to12hClock will help us in converting time