5

I am working on a react dnd project for which I am following the react-dnd documentation. Everything is working properly but I am not able to scroll while dragging.

I need a scroll bar when I am dragging an item and have reached the last droptable source and then it will auto scroll and allow me to place the item over there.

If anyone has any idea how to do this then please share with me. I will be very thankful.

Ben Hare
  • 4,365
  • 5
  • 27
  • 44
dom
  • 1,086
  • 11
  • 24

3 Answers3

3

React Dnd provides DragLayer Component which can be helpful for you.

You can add DragLayer inside your scollable component and call callback from when your scrolling condition satisfied.

You can also add some div on which you can listen onMouseOver event inside custom DragLayer and throw callback to set scroll of parent/scrollable component.

@dragLayer( monitor => ({
   isDragging   : monitor.isDragging(),
}) )
class DragLayer extends Component {
  render() {
   if(!this.props.isDragging) {
     return null;
   }
   return <div onMouseOver={this.props.onScrollOver}></div>
  }

}

class ScrollableContainer extends Component {
....


  _doScroll(event) { 
    const scrollTaget = this._scrollTarget;
    scrollTarget.scrollTop++; //Or You can add animations here
  }

  render() {

   ...return <div style={{overflow:'auto'}}>
      <DragLayer onScrollOver={this._doScroll}/> 
     </div>;
  }
 }
anuj kosambi
  • 194
  • 1
  • 6
1

React Dnd has provided an example for scrolling a sortable list, you can find that in the below link: React Dnd with auto scroll

You can use the following code in the hover section in useDrop:

hover(item: DragItem, monitor: DropTargetMonitor) {
  if (!ref.current) {
    return
  }
  const dragIndex = item.index
  const hoverIndex = index

  // Don't replace items with themselves
  if (dragIndex === hoverIndex) {
    return
  }

  // Determine rectangle on screen
  const hoverBoundingRect = ref.current?.getBoundingClientRect()

  // Get vertical middle
  const hoverMiddleY =
    (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2

  // Determine mouse position
  const clientOffset = monitor.getClientOffset()

  // Get pixels to the top
  const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top

  // Only perform the move when the mouse has crossed half of the items height
  // When dragging downwards, only move when the cursor is below 50%
  // When dragging upwards, only move when the cursor is above 50%

  // Dragging downwards
  if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
    return
  }

  // Dragging upwards
  if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
    return
  }

  // Time to actually perform the action
  moveCard(dragIndex, hoverIndex)

  // Note: we're mutating the monitor item here!
  // Generally it's better to avoid mutations,
  // but it's good here for the sake of performance
  // to avoid expensive index searches.
  item.index = hoverIndex
},
Mahsa
  • 123
  • 1
  • 11
0

I have tried some ways to implement this, hope they are helpful:

  1. react-dnd-scrollzone.

This package can make a container scrolling when you drag the draggable component to the edge of the container. However, it has to be applied to a warpped container, which is not the purpose of my object, so I get rid of it.

  1. Implementing the scroll behavior in the rowSource
const rowSource = {
  isDragging(props, monitor) {
    // determine mouse position
    const clientOffset = monitor.getClientOffset();

    if (clientOffset) {
      // you can implement your own scroll behavior here

      // scroll up if dragging to an upper area
      const moveThreshold = Math.max(120, window.innerHeight / 4);

      if (clientOffset.y < moveThreshold && !window.isScrolling) {
        // scroll up
        window.isScrolling = true;

        $("html, body").animate(
          {
            scrollTop: window.pageYOffset - moveThreshold,
          },
          {
            duration: 300,
            complete: () => {
              window.isScrolling = false;
            },
          }
        );
      }
    }
  },
};

@DragSource("YOUR_DRAG_TYPE", rowSource, (connect, monitor) => ({
  connectDragSource: connect.dragSource(),
}))
class DraggableItem extends Component {
// your component
}
Kaiwen Luo
  • 370
  • 4
  • 10