jqueryzoomingdraggable

Why does jquery ui draggable containment not work if transform scale is used


I have some code which demonstrates the issue.

JSFIDDLE

I have an element which can be dragged around which works fine. I have included a button which allows the user to "zoom" in. This is when it goes wrong.

The issue this has is , after you click the zoom button, the containment part of draggable no longer obeys left/top/width and height the constraint of the parent. It is still constrained but by an unexpected boundary location.

<body style="padding:50px">
    <button id="btn">Zoom in</button>
    <div id="wrapper" style="background-color:aliceblue;padding:50px;">
    <div id="innerWrapper" style="background-color: ivory; min-height: 200px; width: 400px; ">
        <div id="draggable" style="background-color:burlywood;max-width:100px;">Move me</div>
        </div>
    </div>

    <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
    <script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js" integrity="sha256-lSjKY0/srUM9BE3dPm+c4fBo1dky2v27Gdjm2uoZaL0=" crossorigin="anonymous"></script>

    <script>
        $("#draggable").draggable({containment:"#innerWrapper"});  

        const btn = document.getElementById("btn");
        btn.addEventListener("click", zoom);

        function zoom() {
            document.getElementById("innerWrapper").style.transform = "scale(1.2,1.2)";
        }
    </script>
</body>

In fact, each time you click the zoom button provided, it changes the containment boundary.

I have tried to add the drag event callback within the draggable but still unable to see how I can fix this


Solution

  • This occurs because of the scale(), it acts strange in some compositions, and one of them is when you have a draggable element inside a containment, and that containment is scaled, so the element inside doesn't update the actual size of it, even if you destroy or disable and enable the draggable element.

    So what you can do is calculate yourself the containment size:

    const draggableElement = $("#draggable")
    let containmentArea = $("#innerWrapper");
    let percent = 1
    
    
    draggableElement.draggable({
      cursor: "move",
      drag: dragFix,
    });
    
    
    function dragFix(event, ui) {
      var contWidth = containmentArea.width(),
        contHeight = containmentArea.height();
      ui.position.left = Math.max(0, Math.min(ui.position.left / percent, contWidth - ui.helper.width()));
      ui.position.top = Math.max(0, Math.min(ui.position.top / percent, contHeight - ui.helper.height()));
    }
    
    
    function setScale(scalePercentage) {
      percent = scalePercentage;
      $("#innerWrapper").css({
        'transform': 'scale(' + percent + ')',
        '-moz-transform': 'scale(' + percent + ')',
        '-webkit-transform': 'scale(' + percent + ')',
        '-ms-transform': 'scale(' + percent + ')'
      })
    }
    
    
    const btn = document.getElementById("btn");
    btn.addEventListener("click", function() {
      setScale(1.2)
    });
    #wrapper {
      width: 100%;
      height: 300px;
      overflow: auto;
    }
    
    #innerWrapper {
      width: 250px;
      height: 250px;
      position: relative;
      -webkit-transform-origin: 0 0;
      -moz-transform-origin: 0 0;
      transform-origin: 0 0;
      -ms-transform-origin: 0 0;
    }
    
    #draggable {
      display: inline;
      position: absolute;
      top: 10px;
      left: 10px;
    }
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
    
    <button id="btn">Zoom in</button>
    <div id="wrapper" style="background-color:aliceblue;padding:50px;">
      <div id="innerWrapper" style="background-color: ivory; min-height: 200px; width: 400px; ">
        <div id="draggable" style="background-color:burlywood;max-width:100px;">Move me</div>
      </div>
    </div>

    Fiddle Version

    Notes:

    1 - You can use only tranform and transform-only, I did this to show you can do with all the transform types

    2 - For not having glitches when clicking the draggable element you need to make it absolute and the wrapper relative