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.