react-grid-layout / react-draggable

React draggable component
MIT License
9.04k stars 1.03k forks source link

Collision detection #746

Open stefann01 opened 7 months ago

stefann01 commented 7 months ago

Hi!

Is there also a collision detection inside this library so that I cannot overlap rectangles when I drag them around?

Really cool library btw.

JEKO10 commented 4 months ago

No, the react-draggable library doesn't have built-in collision detection to prevent overlapping rectangles. However, you can achieve collision detection functionality using other methods. Here are two approaches:

  1. Manual Collision Detection with React:

This approach involves writing your React code to check for collisions between draggable elements:

import React, { useRef, useState } from 'react';
import Draggable from 'react-draggable';

const MyDraggable = ({ children, onDrag, ...draggableProps }) => {
  const [position, setPosition] = useState({ x: 0, y: 0 });
  const ref = useRef(null);

  const handleDrag = (event, data) => {
    const otherDraggables = [...]; // Array containing references to other draggable elements

    // Check for collision with other draggables
    const isCollidingWithOthers = otherDraggables.some(other => {
      const rectA = ref.current.getBoundingClientRect();
      const rectB = other.current.getBoundingClientRect(); // Access other draggable's ref

      return (
        rectA.left < rectB.right &&
        rectA.right > rectB.left &&
        rectA.top < rectB.bottom &&
        rectA.bottom > rectB.top
      );
    });

    if (isCollidingWithOthers) {
      // Handle collision here (e.g., prevent movement, snap to grid)
      return;
    }

    // Update draggable position if no collision
    setPosition({ x: data.x, y: data.y });
    onDrag && onDrag(event, data); // Call your custom drag function if needed
  };

  return (
    <Draggable ref={ref} onDrag={handleDrag} {...draggableProps} position={position}>
      {children}
    </Draggable>
  );
};

Usage:

const MyComponent = () => {
  const draggable1Ref = useRef(null);
  const draggable2Ref = useRef(null);
  // ... (other draggable references)

  const handleDrag1 = (event, data) => {
    handleDrag(event, data, draggable1Ref);
  };

  const handleDrag2 = (event, data) => {
    handleDrag(event, data, draggable2Ref);
  };

  // ... (other drag handlers)

  return (
    <div>
      <MyDraggable ref={draggable1Ref} onDrag={handleDrag1}>
        <div style={{ width: 100, height: 100, backgroundColor: 'red' }}>Draggable 1</div>
      </MyDraggable>
      <MyDraggable ref={draggable2Ref} onDrag={handleDrag2}>
        <div style={{ width: 100, height: 100, backgroundColor: 'blue' }}>Draggable 2</div>
      </MyDraggable>
      {/* ... (other draggables) */}
    </div>
  );
};
  1. Third-party Libraries:

Several libraries offer collision detection functionalities that can be integrated with react-draggable. Here are a few options:

-react-dnd: This popular library provides drag-and-drop functionalities, including collision detection and other advanced features.

-react-grid-layout: This library helps manage draggable elements in a grid layout, ensuring they don't overlap. These libraries offer different functionalities and levels of complexity.

Hope this helps :)