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
How do I get the coordinates of my dropped item relative to the drop target container? #151
Comments
Seems like |
Yeah I guess we could have this for symmetry. For now, you can just use |
I would like something like this as well. I need to get the bounding rect/coordinates of the drop target, so when I hover something on it I can calculate if it's on the left, right, top or bottom side inside the drop target. |
The relative coordinates can be useful for other use cases. For a Trello-like app, when you drag a card over a list, the list scrolls to bottom when hovering near bottom of drop area, and scrolls up when hovering near the top. Trivial to implement on user space tho. Also, I vaguely remember reading that accessing bounding rectangle triggers reflow in browsers and somewhat costly. Not sure if this is still the case. |
I don't think there's a way to do this without actually accessing
That's a great use case. The perf penalty is indeed, significant, and will be wasted if it's added to React DnD but your app doesn't use it. Therefore, I don't want to add this to React DnD. It is easy to implement in userland, and you will be able to do things like throttle I'm open to adding “scroll on hover at the bottom” as an example to the sortable stress test. This would involve adding another drop target at the Container level that only listens to However I won't add the DOM coordinate methods to React DnD for the reasons described above. |
@gaearon I'm interested in generalized solution. How can we use |
I solved this by passing the // some code before...
const [, dropRef] = useDrop({
accept: 'STICKY',
drop(item, monitor) {
move(
item.id,
monitor.getInitialSourceClientOffset(),
monitor.getSourceClientOffset()
);
},
});
// I'm updating my state with npm immer (immutable helper) throuthg the produce function...
const move = (id, initialPosition, finalPosition) => {
setList(
produce(list, draft => {
list.map(item => {
if (item.id === id) {
item.position = getCorrectDroppedOffsetValue(
initialPosition,
finalPosition
);
}
return item;
});
})
);
};
// and finally, my getCorrectDroppedOffsetValue function
const getCorrectDroppedOffsetValue = (initialPosition, finalPosition) => {
// get the container (view port) position by react ref...
const dropTargetPosition = ref.current.getBoundingClientRect();
const { y: finalY, x: finalX } = finalPosition;
const { y: initialY, x: initialX } = initialPosition;
// calculate the correct position removing the viewport position.
// finalY > initialY, I'm dragging down, otherwise, dragging up
const newYposition =
finalY > initialY
? initialY + (finalY - initialY) - dropTargetPosition.top
: initialY - (initialY - finalY) - dropTargetPosition.top;
const newXposition =
finalX > initialX
? initialX + (finalX - initialX) - dropTargetPosition.left
: initialX - (initialX - finalX) - dropTargetPosition.left;
return {
x: newXposition,
y: newYposition,
};
}; |
function useCustomDrop(onDrop: (info: unknown, xy: Point) => void) {
const ref = useRef<Element>();
const [, dropTarget] = useDrop<any, void, unknown>({
accept: 'item-type',
drop(item, monitor) {
const offset = monitor.getSourceClientOffset();
if (offset && ref.current) {
const dropTargetXy = ref.current.getBoundingClientRect();
onDrop(item.data, {
x: offset.x - dropTargetXy.left,
y: offset.y - dropTargetXy.top,
});
}
}
});
return (elem) => {
ref.current = elem;
dropTarget(ref);
};
} |
@quanganhtran do you have any complete code samples you'd be willing share, please? |
A contrived example: https://codesandbox.io/s/elastic-liskov-00ldf The API is nicer when we don't have to store the |
this solution isn't reliable especially when you zoom in the browser or device resolution change. any idea? |
i have the same question @sepehr09 |
Just passing by after a few google searches... Any update on the original question? (obtaining the x/y of a dropped item relative to the drop target) |
I guess I'll join the list of those, who needs this. Any help please? |
I think this feature very necessary, need to be add in library. Right now, Anyone worked with it, please help us ! |
I too would benefit of a solution to this problem! Thanks |
My workaround is to put a div with element reference around the drop target and use that to measure. Because I also put other stuff inside that container div I position the drop target absolute over the entire container. Something like this (pseudo-code, copy-paste at your own risk)
|
|
Here is a working solution on hover: const [, drop] = useDrop(() => ({
accept: 'Box',
hover: (_item, monitor) => {
const offset = monitor.getClientOffset()
if (offset && rootRef.current) {
const rect = rootRef.current.getBoundingClientRect()
console.log({
x: offset.x - rect.left,
y: offset.y - rect.top,
})
}
},
drop: (_item, monitor) => {
if (monitor.didDrop()) return
return {
id: 'foo',
}
},
collect: () => ({}),
}), []) Hope it helps. |
Thanks @dherault . How do you get |
Here's a gist: const rootRef = useRef()
// ... the code from before
const forkedRef = useForkedRef(rootRef, drop) // Google useForkedRef
return <div ref={forkedRef} /> |
Thanks @dherault . This is another way of doing it more explicitly, in case somebody is interested: function DropTarget(props) {
const boundingBox = useRef(null)
const [output_of_collect, drop_ref] = useDrop(
() => ({
// ... <your stuff> ... //
hover: (item, monitor) => {
const offset = monitor.getClientOffset();
const deltaX = offset.x - boundingBox.current.x
const deltaY = offset.y - boundingBox.current.y
console.log("deltaX = " + deltaX + ", deltaY = " + deltaY)
},
// ... < your other stuff > ... //
}))
function combinedRef(el) {
drop_ref(el);
if (el) {
boundingBox.current = el.getBoundingClientRect();
}
}
return (
<div ref={combinedRef} > Content of your div </div>
) |
I am working with 1.0.0-rc.
In
drag-around-naive
:At present it looks like I need to get the offset from the page of the original item, then I can find the offset from the page of where I dropped, then I need to find the offset of the drop container from the page, then do that calculation and I have the relative position in my drop target container.
This seems like a lot of work for something pretty common...
The text was updated successfully, but these errors were encountered: