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 curves into our React app
Install Required Packages
We have to install a few modules.
To get started, we run:
npm i @visx/curve @visx/gradient @visx/group @visx/marker @visx/mock-data @visx/responsive @visx/scale @visx/shape
to install the packages.
Create the Curves
We can create the chart by adding the items provided by the modules.
We use the data from the @visx/mock-data
module.
To create the curves, we write:
import React, { useState } from "react";
import { extent, max } from "d3-array";
import * as allCurves from "@visx/curve";
import { Group } from "@visx/group";
import { LinePath } from "@visx/shape";
import { scaleTime, scaleLinear } from "@visx/scale";
import {
MarkerArrow,
MarkerCross,
MarkerX,
MarkerCircle,
MarkerLine
} from "@visx/marker";
import generateDateValue from "@visx/mock-data/lib/generators/genDateValue";
const curveTypes = Object.keys(allCurves);
const lineCount = 3;
const series = new Array(lineCount)
.fill(null)
.map((_) =>
generateDateValue(25).sort((a, b) => a.date.getTime() - b.date.getTime())
);
const allData = series.reduce((rec, d) => rec.concat(d), []);
const getX = (d) => d.date;
const getY = (d) => d.value;
// scales
const xScale = scaleTime({
domain: extent(allData, getX)
});
const yScale = scaleLinear({
domain: [0, max(allData, getY)]
});
function Example({ width, height, showControls = true }) {
const [curveType, setCurveType] = useState("curveNatural");
const [showPoints, setShowPoints] = useState(true);
const svgHeight = showControls ? height - 40 : height;
const lineHeight = svgHeight / lineCount;
xScale.range([0, width - 50]);
yScale.range([lineHeight - 2, 0]);
return (
<div className="visx-curves-demo">
{showControls && (
<>
<label>
Curve type
<select
onChange={(e) => setCurveType(e.target.value)}
value={curveType}
>
{curveTypes.map((curve) => (
<option key={curve} value={curve}>
{curve}
</option>
))}
</select>
</label>
<label>
Show points
<input
type="checkbox"
checked={showPoints}
onChange={() => setShowPoints(!showPoints)}
/>
</label>
<br />
</>
)}
<svg width={width} height={svgHeight}>
<MarkerX
id="marker-x"
stroke="#333"
size={22}
strokeWidth={4}
markerUnits="userSpaceOnUse"
/>
<MarkerCross
id="marker-cross"
stroke="#333"
size={22}
strokeWidth={4}
strokeOpacity={0.6}
markerUnits="userSpaceOnUse"
/>
<MarkerCircle id="marker-circle" fill="#333" size={2} refX={2} />
<MarkerArrow
id="marker-arrow-odd"
stroke="#333"
size={8}
strokeWidth={1}
/>
<MarkerLine id="marker-line" fill="#333" size={16} strokeWidth={1} />
<MarkerArrow id="marker-arrow" fill="#333" refX={2} size={6} />
<rect width={width} height={svgHeight} fill="#efefef" rx={14} ry={14} />
{width > 8 &&
series.map((lineData, i) => {
const even = i % 2 === 0;
let markerStart = even ? "url(#marker-cross)" : "url(#marker-x)";
if (i === 1) markerStart = "url(#marker-line)";
const markerEnd = even
? "url(#marker-arrow)"
: "url(#marker-arrow-odd)";
return (
<Group key={`lines-${i}`} top={i * lineHeight} left={13}>
{showPoints &&
lineData.map((d, j) => (
<circle
key={i + j}
r={3}
cx={xScale(getX(d))}
cy={yScale(getY(d))}
stroke="rgba(33,33,33,0.5)"
fill="transparent"
/>
))}
<LinePath
curve={allCurves[curveType]}
data={lineData}
x={(d) => xScale(getX(d)) ?? 0}
y={(d) => yScale(getY(d)) ?? 0}
stroke="#333"
strokeWidth={even ? 2 : 1}
strokeOpacity={even ? 0.6 : 1}
shapeRendering="geometricPrecision"
markerMid="url(#marker-circle)"
markerStart={markerStart}
markerEnd={markerEnd}
/>
</Group>
);
})}
</svg>
<style jsx>{`
.visx-curves-demo label {
font-size: 12px;
}
`}</style>
</div>
);
}
export default function App() {
return (
<div className="App">
<Example width={500} height={300} />
</div>
);
}
We get the curve types from the @visx/curve
library.
The curveTypes
is generated from the keys of the module object.
The data for the curves are created from the generateDataValue
function from the @visx/mock-data
module.
The getX
and getY
functions are the data accessor functions to get the data for the x and y axes respectively.
xScale
has the x-axis scale.
yScale
has the y-axis scale.
The Example
component has the curves.
We have a dropdown to set the curveType
state.
And we have a checkbox to set the showPoints
state.
We add the markers for the curves with the MarkerX
, MarkerCross
, MarkerCircle
, MarkerLine
and MarkerArrow
components.
Then to add the curves, we add the LinePath
component.
We set the curve
prop to the type of curve we want to render.
data
has the line data.
x
and y
have the x and y values to render respectively.
stroke
and strokeWidth
have the stroke styles.
We set the markers to display in the curve with the markerMid
, markerStart
and markerEnd
props.
markerMid
has the markers in the middle of the curve.
And the others are displayed at the ends.
Conclusion
We can add curves easily into our React app with the Visx library.