javascripthtmlcssdrag-and-droprotatetransform

Drag and drop rotated images javascript


so i have a code that allows me to drag and drop an img tag. The drag and drop works fine but when i added a rotation function, the drag and drop started acting weird (the coordinates changed and when i drag the element the rotation reset). Also when i try dragging again, it goes back to its initial position, do you please have any idea on how i can fix this? Image before rotation Image after rotation while dragging after changing rotation

This is my code and thank you in advance:

let rotate=0

function rot_plus() {
 
  rotate=rotate+10
  $("#test").css('transform',"rotate("+rotate+"deg)")
 

}

function rot_minus() {
 
  rotate=rotate-10
  $("#test").css('transform',"rotate("+rotate+"deg)")
 

}

var active = false;
var currentX;
var currentY;
var initialX;
var initialY;
var xOffset = 0;
var yOffset = 0;
let current_elem
var container = document.querySelector("#boite");
container.addEventListener("mousedown", dragStart, false);
container.addEventListener("mouseup", dragEnd, false);
container.addEventListener("mousemove", drag, false);

function dragStart(e) {
if(e.target.id=="test"){
dragItem1=e.target.id
    dragItem = document.querySelector("#"+e.target.id);
          initialX=e.clientX-xOffset
          initialY=e.clientY-yOffset

    active = true;
}
  }



function drag(e) {

  if (active) {

    e.preventDefault();
   currentX = e.clientX - initialX;
          currentY = e.clientY - initialY;

    xOffset = currentX;
    yOffset = currentY;
    setTranslate(currentX, currentY, dragItem);
  }

}

function dragEnd(e) {
        active = false;
        initialX=currentX
       initialY=currentY

  selectedElement = null;
   }


function setTranslate(xPos, yPos, el) {

 el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0) rotate("+rotate+"deg)";


}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js" integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
    <div id="boite">
 <img src="https://static.vecteezy.com/system/resources/previews/009/342/282/original/cartoon-eyes-clipart-design-illustration-free-png.png" id="test" class="remove" style="position: absolute; width:150px; height:auto" >
  <svg xmlns="http://www.w3.org/2000/svg" width="46" height="46" fill="currentColor" class="bi bi-plus-circle" id="rotplus" style="margin-top:120px" onclick="rot_plus()" viewBox="0 0 16 16">
    <path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/>
    <path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/>
  </svg>

  <svg xmlns="http://www.w3.org/2000/svg"width="46" height="46" fill="currentColor" class="bi bi-dash-circle" id="rotminus"
style="margin-top:120px" onclick="rot_minus()" viewBox="0 0 16 16">
    <path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z"/>
    <path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/>
  </svg>
</div>
</body>
</html>


Solution

  • You are using $.css to change the transform in the rotation functions. But this removes the positional changes as both are defined in 'transform'. That is, to fix this you need to keep the position information when rotating.

    To do this it is better not to use jquery as it will clean the information in transform. So what I did was just replicate the line where you define the position but instead of taking the positions defined in your function I take it directly from the variables where you store the values.

    I also used a CSS to prevent items from being selected when dragging:

    CSS:

        #boite,
        #boite * {
            user-select: none;
        }
    

    JS:

    function rot_plus() {
        const el = lastItemDragged
        rotate = rotate + 10;
        el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
    }
    
    function rot_minus() {
        const el = lastItemDragged
        rotate = rotate - 10;
        el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
    }
    
    function setTranslate(el) {
        el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
    }
    

    I also added the variable lastItemDragged to store the last item dragged (so that the rotation reaches the same)

    full code:

    let rotate = 0
    
    function rot_plus() {
        const el = lastItemDragged
        rotate = rotate + 10;
        el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
    }
    
    function rot_minus() {
        const el = lastItemDragged
        rotate = rotate - 10;
        el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
    }
    var lastItemDragged = document.querySelector('#test')
    var active = false;
    var currentX;
    var currentY;
    var initialX;
    var initialY;
    var xOffset = 0;
    var yOffset = 0;
    let current_elem
    var container = document.querySelector("#boite");
    container.addEventListener("mousedown", dragStart, false);
    container.addEventListener("mouseup", dragEnd, false);
    container.addEventListener("mousemove", drag, false);
    
    function dragStart(e) {
        if (e.target.id == "test") {
            dragItem1 = e.target.id
            dragItem = document.querySelector("#" + e.target.id);
            initialX = e.clientX - xOffset
            initialY = e.clientY - yOffset
            active = true;
        }
    }
    
    function drag(e) {
        if (active) {
            e.preventDefault();
            currentX = e.clientX - initialX;
            currentY = e.clientY - initialY;
            xOffset = currentX;
            yOffset = currentY;
            setTranslate(dragItem);
        }
    }
    
    function dragEnd(e) {
        active = false;
        initialX = currentX
        initialY = currentY
        selectedElement = null;
    }
    
    function setTranslate(el) {
        el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
    }
    #boite,
    #boite * {
        user-select: none;
    }
    <div id="boite">
        <img src="https://static.vecteezy.com/system/resources/previews/009/342/282/original/cartoon-eyes-clipart-design-illustration-free-png.png" id="test" class="remove" style="position: absolute; width:150px; height:auto">
        <svg xmlns="http://www.w3.org/2000/svg" width="46" height="46" fill="currentColor" class="bi bi-plus-circle" id="rotplus" style="margin-top:120px" onclick="rot_plus()" viewBox="0 0 16 16">
            <path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" />
            <path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z" />
        </svg>
        <svg xmlns="http://www.w3.org/2000/svg" width="46" height="46" fill="currentColor" class="bi bi-dash-circle" id="rotminus" style="margin-top:120px" onclick="rot_minus()" viewBox="0 0 16 16">
            <path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z" />
            <path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z" />
        </svg>
    </div>