react-draggable
react-draggable copied to clipboard
positionOffset effects the bounds
<Draggable enableUserSelectHack={false} bounds="body" positionOffset={{ x: '-50%', y: '-50%' }} >
after I check the getBoundPosition function , I think node.offsetLeft does not contains css3 transform translate that positionOffset makes. referer How do I get the position of an element after css3 translation in JavaScript?
Maybe It is the same problem I've had recently. If you set values for 'positionOffset', then the positionOffset affects the entire draggable boundary so that the bounds you set will be also moved. I wanted the draggable element to be center of body, so I set values 'positionOffset={{ x: -50%, y: -50%}}' and css 'position: absolute; top: -50%; left: -50%;'. I don't know the reason but the css 'transform: translate(x, y)' value I set is not working. Maybe I guess the reason is that the transform value is variable with my dragging.
This is how I get through this problem.
const [bounds, setBounds] = useState({ left: null, right: null, top: null, bottom: null })
const handleStart = (e, data) => {
if(data) {
const x = data.node.offsetLeft - (data.node.offsetWidth / 2)
const top = data.node.offsetTop
const bottom = window.innerHeight - data.node.offsetHeight - data.note.offsetTop
setBounds({ left: -x, right: x, top: top, bottom: bottom })
}
}
<Draggable
positionOffset={{ x: '-50%', y: '-50%' })
onStart={handleStart}
bounds={bounds}
...
>
<div
style={{ position: 'absolute', top: '50%', left: '50% }}
...>
...
</div>
</Draggable>
then the Draggable element is placed in the center of the browser, and the 'bounds' works.
but It is the case when you want that the 'bounds' value is equal to the entire browser screen.
Anyway, I hope my comment was helpful.
@seungha-0709 Thanks for the idea. I had to adapt your code a bit to work with typescript. Plus, it looks like we only need to set the bounds once and draggable handles the rest.
import React from "react";
import Draggable from "react-draggable";
import s from "./modal.module.scss";
export interface Props {
header: string,
content: string,
draggable?: boolean,
boundingElement?: string,
dragPadding?: number
}
export interface State {
bounds: Object
}
export default class Modal extends React.PureComponent<Props, State> {
private hasSetBounds = false;
constructor(props: Props) {
super(props);
// Setup draggable
if (this.props.draggable) {
// Track the bounds state
this.state = {
bounds: { left: null, top: null, right: null, bottom: null}
}
}
}
handleDragStartOnce = (e: any, data: any) => {
// Handles fixing the draggable bounds
// Ref: https://github.com/react-grid-layout/react-draggable/issues/535
if (this.hasSetBounds
|| !data
|| !this.props.draggable
|| !this.props.boundingElement) return;
// Set our run-once flag
this.hasSetBounds = true;
// Padding applied to edges of bounding box
const dragPadding = this.props.dragPadding || 10;
// Grab the bounding element's bounding box data
const boundingBox = document.querySelector(this.props.boundingElement)?.getBoundingClientRect();
if (!boundingBox) {
console.warn('Could not find bounding box of specified bounding element', this.props.boundingElement);
return;
}
// Grab the node's bounding box data
const nodeBox = data.node.getBoundingClientRect();
// Set the state
this.setState({
bounds: {
left: (nodeBox.left - boundingBox.left - dragPadding) * -1,
right: boundingBox.right - nodeBox.right - dragPadding,
top: (nodeBox.top - boundingBox.top - dragPadding) * -1,
bottom: boundingBox.bottom - nodeBox.bottom - dragPadding,
}
});
}
render() {
// Build our inner section we may wrap
let childSection = (
<div className={s.container}>
<div className={s.titleBar} />
<div className={s.mainBody}>
<h3 className={s.header}>{this.props.header}</h3>
<div className={s.content}>{this.props.content}</div>
</div>
</div>
);
// Wrap with draggable
if (this.props.draggable) {
const onStart = (this.props.boundingElement) ? this.handleDragStartOnce : undefined
childSection = (
<Draggable
bounds={this.state.bounds}
onStart={onStart}
handle={'.' + s.titleBar}
positionOffset={{ x: 0, y: 'calc(40vh - 50%)' }}>
{childSection}
</Draggable>
)
}
// Compile the final block
return (
<div className={s.modalWrapper}>
{childSection}
</div>
);
}
}