javascriptjquerycssjquery-uijquery-ui-sortable

jQuery UI sortable with body zoom not working, Not calculating drag and drop area correctly


I am trying to jQuery UI sortable work with zoom CSS property on body. But it's not allowing me to drag and drop correctly on the right position.

Drag only working with half area, if user try to drag and drop from empty area on right side(Black area in my case) it's not working

https://codepen.io/VijayDhanvai/pen/poqxEzQ

Red area where drop not working Red area where drop not working

 $(function () {
    var zoomScale = $("body").css("zoom");
    console.log(typeof zoomScale, zoomScale.toString());
    var canvasHeight = $("#sortable").height();
    var canvasWidth = $("#sortable").width();

    $("#sortable").sortable({
      sort: function (e, ui) {
        var changeLeft = ui.position.left - ui.originalPosition.left;
        var changeTop = ui.position.top - ui.originalPosition.top;
        var sortIndex =
          $("#sortable .ui-sortable-placeholder").index() + 30;
        var newLeft =
          ui.originalPosition.left +
          changeLeft / zoomScale -
          ui.item.parent().offset().left;

        var newTop =
          ui.originalPosition.top +
          changeTop / zoomScale -
          ui.item.parent().offset().top +
          sortIndex;

        ui.helper.css({
          left: newLeft,
          top: newTop,
        });
      },
    });
  });

 $(function () {
        var zoomScale = $("body").css("zoom");
        console.log(typeof zoomScale, zoomScale.toString());
        var canvasHeight = $("#sortable").height();
        var canvasWidth = $("#sortable").width();

        $("#sortable").sortable({
          sort: function (e, ui) {
            var changeLeft = ui.position.left - ui.originalPosition.left;
            var changeTop = ui.position.top - ui.originalPosition.top;
            var sortIndex =
              $("#sortable .ui-sortable-placeholder").index() + 30;
            var newLeft =
              ui.originalPosition.left +
              changeLeft / zoomScale -
              ui.item.parent().offset().left;

            var newTop =
              ui.originalPosition.top +
              changeTop / zoomScale -
              ui.item.parent().offset().top +
              sortIndex;

            ui.helper.css({
              left: newLeft,
              top: newTop,
            });
          },
        });
      });
 .ui-sortable-placeholder,
      .ui-sortable-helper {
        visibility: visible !important;
        background-color: black !important;
      }
      .ui-sortable-placeholder td,
      .ui-sortable-helper td {
        background-color: aqua;
      }

      table {
        /* width: 100%; */
        border-spacing: collapse;
        border-spacing: 0;
      }
      td {
        padding: 0px;
        min-width: 100%;
        border: solid 1px #ddd;
      }
      body {
        zoom: 1.3;

        
      }
<link rel="stylesheet" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" />    
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js"></script>
    <script type="text/javascript" src="https://github.com/borbit/jquery.viewport/raw/master/jquery.viewport.js"></script>
    <script type="text/javascript" src="https://github.com/borbit/jquery.scraggable/raw/master/jquery.scraggable.js"></script>

                  
  <table>
      <thead>
        <tr>
          <th>Month</th>
          <th>Savings</th>
        </tr>
      </thead>
      <tbody id="sortable">
        <tr>
          <td>January</td>
          <td>$100</td>
        </tr>
        <tr>
          <td>February</td>
          <td>$80</td>
        </tr>
        <tr>
          <td>January</td>
          <td>$100</td>
        </tr>
        <tr>
          <td>February</td>
          <td>$80</td>
        </tr>
        <tr>
          <td>January</td>
          <td>$100</td>
        </tr>
        <tr>
          <td>February</td>
          <td>$180</td>
        </tr>
      </tbody>
    </table>         


Solution

  • Possible Causes

    The behavior of jQuery UI sortable is comparing the mouse position with the element offsets. However, It seems that offset values of children elements won't be affected by zoom if setting zoom on a parent element. (Safari CSS Reference has mentioned it slightly.)

    By the way, according to Mozilla document of zoom, CSS zoom is non-standard. It means it has possibility of different behaviors in variable browsers. If it's possible, try not to use CSS zoom.

    Solution: nested zooming

    In your case, it works well to get the width after zooming if zoom set on <td>. So I try to set nested zoom to simulate the view of setting zoom on <body>:

    tbody {
      zoom: calc(1 / 1.3);
    }
    
    td {
      zoom: 1.3;
      padding: 0px;
      min-width: 100%;
      border: solid 1px #ddd;
    }
    
    body {
      zoom: 1.3;
    }
    

    If you do above, you don't have to calculate helper element by yourself:

    $("#sortable").sortable();
    

    Here is demo: https://codepen.io/LyreneLiu/pen/PoXyQYx