I have an image that when I drag I want to implement a rotation too. The solution I had in mind was to use React DnD to get the xy coordinates of the dragged image position and calculate the difference between the original image location. The value from this difference would form the basis to make the rotation.
I've looked at examples on the ReactDnD library and see that the DragSource Specification can access the Monitor variable. This monitor variable has access to methods like getInitialClientOffset()
. When I implement a console.log()
of this value it shows me the last last coordinate set when I release the mouse.
Using this library, is there an easy way to get the current position of the dragged element as I move the mouse?
import React from 'react'
import { DragSource } from 'react-dnd'
// Drag sources and drop targets only interact
// if they have the same string type.
// You want to keep types in a separate file with
// the rest of your app's constants.
const Types = {
CARD: 'card',
}
/**
* Specifies the drag source contract.
* Only `beginDrag` function is required.
*/
const cardSource = {
beginDrag(props,monitor,component) {
// Return the data describing the dragged item
const clientOffset = monitor.getSourceClientOffset();
const item = { id: props.id }
console.log(clientOffset);
return item
},
isDragging(props, monitor){
console.log(monitor.getClientOffset())
},
endDrag(props, monitor, component) {
if (!monitor.didDrop()) {
return
}
// When dropped on a compatible target, do something
const item = monitor.getItem()
const dropResult = monitor.getDropResult()
console.log(item,dropResult)
//CardActions.moveCardToList(item.id, dropResult.listId)
},
}
/**
* Specifies which props to inject into your component.
*/
function collect(connect, monitor) {
return {
// Call this function inside render()
// to let React DnD handle the drag events:
connectDragSource: connect.dragSource(),
// You can ask the monitor about the current drag state:
isDragging: monitor.isDragging(),
}
}
function Card(props) {
// Your component receives its own props as usual
const { id } = props
// These two props are injected by React DnD,
// as defined by your `collect` function above:
const { isDragging, connectDragSource } = props
return connectDragSource(
<div>
I am a draggable card number {id}
{isDragging && ' (and I am being dragged now)'}
</div>,
)
}
// Export the wrapped version
export default DragSource(Types.CARD, cardSource, collect)(Card)
The useDrop hook has a hover(item, monitor)
method which does what you are looking for. It triggers repeatedly while you are hovering over the drop target.
I'm posting this way after the fact, but in case anyone is looking for this answer, the react-dnd way of doing this is by using what they call a Drag Layer - it gives you a way to use a custom component to be displayed when dragging.
They have a full example here: https://codesandbox.io/s/github/react-dnd/react-dnd/tree/gh-pages/examples_hooks_js/02-drag-around/custom-drag-layer?from-embed=&file=/src/CustomDragLayer.jsx
Also in the docs you want to look at useDragLayer and DragLayerMonitor
From what I remember, custom drag layer had serious performance issues. It's better to directly subscribe to the underlying API (the official documentation is severely lacking, but you can get this information from reading drag layer source):
const dragDropManager = useDragDropManager();
const monitor = dragDropManager.getMonitor();
React.useEffect(() => monitor.subscribeToOffsetChange(() => {
const offset = monitor.getClientOffset();
// do stuff like setState, though consider directly updating style through refs for performance
}), [monitor]);
You can also use some flag based on drag state to only subscribe when needed (simple isDragging && monitor.subscribe...
plus dependencies array does the trick).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With