Javascript 如何创建具有约束和过度标记的可拖动文件?

Javascript 如何创建具有约束和过度标记的可拖动文件?,javascript,reactjs,rubber-band,Javascript,Reactjs,Rubber Band,我正在尝试创建一个在定义的约束内(例如:在一个300*200px的容器内)的draggable。然而,除此之外,我还想创建一些橡皮筋效果,用于对可拖动设备进行过度包装。直到现在,我还没有找到用(纯)JavaScript实现这一点的方法 期望输出: 我当前的代码: import React,{Component,Fragment}来自“React”; 常数外径=400; 常数outerHeight=300; 导出默认类ImagePreview扩展组件{ DragableContainerRef

我正在尝试创建一个在定义的约束内(例如:在一个300*200px的容器内)的draggable。然而,除此之外,我还想创建一些橡皮筋效果,用于对可拖动设备进行过度包装。直到现在,我还没有找到用(纯)JavaScript实现这一点的方法

期望输出:

我当前的代码:

import React,{Component,Fragment}来自“React”;
常数外径=400;
常数outerHeight=300;
导出默认类ImagePreview扩展组件{
DragableContainerRef=null;
状态={
拖动:false,
posX:0,
波西:0
};
组件将装入=()=>{
document.addEventListener(“mousedown”,this.onMouseDown);
document.addEventListener(“mouseup”,this.onMouseUp);
};
组件将卸载=()=>{
document.removeEventListener(“mousedown”,this.onMouseDown);
document.removeEventListener(“mouseup”,this.onMouseUp);
};
calculateCenter=r=>{
常数{clientWidth,clientHeight}=r;
log({clientHeight,clientWidth});
//const centerX=innerWidth/2-clientWidth/2;
//const centerY=内部高度/2-客户端高度/2;
const centerX=外径/2-客户端宽度/2;
常数中心=外部高度/2-客户端高度/2;
log({centerX,centerY});
这是我的国家({
posX:centerX,
波西:森蒂
});
};
lastMousePos={
x:0,,
y:0
};
/**
*查看mouseEvent中的鼠标是否位于所需目标(.draggable)上
*@返回{boolean}真/假
*@memberofimagepreview
*/
checkTarget=e=>{
如果(
e、 目标&&
(e.target.classList.contains(“可拖动”)| | e.target.tagName==“SPAN”)
)
返回true;
返回false;
};
TotalTranslationy=null;
检查边界=(位置、维度、窗口维度)=>{
const posBoundBefore=0;
const posBoundAfter=窗口维度-维度;
if(posPOSBOUNDEAFTER){
返回后返回;
}
返回pos;
};
/**
*.draggable的Mousedown事件侦听器
*如果放大,则启动拖动过程。
*@memberofimagepreview
*/
onMouseDown=e=>{
如果(本检查目标(e)){
this.lastMousePos={
x:e.clientX,
y:e.clientY
};
document.addEventListener(“mousemove”,this.onMouseMove);
}
};
/**
*.draggable的Mousemove事件侦听器
*移动
*@memberofimagepreview
*/
onMouseMove=e=>{
常数{clientX,clientY}=e;
常量{x:initialX,y:initialY}=this.lastMousePos;
const{posX:lastStateX,posY:lastStateY}=this.state;
设posX=this.checkBounds(
lastStateX+(clientX-initialX),
this.draggableContainerRef.clientWidth,
外层宽度
);
设posY=this.checkBounds(
lastStateY+(客户端-首字母缩写),
此.DragableContainerRef.clientHeight,
户外照明
);
this.lastMousePos={
x:clientX,
y:clientY
};
这是我的国家({
姿势:“Zoomedindamped”,
是的,
posX,
波西
});
};
/**
*.draggable的Mouseup事件侦听器
*检查图像是否已被拖动。否则,它将切换放大/缩小的姿势和默认位置。
*@memberofimagepreview
*/
onMouseUp=e=>{
document.removeEventListener(“mousemove”,this.onMouseMove);
this.setState({drawing:false});
};
ref=r=>{
this.draggableContainerRef=r;
如果(r!==null)此.calculateCenter(r);
};
render(){
const{posX,posY}=this.state;
返回(
拖我!
);
}
}

您有代码吗?这是一个非常广泛的问题。。有许多库可以帮助您实现这一点。与此类似,“react-dnd”react-dnd使用HTML5的拖放API,它不能提供像上面显示的GIF那样多的视觉反馈。我目前的原型太混乱了,不过如果需要的话,我会尽量简化它,并将其添加到问题中
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>
    );
  }
}