skip to Main Content

I am trying to drag an element a little way on a mousedown event, so that it reveals a new item which will be drawn underneath. But when I try a move, it jumps to all the way to the right side of the window. How do I make it move to where I wanted? I have tried changing positions from ‘relative’ to ‘absolute’ , I have tried setting the new position to a fixed x and y, and relative to the mouse event; they all give the same result.

Something wrong with my basic understanding here. As background, I have been using vue.js quite a lot, to avoid getting too involved with dom manipulation myself (as I’m not too experienced!), and came across this problem in a vue project. Initially I thought it was a problem with Vue, but I’ve now shown it not to be.

document.getElementById("red").addEventListener("mousedown", mouseDown);
      function mouseDown(e) {

        const el = e.target;
        // const x = e.pageX;
        // const y = e.pageY;
     
        const rect = el.getBoundingClientRect();
        const x = rect.left + 20;
        const y = rect.top + 20;

        el.style.left = `${x}px`
        el.style.top = `${y}px`

        const newrect = el.getBoundingClientRect();

        document.getElementById("from").innerHTML = "drag from:      " + rect.left + ", " + rect.top;
        document.getElementById("to").innerHTML = "try to drag to: " + x + ", " + y;
        document.getElementById("result").innerHTML = "dragged to:     " + + newrect.left + ", " + newrect.top;
      }
.box {
    position:relative;
    margin: auto;
    border: 3px solid #73AD21;
    width: 200px;
    height: 250px;
    }
.button {
    position:relative;
    background-color: red;
    color: white;
    padding: 10px 20px;
    text-align: center;
    width: 100px;
    font-size: 16px;
    cursor: pointer;
  }
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Drag Drop Test</title>
  </head>
   
  <body>
    <div id="app" align="center" class="box">
      <button id="red" class="button" >Red</button>
      <p id="from"></p>
      <p id="to"></p>
      <p id="result"></p>
    </div>
  </body>
</html>

2

Answers


  1. Chosen as BEST ANSWER

    Simplifying @Mol nAK's answer for my specific requirement, I just need the following:

      const button = document.getElementById("red");
      button.addEventListener("mousedown", mouseDown);
    
      function mouseDown(e) {
        const parentRect = button.parentElement.getBoundingClientRect();
        const buttonRect = button.getBoundingClientRect();
    
        const moveFromLeft = buttonRect.left - parentRect.left;
        const moveFromTop =  buttonRect.top - parentRect.top; 
      
        button.style.left = `${moveFromLeft}px`
        button.style.top = `${moveFromTop}px`
      }
    

  2. The button is moving to the extreme right because in your code here:

    const el = e.target; //el is the button with id "red you click on
    
    const rect = el.getBoundingClientRect(); //this returns the size of the button and its current position relative to the viewport(not the parent element)
    
    const x = rect.left + 20;
    const y = rect.top + 20;
    
    el.style.left = `${x}px`//moves the button by 20px via x co-ordinate.
    el.style.top = `${y}px //moves the button by 20px via y co-oridnate.
    

    since in your CSS you have made both button and box to be relative, as soon as you push the button 20px from left and top, and since you haven’t considered the dimensions of the parent element of the button which is the box in this case, the button moves to the farthest right. If you want to keep the button inside the box, then you have to get the positions of the button relative to the parent element and not the whole viewport also the position of button should be absolute as you have made the postion of box to be relative.

    This is my code to achieve what I presume you want, a draggable button inside the box only. Hope this helps.

    const button = document.getElementById("red");
    const box = document.getElementById("app");
    
    const boxWidth = box.offsetWidth+3;
    const boxHeight = box.offsetHeight+3;//including border
    
    const buttonWidth = button.offsetWidth;
    const buttonHeight = button.offsetHeight;
    
    let dragStartX, dragStartY; //drag start posiitions
    let buttonX, buttonY;
    
    let isDragging; //to check if currently dragging or not
    let marginReached=false; //to check wether the button reaches the margin of the box or not
    
    button.addEventListener("mousedown", handleMouseDown);
    button.addEventListener("mousemove", handleMouseMove);
    button.addEventListener("mouseup", handleMouseUp);
    
    //handles mousedown events
    function handleMouseDown(e){
      const boxRect = box.getBoundingClientRect();
      const buttonRect = button.getBoundingClientRect();
      const LEFT = buttonRect.left - boxRect.left;
      const TOP = buttonRect.top - boxRect.top;
      isDragging = true;//set dragging to true
      dragStartX = e.clientX; //mouse pointer position on x axis
      dragStartY = e.clientY; //mouse pointer position on y axis
      buttonX = LEFT;//position of button on x axis
      buttonY = TOP;//position of button on y axis
    }
    
    //handles mouse move events
    function handleMouseMove(e){
      const mouseX = e.clientX;//current mouse position on x axis
      const mouseY = e.clientY;// current mouse position on y axis
      
      const moveFromLeft = mouseX-dragStartX+buttonX;
      const moveFromTop = mouseY-dragStartY+buttonY;
      
      //checks wether the button reaches the margin of the box and prevents it from going any further
      if(moveFromLeft>=(boxWidth-buttonWidth) || 
        moveFromTop>=(boxHeight-buttonHeight)||
        moveFromLeft<=0||
        moveFromTop<=0
        ){
        marginReached = true
      }else{
        marginReached = false
      }
      
        if(isDragging && !marginReached){
        button.style.left = `${moveFromLeft}px`
        button.style.top = `${moveFromTop}px`
      }
    }
    
    //handles mouse up events
    function handleMouseUp(e){
        isDragging = false; //set dragging to false on mouse button release
    }
    .box {
        position:relative;
        margin: auto;
        border: 3px solid #73AD21;
        width: 200px;
        height: 250px;
        }
    .button {
        position:absolute;
        left:25%;
        background-color: red;
        color: white;
        padding: 10px 20px;
        text-align: center;
        width: 100px;
        font-size: 16px;
        cursor: pointer;
      }
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <link rel="icon" href="/favicon.ico">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Drag Drop Test</title>
      </head>
       
      <body>
        <div id="app" align="center" class="box">
          <button id="red" class="button" >Red</button>
          <p id="from"></p>
          <p id="to"></p>
          <p id="result"></p>
        </div>
      </body>
    </html>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search