Categories
Visx

Add Drag and Drop Features 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 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.

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 *