Categories
Visx

Add Radar Charts into Our React App with the Visx Library

Spread the love

Visx is a library that lets us add graphics to our React app easily.

In this article, we’ll look at how to use it to add radar charts into our React app.

Install Required Packages

We have to install a few modules.

To get started, we run:

npm i @visx/group @visx/mock-data @visx/responsive @visx/point @visx/scale @visx/shape

to install the packages.

Radar Chart

To create a radar chart, we write:

import React from "react";
import { Group } from "@visx/group";
import letterFrequency from "@visx/mock-data/lib/mocks/letterFrequency";
import { scaleLinear } from "@visx/scale";
import { Point } from "@visx/point";
import { Line, LineRadial } from "@visx/shape";

const orange = "#ff9933";
const pumpkin = "#f5810c";
const silver = "#d9d9d9";
const background = "#FAF7E9";

const degrees = 360;
const data = letterFrequency.slice(2, 12);

const y = (d) => d.frequency;

const genAngles = (length) =>
  [...new Array(length + 1)].map((_, i) => ({
    angle: i * (degrees / length)
  }));

const genPoints = (length, radius) => {
  const step = (Math.PI * 2) / length;
  return [...new Array(length)].map((_, i) => ({
    x: radius * Math.sin(i * step),
    y: radius * Math.cos(i * step)
  }));
};

function genPolygonPoints(dataArray, scale, getValue) {
  const step = (Math.PI * 2) / dataArray.length;
  const points = new Array(dataArray.length).fill({
    x: 0,
    y: 0
  });
  const pointString = new Array(dataArray.length + 1)
    .fill("")
    .reduce((res, _, i) => {
      if (i > dataArray.length) return res;
      const xVal = scale(getValue(dataArray[i - 1])) * Math.sin(i * step);
      const yVal = scale(getValue(dataArray[i - 1])) * Math.cos(i * step);
      points[i - 1] = { x: xVal, y: yVal };
      res += `${xVal},${yVal} `;
      return res;
    });

  return { points, pointString };
}

const defaultMargin = { top: 40, left: 80, right: 80, bottom: 80 };

function Example({ width, height, levels = 5, margin = defaultMargin }) {
  const xMax = width - margin.left - margin.right;
  const yMax = height - margin.top - margin.bottom;
  const radius = Math.min(xMax, yMax) / 2;

const radialScale = scaleLinear({
    range: [0, Math.PI * 2],
    domain: [degrees, 0]
  });

const yScale = scaleLinear({
    range: [0, radius],
    domain: [0, Math.max(...data.map(y))]
  });

const webs = genAngles(data.length);
  const points = genPoints(data.length, radius);
  const polygonPoints = genPolygonPoints(data, (d) => yScale(d) ?? 0, y);
  const zeroPoint = new Point({ x: 0, y: 0 });

  return width < 10 ? null : (
    <svg width={width} height={height}>
      <rect fill={background} width={width} height={height} rx={14} />
      <Group top={height / 2 - margin.top} left={width / 2}>
        {[...new Array(levels)].map((_, i) => (
          <LineRadial
            key={`web-${i}`}
            data={webs}
            angle={(d) => radialScale(d.angle) ?? 0}
            radius={((i + 1) * radius) / levels}
            fill="none"
            stroke={silver}
            strokeWidth={2}
            strokeOpacity={0.8}
            strokeLinecap="round"
          />
        ))}
        {[...new Array(data.length)].map((_, i) => (
          <Line
            key={`radar-line-${i}`}
            from={zeroPoint}
            to={points[i]}
            stroke={silver}
          />
        ))}
        <polygon
          points={polygonPoints.pointString}
          fill={orange}
          fillOpacity={0.3}
          stroke={orange}
          strokeWidth={1}
        />
        {polygonPoints.points.map((point, i) => (
          <circle
            key={`radar-point-${i}`}
            cx={point.x}
            cy={point.y}
            r={4}
            fill={pumpkin}
          />
        ))}
      </Group>
    </svg>
  );
}

export default function App() {
  return (
    <div className="App">
      <Example width={500} height={300} />
    </div>
  );
}

We define the variables with the colors for the chart as the values.

degrees has the degrees for the radar chart.

data has the data for the chart.

y is a getter to let us get the y-axis values.

genAngles lets us create the angles for the chart and genPoints create the points.

genPolygonPoints generate the points for the radar chart.

Then to create the radar chart, we add the LineRadial compoennt to add the web for the radar chart.

We get the angles from the radialScale function.

The radius is computed from the radius prop.

The line segments for the graph is created with the Line component.

polygon lets us create the polygon fill for the radar chart.

The circle in the polygonPoints.map callback creates the points that are located at the angles.

Conclusion

We can add radar charts easily into our React app with the Visx library.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *