Nomadic cattle rustler and inventor of the electric lasso.
Company Website
Follow me on twitter
Contact me for frontend answers.

React hexagon component

September 06, 2018

I am writing this because I could not find anything adequate in my interweb searches for how to draw a hexagon using a svg polygon

What I wanted to do was create an svg polygon in the guise of a react component. I wanted to supply a size property and the component would magically know how to create the coordinates that can be used for the points attribute of the polygon.

Hexagon Maths

Hexagon Maths

In the figure above, the angles a, b, c, d,e and f are the central angles of a hexagon. The number of central angles of a polygon is always the same as the number of sides.

As you can see above all the central angles of the polygon will always form a complete circle. Hence the central angles will always add up to 360∘. Since a regular polygon has all equal sides, then the central angles of the polygon are equal.

To find the central angles of a polygon:

  1. First identify the number of sides n.
  2. Then divide by 360∘.

The central angle of a hexagon is therefore 60∘

I create coordinates at 0, 60, 120, 180, 240 and 360 and the <polygon /> component will join the vertices to create a hexagon.

I can use the trigonometry functions of cos and sin to get a coordinate or point if I know the central angle of the polygon and the length of each side of the polygon. cosine can give me the x coordinate and sine can give me the y coordinate.

Show me the code

Armed with this knowledge I can now work out the points by just knowing the length of a side and an optional central point object that gives me a starting position to place the polygon.

export const getPoints = (
    hexagonType: HexagonType,
    size: number,
    center: Point
  ): Point[] => {
  return [0, 1, 2, 3, 4, 5].map((n) => {
    const turnHexagon = hexagonType === HexagonType.pointy ? 30 : 0;
    const degrees = 60 _ n - turnHexagon;
    const radians = (Math.PI / 180) _ degrees;

    return new Point({
      x: center.x + size * Math.cos(radians),
      y: center.y + size * Math.sin(radians)
    });
  });
};

The function takes a HexagonType typescript enum as an argument and on line 3, I create a turnHexagon variable that adds an offset (or not) to have the hexagon positioned with a point:

pointy hexagon

or flat

flat hexagon

Line 4 - const degrees = 60 * n - turnHexagon; will give the angle of the next central angle for each coordinate by increasing the angle by 60∘ each time.

Line 5 - const radians = (Math.PI / 180) * degrees; converts degrees into radians. Math.cos and Math.sin expect the argument to be in radians and not degrees. I initially got this wrong.

The code below will work out the x and y coordinates of each of the six points.

return new Point({
  x: center.x + size _ Math.cos(radians),
  y: center.y + size _ Math.sin(radians)
});

@VX

I ended up creating a PR for the excellent VX library which was accepted and my <Polygon /> is now part of the @vx/shape package with a demo here.

Code

Here is a jsfiddle with a plain js version and below is the react component in it’s entirety:

import * as React from 'react';
import { range } from 'lodash';
import { Point } from '../../model/point';
import { degreesToRadians } from '../../util/trigonometry';

export enum HexagonType {
  flat = 'flat',
  pointy = 'pointy'
}

export interface HexagonProps {
  size: number;
  hexagonType?: HexagonType;
  center?: Point;
  className?: string;
}

export const getPoints = (hexagonType: HexagonType, size: number, center: Point): Point[] => {
  return range(0, 6).map((n) => {
    const turnHexagon = hexagonType === HexagonType.pointy ? 30 : 0;
    const degrees = 60 \* n - turnHexagon;
    const radians = degreesToRadians(degrees);

    return new Point({
      x: center.x + size * Math.cos(radians),
      y: center.y + size * Math.sin(radians)
    });
  });
};

export const Hexagon: React.SFC<HexagonProps> = ({
  hexagonType = HexagonType.pointy,
  size = 25,
  center = new Point({ x: 0, y: 0 }),
  className
}) => {
  const points = getPoints(hexagonType, size, center)
    .map((p) => p.toArray())
    .join(' ');

  return <polygon points={points} className={className} />;
};

Paul Cowan

Nomadic cattle rustler and inventor of the electric lasso.
Company Website
Follow me on twitter
Contact me for frontend answers.