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 with segments that have their own styles into our React app
Install Required Packages
We have to install a few modules.
To get started, we run:
npm i @visx/drag @visx/gradient @visx/responsive @visx/scale
to install the packages.
Add Drag and Drop Feature
We add drag and drop by writing the following code:
import React, { useMemo, useState, useEffect } from "react";
import { scaleOrdinal } from "@visx/scale";
import { LinearGradient } from "@visx/gradient";
import { Drag, raise } from "@visx/drag";
const colors = [
"#025aac",
"#02cff9",
"#02efff",
"#03aeed",
"#0384d7",
"#edfdff",
"#ab31ff",
"#5924d7"
];
const generateCircles = ({ width, height }) =>
new Array(width < 360 ? 40 : 185).fill(1).map((d, i) => {
const radius = 25 - Math.random() * 20;
return {
id: `${i}`,
radius,
x: Math.round(Math.random() * (width - radius * 2) + radius),
y: Math.round(Math.random() * (height - radius * 2) + radius)
};
});
function Example({ width, height }) {
const [draggingItems, setDraggingItems] = useState([]);
useEffect(() => {
if (width > 10 && height > 10)
setDraggingItems(generateCircles({ width, height }));
}, [width, height]);
const colorScale = useMemo(
() =>
scaleOrdinal({
range: colors,
domain: draggingItems.map((d) => d.id)
}),
[width, height]
);
if (draggingItems.length === 0 || width < 10) return null;
return (
<div className="Drag" style={{ touchAction: "none" }}>
<svg width={width} height={height}>
<LinearGradient id="stroke" from="#ff00a5" to="#ffc500" />
<rect fill="#c4c3cb" width={width} height={height} rx={14} />
{draggingItems.map((d, i) => (
<Drag
key={`drag-${d.id}`}
width={width}
height={height}
x={d.x}
y={d.y}
onDragStart={() => {
setDraggingItems(raise(draggingItems, i));
}}
>
{({ dragStart, dragEnd, dragMove, isDragging, x, y, dx, dy }) => (
<circle
key={`dot-${d.id}`}
cx={x}
cy={y}
r={isDragging ? d.radius + 4 : d.radius}
fill={isDragging ? "url(#stroke)" : colorScale(d.id)}
transform={`translate(${dx}, ${dy})`}
fillOpacity={0.9}
stroke={isDragging ? "white" : "transparent"}
strokeWidth={2}
onMouseMove={dragMove}
onMouseUp={dragEnd}
onMouseDown={dragStart}
onTouchStart={dragStart}
onTouchMove={dragMove}
onTouchEnd={dragEnd}
/>
)}
</Drag>
))}
</svg>
<style jsx>{`
.Drag {
display: flex;
flex-direction: column;
user-select: none;
}
svg {
margin: 1rem 0;
}
.deets {
display: flex;
flex-direction: row;
font-size: 12px;
}
.deets > div {
margin: 0.25rem;
}
`}</style>
</div>
);
}
export default function App() {
return (
<div className="App">
<Example width={500} height={300} />
</div>
);
}
We have the generateCircles
function to return an array of objects with id
, radius
, and x
and y
properties.
id
is the unique ID for each circle.
And the other properties are used to render circles on the page.
In the Example
component, we keep track of the items being tracked with the draggingItems
state.
We watch the width and height and add the circles in the useEffect
hook callback.
The colorScale
state lets us compute the scale for the colors according to the colors
array we created earlier.
In the return
statement, we have the Drag
component, which is the container for holding draggable items.
Then we render the draggable items with the render prop in the Drag
component.
It renders the circles
in the draggingItems
array.
We pass in the drag event handlers from the object parameter as props of the circle
to make them draggable.
Their positions will be updated with those event handler functions.
Finally, we have the styles in the style
tag to change the styles for the container.
Now we should have circles on the screen that can be dragged around the box.
Conclusion
We can add drag and drop features into our React app with the Visx library.