Javascript 如何在React中实现拖放界面,并具有放大和缩小功能?
我正在尝试构建一个web应用程序,其中一个核心功能是将图标拖放到地图的蓝图上。为此,我使用React,因为我需要能够存储蓝图中各种对象的位置,以便准确地复制它们 到目前为止,我有一个存储对象数组的父组件,每个对象都有一个x和一个y属性。该数组被传递给画布组件,该组件在数组上迭代,并通过将top和left属性设置为相应对象的适当x和y属性,在画布中绝对定位每个数组 我已经在这个代码笔中演示了这个原则: 我遇到的问题是增加了缩放功能。父组件存储传递到画布的缩放属性,并且使用CSS中的缩放变换根据缩放因子缩放画布的大小Javascript 如何在React中实现拖放界面,并具有放大和缩小功能?,javascript,reactjs,Javascript,Reactjs,我正在尝试构建一个web应用程序,其中一个核心功能是将图标拖放到地图的蓝图上。为此,我使用React,因为我需要能够存储蓝图中各种对象的位置,以便准确地复制它们 到目前为止,我有一个存储对象数组的父组件,每个对象都有一个x和一个y属性。该数组被传递给画布组件,该组件在数组上迭代,并通过将top和left属性设置为相应对象的适当x和y属性,在画布中绝对定位每个数组 我已经在这个代码笔中演示了这个原则: 我遇到的问题是增加了缩放功能。父组件存储传递到画布的缩放属性,并且使用CSS中的缩放变换根据缩放
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
zoom: 1, // ratio to scale canvas
map: map // root object that stores positions of items within canvas
}
}
updatePositions(newPositions) {} // updates positions in state when element is finished dragging
updateZoom(e) {} // updates zoom factor
render() {
return (
<div>
<Canvas
positions={this.state[...].positions}
updatePositions={this.updatePositions}
zoom={this.state.zoom}/>
</div>
)
}
}
类应用程序扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
缩放:1,//与画布比例
映射:映射//在画布中存储项目位置的根对象
}
}
updatePositions(newPositions){}//在元素拖动完成时更新状态中的位置
updateZoom(e){}//更新缩放因子
render(){
返回(
)
}
}
子组件迭代位置数组并渲染每个位置
class Canvas extends React.Component {
constructor(props) {
super(props);
this.state = {
index: 0
}
// Logic to get bounds of rendered element to calculate positions within canvas
this.selector = React.createRef();
}
// Select element, set active index to track position object to update, add event listener to get new position
selectElement(index) {
this.setState({
index: index,
drag: true
}, () => {
document.addEventListener("mousemove", this.onMouseMove);
document.addEventListener("mouseup", this.onMouseUp);
});
}
// Track mouse within bounding box to move object
onMouseMove(e) {
let width = 100;
let height = 100;
let elements = [...this.props.operatorPositions];
let newX = e.pageX - (width / 2);
let newY = e.pageY - height;
// Make sure object is within canvas
if (newX < this.state.bounds.left) {
newX = this.state.bounds.left - this.state.bounds.x;
} else if (newX> this.state.bounds.right - width - this.state.bounds.x) {
newX = this.state.bounds.right - width - this.state.bounds.x;
}
if (newY < this.state.bounds.top - this.state.bounds.y) {
newY = this.state.bounds.top - this.state.bounds.y;
} else if (newY > this.state.bounds.bottom - height - this.state.bounds.y) {
newY = this.state.bounds.bottom - height - this.state.bounds.y;
}
elements[this.state.index].x = newX;
elements[this.state.index].y = newY;
this.props.updatePositions(elements);
}
// Stop tracking mouse when object is dropped
onMouseUp(e) {
document.removeEventListener("mousemove", this.onMouseMove);
document.removeEventListener("mouseup", this.onMouseUp);
this.setState({
drag: false
});
}
// Get bounding box of canvas
componentDidMount() {
if (!this.state.bounds) {
this.setState({
bounds: this.selector.current.getBoundingClientRect()
})
}
}
render() {
const boxes = this.props.operatorPositions.map((op, index) => {
return <Box name={this.props.operators[index]} x={op.x} y={op.y} key={index} index={index}
selectElement={this.selectElement} drag={index === this.state.index && this.state.drag}/>
});
return (
<div id="canvas" ref={this.selector} style={{ transform: `scale(${this.props.zoom}`}}>
{ boxes }
</div>
)
}
}
类画布扩展React.Component{
建造师(道具){
超级(道具);
此.state={
索引:0
}
//获取渲染元素边界以计算画布内位置的逻辑
this.selector=React.createRef();
}
//选择元素,设置活动索引以跟踪要更新的位置对象,添加事件侦听器以获取新位置
选择元素(索引){
这是我的国家({
索引:索引,,
拖动:正确
}, () => {
document.addEventListener(“mousemove”,this.onMouseMove);
document.addEventListener(“mouseup”,this.onMouseUp);
});
}
//在边界框内跟踪鼠标以移动对象
onMouseMove(e){
宽度=100;
设高度=100;
让元素=[…this.props.operatorPositions];
设newX=e.pageX-(宽度/2);
设newY=e.pageY-高度;
//确保对象位于画布内
if(newXthis.state.bounds.right-width-this.state.bounds.x){
newX=this.state.bounds.right-width-this.state.bounds.x;
}
if(newYthis.state.bounds.bottom-height-this.state.bounds.y){
newY=this.state.bounds.bottom-height-this.state.bounds.y;
}
元素[this.state.index].x=newX;
元素[this.state.index].y=newY;
this.props.updatePosition(元素);
}
//物体下落时停止跟踪鼠标
onMouseUp(e){
document.removeEventListener(“mousemove”,this.onMouseMove);
document.removeEventListener(“mouseup”,this.onMouseUp);
这是我的国家({
拖动:false
});
}
//获取画布的边界框
componentDidMount(){
如果(!this.state.bounds){
这是我的国家({
边界:this.selector.current.getBoundingClientRect()
})
}
}
render(){
常量框=this.props.operatorPositions.map((op,index)=>{
返回
});
返回(
{box}
)
}
}
我不赞成这种方法。从演示中可以看出,缩放限制了画布的可访问区域,并破坏了当前在画布中拖动和定位元素的能力
这个问题与其说是找到一个bug,不如说是请求帮助开发一种方法来实现所描述系统的缩放。我不难使用当前的方法,但任何方法都需要满足一些参数:
- 可以存储和重新创建画布中所有元素的位置
- 可以在画布中拖动元素
- 画布可以放大或缩小以获得更好的可见性,而不会影响元素相对于背景的移动或位置