loading...
Cover image for Scripted natural motion with react-beautiful-dnd

Scripted natural motion with react-beautiful-dnd

raathigesh profile image Raathi ・3 min read

React-beautiful-dnd v12 ships with a Sensor API that allows us to control the drag and drop actions programmatically. This is going to open up a wide range of possibilities. We can programmatically move a draggable using either a snap dragging or a fluid dragging.

This blog post goes into the details of how to perform good looking fluid drags using the new fluidLift method.

The fluidLift method would allow us to create beautiful scripted experiences without user interaction. For example, a trip planner app, as shown below, could provide an interactive onboarding experience using the new fluidLift method by showing the user how to plan a trip.

Alt Text

Take full control of draggable using fluid dragging

The fluidLift method allows us to freely move a draggable to a new position by providing a coordinate.

Let's say if we want to move a draggable from it's initial position to a new position with the coordinate 400, 500, we could call the .move() method with { x: 400, y: 500 } as the argument as shown below.

 function useMyCoolSensor(api) {
    const startDrag = function start() {
      const preDrag = api.tryGetLock("my-draggable-item");
      if (!preDrag) {
        return;
      }

      const drag = preDrag.fluidLift({ x: 0, y: 0 });
      const end = { x: 400, y: 500 };
      drag.move(end);
      drag.drop()
    };
  }

This will make our draggable move to the new position. In the illustration below, you might have noticed that the box jumps from its initial position to its target position.

Alt Text

Making the motion natural

In order to achieve a more natural motion, we have to tell react-beautiful-dnd to move the draggable element coordinate by coordinate through time towards the target position.

So instead of calling the .move() just once, we are going to call it multiple times with multiple coordinates which lies between the start coordinate and the end coordinate so the drag motion would be more natural.

To create the coordinates between the start and the end coordinates, we are going to use a helper library called tween-functions. The API of the tween-functions library goes as below.

tweenFunction.tweenName(currentTime, beginValue, endValue, totalDuration)

Let's go ahead and generate 20 points between the start position and the end position and then call the .move() method with our new set of coordinates in requestAnimationFrame.

import * as tweenFunctions from "tween-functions";

function useMyCoolSensor(api) {
    const startDrag = function start() {
      const preDrag = api.tryGetLock("my-draggable-item");
      if (!preDrag) {
        return;
      }

      const start = { x: 0, y: 0 };
      const end= { x: 400, y: 500 };
      const drag = preDrag.fluidLift(start );

      const points = [];

      // we want to generate 20 points between the start and the end
      const numberOfPoints = 20;

      for (let i = 0; i < numberOfPoints ; i++) {
        points.push({
          x: tweenFunctions.easeOutCirc(i, start.x, end.x, numberOfPoints),
          y: tweenFunctions.easeOutCirc(i, start.y, end.y, numberOfPoints)
        });
      }

      moveStepByStep(drag, points);
    };
  }

function moveStepByStep(drag, values) {
  requestAnimationFrame(() => {
    const newPosition = values.shift();
    drag.move(newPosition);

    if (values.length) {
      moveStepByStep(drag, values);
    } else {
      drag.drop();
    }
  });
}

Alt Text

That looks much better.

Here is the full codesandbox example.

The new Sensor API unlocks a vast amount of possibilities. Experiment with it and go build amazing things.

Discussion

pic
Editor guide