Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dragging and sorting in both directions? #593

Closed
jr69 opened this issue Dec 13, 2016 · 8 comments
Closed

Dragging and sorting in both directions? #593

jr69 opened this issue Dec 13, 2016 · 8 comments
Labels

Comments

@jr69
Copy link

jr69 commented Dec 13, 2016

I've looked at the example sortable list and have managed to make it work horizontal, by having the divs display in inline-block, and then changing the "Draggable-XXX" file's cardTarget, hover() method, to have X variables instead of Y.

Is there a way to somehow make react-dnd detect both direction dragging? I am currently trying putting this:

// Dragging downwards if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { return; } // Dragging upwards if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { return; } // Dragging left if (dragIndex < hoverIndex && hoverClientX < hoverMiddleX) { return; } // Dragging right if (dragIndex > hoverIndex && hoverClientX > hoverMiddleX) { return; }

but to no avail, the dragging is really buggy, sometimes it won't even swap the elements, and I have to move the mouse around like crazy to get some registration/feedback

@OliverJAsh
Copy link
Contributor

@juampick
Copy link

juampick commented Jun 5, 2017

What we did with our team is the following and it's working ok: (based on @OliverJAsh and the original, done some tweaks)

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

    // Get horizontal middle
    const hoverMiddleX = (hoverBoundingRect.right - hoverBoundingRect.left) / 2;

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

    // Get pixels to the top
    const hoverClientY = clientOffset.y - hoverBoundingRect.top;

    // Get pixels to the left
    const hoverClientX = clientOffset.x - hoverBoundingRect.left;

    const upwards = dragIndex > hoverIndex && hoverClientY > hoverMiddleY;
    const downwards = dragIndex < hoverIndex && hoverClientY < hoverMiddleY;
    const leftwards = dragIndex > hoverIndex && hoverClientX > hoverMiddleX;
    const rightwards = dragIndex < hoverIndex && hoverClientX < hoverMiddleX;

    if (upwards && (leftwards || rightwards)){
      return;
    }

    if (downwards && (leftwards || rightwards)){
      return;
    }

Thanks to all!

Juan

@anztrax
Copy link

anztrax commented Oct 9, 2017

thanks @juampick , @OliverJAsh 👍

@Av1shay
Copy link

Av1shay commented May 4, 2018

I've managed to make it work as expected, inspired by @OliverJAsh's commit:

// get hovered image vertical middle position
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

// get hovered image horizontal middle position
const hoverMiddleX = (hoverBoundingRect.right - hoverBoundingRect.left) / 2;

// determine mouse position
const clientOffset = monitor.getClientOffset();

// get pixels to the top
const hoverClientY = clientOffset.y - hoverBoundingRect.top;

// get pixels to the left
const hoverClientX = clientOffset.x - hoverBoundingRect.left;

// only perform the move when the mouse has crossed half of the items height/width
// are we dragging right or left?
const dragRight = dragIndex === (hoverIndex - 1);
const dragLeft = dragIndex === (hoverIndex + 1);

// are we dragging up or down?
const dragUp = dragBoundingRect.top > hoverBoundingRect.top;
const dragDown = dragBoundingRect.bottom < hoverBoundingRect.bottom;

if ( dragRight && dragIndex < hoverIndex && hoverClientX < hoverMiddleX ) {
  return;
}

if ( dragLeft && dragIndex > hoverIndex && hoverClientX > hoverMiddleX ) {
  return;
}

if ( dragUp && dragIndex > hoverIndex && hoverClientY > hoverMiddleY ) {
  return;
}

if ( dragDown && dragIndex < hoverIndex && hoverClientY < hoverMiddleY ) {
  return;
}

@tizzle
Copy link

tizzle commented Jun 5, 2018

@Av1shay,

thanks for your code, can you maybe explain where you get the dragBoundingRect from?

Cheers

@Av1shay
Copy link

Av1shay commented Jun 6, 2018

@tizzle
Sure, this is the element currently being dragged:

const dragElement = document.getElementById(monitor.getItem().elementID);
const dragBoundingRect = dragElement.getBoundingClientRect();

You need to pass in beginDrag the dragged element id:

beginDrag(props) {
    return {
      elementID: props.elementID
    };
  }

@stale
Copy link

stale bot commented Jul 6, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jul 6, 2019
@stale stale bot closed this as completed Jul 13, 2019
@getanwar
Copy link

I've managed to make it work as expected, inspired by @OliverJAsh's commit:

// get hovered image vertical middle position
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

// get hovered image horizontal middle position
const hoverMiddleX = (hoverBoundingRect.right - hoverBoundingRect.left) / 2;

// determine mouse position
const clientOffset = monitor.getClientOffset();

// get pixels to the top
const hoverClientY = clientOffset.y - hoverBoundingRect.top;

// get pixels to the left
const hoverClientX = clientOffset.x - hoverBoundingRect.left;

// only perform the move when the mouse has crossed half of the items height/width
// are we dragging right or left?
const dragRight = dragIndex === (hoverIndex - 1);
const dragLeft = dragIndex === (hoverIndex + 1);

// are we dragging up or down?
const dragUp = dragBoundingRect.top > hoverBoundingRect.top;
const dragDown = dragBoundingRect.bottom < hoverBoundingRect.bottom;

if ( dragRight && dragIndex < hoverIndex && hoverClientX < hoverMiddleX ) {
  return;
}

if ( dragLeft && dragIndex > hoverIndex && hoverClientX > hoverMiddleX ) {
  return;
}

if ( dragUp && dragIndex > hoverIndex && hoverClientY > hoverMiddleY ) {
  return;
}

if ( dragDown && dragIndex < hoverIndex && hoverClientY < hoverMiddleY ) {
  return;
}

This solution helped me a lot. You can drag and drop any direction without any hassle.

Also, to get dragBoundingRect directly in hover method without accessing the DOM you can return it from beginDrag method.

beginDrag(props, monitor, component) {
    // `getNode` comes from `useImperativeHandle` suggested by ReactDnD
    const node = component.getNode(); 
    const dragBoundingRect = node.getBoundingClientRect();

    return {
        // ....
        dragBoundingRect
    };
  }

Then easily retrieve it from monitor.getItem()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants