我正在尝试创建一个可拖动的,它位于定义的约束内(例如:在 300*200px 容器内)。但是,除此之外,我想创建某种橡皮筋效果来过度拖动可拖动对象。直到现在,我还没有找到任何方法在(纯)JavaScript 中解决这个问题。
期望的输出:
我当前的代码: CodeSandbox URL
import React, { Component, Fragment } from "react";
const outerWidth = 400;
const outerHeight = 300;
export default class ImagePreview extends Component {
draggableContainerRef = null;
state = {
dragging: false,
posX: 0,
posY: 0
};
componentWillMount = () => {
document.addEventListener("mousedown", this.onMouseDown);
document.addEventListener("mouseup", this.onMouseUp);
};
componentWillUnmount = () => {
document.removeEventListener("mousedown", this.onMouseDown);
document.removeEventListener("mouseup", this.onMouseUp);
};
calculateCenter = r => {
const { clientWidth, clientHeight } = r;
console.log({ clientHeight, clientWidth });
//const centerX = innerWidth / 2 - clientWidth / 2;
//const centerY = innerHeight / 2 - clientHeight / 2;
const centerX = outerWidth / 2 - clientWidth / 2;
const centerY = outerHeight / 2 - clientHeight / 2;
console.log({ centerX, centerY });
this.setState({
posX: centerX,
posY: centerY
});
};
lastMousePos = {
x: 0,
y: 0
};
/**
* Looks whether the mouse in a mouseEvent is on the desired target (.draggable)
* @returns {boolean} True / False
* @memberof ImagePreview
*/
checkTarget = e => {
if (
e.target &&
(e.target.classList.contains("draggable") || e.target.tagName === "SPAN")
)
return true;
return false;
};
totalTranlationY = null;
checkBounds = (pos, dimension, windowDimension) => {
const posBoundBefore = 0;
const posBoundAfter = windowDimension - dimension;
if (pos < posBoundBefore) {
return posBoundBefore;
} else if (pos > posBoundAfter) {
return posBoundAfter;
}
return pos;
};
/**
* Mousedown event listener for .draggable
* Initiates dragging process if zoomed in.
* @memberof ImagePreview
*/
onMouseDown = e => {
if (this.checkTarget(e)) {
this.lastMousePos = {
x: e.clientX,
y: e.clientY
};
document.addEventListener("mousemove", this.onMouseMove);
}
};
/**
* Mousemove event listener for .draggable
* Moves
* @memberof ImagePreview
*/
onMouseMove = e => {
const { clientX, clientY } = e;
const { x: initialX, y: initialY } = this.lastMousePos;
const { posX: lastStateX, posY: lastStateY } = this.state;
let posX = this.checkBounds(
lastStateX + (clientX - initialX),
this.draggableContainerRef.clientWidth,
outerWidth
);
let posY = this.checkBounds(
lastStateY + (clientY - initialY),
this.draggableContainerRef.clientHeight,
outerHeight
);
this.lastMousePos = {
x: clientX,
y: clientY
};
this.setState({
pose: "zoomedInDampened",
dragging: true,
posX,
posY
});
};
/**
* Mouseup event listener for .draggable
* Checks whether image has been dragged around. Otherwise it toggles the pose for zooming in/out and defaults position.
* @memberof ImagePreview
*/
onMouseUp = e => {
document.removeEventListener("mousemove", this.onMouseMove);
this.setState({ dragging: false });
};
ref = r => {
this.draggableContainerRef = r;
if (r !== null) this.calculateCenter(r);
};
render() {
const { posX, posY } = this.state;
return (
<Fragment>
<div
className="draggableContainer"
style={{
fontFamily: "sans-serif",
width: outerWidth,
height: outerHeight,
background: "#292929",
position: "absolute",
margin: "auto",
left: 0,
right: 0,
top: 0,
bottom: 0
}}
>
<div
ref={this.ref}
className="draggable"
style={{
padding: "10px 15px",
cursor: "grab",
background: "gray",
position: "absolute",
userSelect: "none",
transform: `translateX(${posX}px) translateY(${posY}px)`
}}
>
<span
draggable={false}
style={{ color: "black", fontWeight: "bold" }}
>
Drag me!
</span>
</div>
</div>
</Fragment>
);
}
}