【问题标题】:jQuery UI Draggable + CSS Transform Causes "Jumping"jQuery UI Draggable + CSS Transform 导致“跳跃”
【发布时间】:2021-02-04 03:53:27
【问题描述】:

编辑:我解决了。但是 StackOverflow 并没有让我将我的答案标记为解决方案,所以我根本不会这样做。

我在将 Draggable 与 CSS 转换的父级一起使用时遇到了问题。基本上,我需要使用绝对定位在光标正下方生成一个 Draggable div。当绝对定位与 CSS 变换一起使用时,可拖动元素会随着拖动的发生而向右跳跃。跳跃发生后,行为按预期进行。如果没有对可拖动或父 div 应用任何转换,则不会发生跳转。

这是一个小提琴,它准确地显示了问题所在: http://jsfiddle.net/qBubN/7/

body {
     background-color: blue;   
}

#draggable {
    position: absolute;
    left: 50px;
    top: 50px;
    background-color: rgba(0,0,0,0.5);
    border: 1px solid black;
    width: 350px;
    height: 350px;
    color: white;
    -moz-transform: scale(0.5);
    -webkit-transform: scale(0.5);
    transform: scale(0.5);}

     $("#draggable").draggable({
            scroll: true, 
            distance: 5,
            grid : [ 10, 10 ],
            start: function (event, ui) {
            }
        });

<html>
    <body>
       <div id="draggable">
           Hello!
        </div>
    </body>
</html>

已经尝试应用此补丁,但无济于事。有一个(很好的)机会,这个修复太旧了,无法工作。我也有可能错误地应用了补丁。 Webkit and jQuery draggable jumping

【问题讨论】:

  • 为了清楚起见,我使用的是 Firefox 21.0

标签: jquery css jquery-ui scale


【解决方案1】:
//css3 transform bug with jquery ui drag - fixed(works fine whether position, absolute or relative)
var __dx;
var __dy;
var __scale=0.5;
var __recoupLeft, __recoupTop;

$("#draggable").draggable({
    //revert: true,
    zIndex: 100,
    drag: function (event, ui) {
        //resize bug fix ui drag `enter code here`
        __dx = ui.position.left - ui.originalPosition.left;
        __dy = ui.position.top - ui.originalPosition.top;
        //ui.position.left = ui.originalPosition.left + ( __dx/__scale);
        //ui.position.top = ui.originalPosition.top + ( __dy/__scale );
        ui.position.left = ui.originalPosition.left + (__dx);
        ui.position.top = ui.originalPosition.top + (__dy);
        //
        ui.position.left += __recoupLeft;
        ui.position.top += __recoupTop;
    },
    start: function (event, ui) {
        $(this).css('cursor', 'pointer');
        //resize bug fix ui drag
        var left = parseInt($(this).css('left'), 10);
        left = isNaN(left) ? 0 : left;
        var top = parseInt($(this).css('top'), 10);
        top = isNaN(top) ? 0 : top;
        __recoupLeft = left - ui.position.left;
        __recoupTop = top - ui.position.top;
    },
    stop: function (event, ui) {
        $(this).css('cursor', 'default');
        //alternate to revert (don't use revert)
        $(this).animate({
            left: $(this).attr('oriLeft'),
            top: $(this).attr('oriTop')
        }, 1000)
    },
    create: function (event, ui) {
        $(this).attr('oriLeft', $(this).css('left'));
        $(this).attr('oriTop', $(this).css('top'));
    }
});

【讨论】:

    【解决方案2】:

    我找到了解决办法。

    解决方案是在使用 Draggable 和 CSS 转换时完全避免 position:absolute;。您可以轻松地将任何东西从绝对/窗口/任何坐标转换为相对坐标,这就是我所做的。

    在我的例子中,我在鼠标下方生成了一个 Draggable 元素。我根据鼠标位置和元素的 offset() 计算相对位置(都在窗口坐标中),然后除以父 div 的比例。

    这是一个sn-p:

    // ops.[x|y] is the mouse position in window coords
    // parentDiv.offset().[left|right] is the div position in window coords
    
    // get the scale transform matrix from our poorly written panzooming lib
    var mtx = graph.parentDiv.panzoom('getMatrix');
    var zx = mtx[0];
    var zy = mtx[3];
    
    // calculate the relative position
    var x = (ops.x - parentDiv.offset().left) / zx;
    var y = (ops.y - parentDiv.offset().top) / zy;
    
    // set some initial css
    parentDiv.css('position', 'relative')
             .css('left', x + 'px')
             .css('top', y + 'px');
    
    // initialize the draggable
    parentDiv.draggable({
        stack: $(graph.parentDiv).children(),
        drag: function(e, ui){
            var mtx = graph.parentDiv.panzoom('getMatrix');
            var zoomScaleX = mtx[0];
            var zoomScaleY = mtx[3];
    
            // scale the delta by the zoom factor
            var dx = ui.position.left - ui.originalPosition.left;
            var dy = ui.position.top - ui.originalPosition.top;
    
            ui.position.left = ui.originalPosition.left + (dx / zoomScaleX);
            ui.position.top = ui.originalPosition.top + (dy / zoomScaleY);
        }
    });
    

    【讨论】:

    【解决方案3】:

    一个更简单的解决方案是用另一个 div 包装缩放的内容并将其设置为可拖动。

    【讨论】:

    • 是的,这是最简单的解决方案。试了一下,不会出现“跳楼问题”。
    【解决方案4】:

    这是一个显示 raghugolconda 的 method 的工作示例。

    我使用了data 方法,而不是设置非标准的attr 值。

    我将它全部封装到一个名为 $.fn.draggablePatched 的 jQuery 插件中。

    function main() {
      $('#draggable').draggablePatched({
        cursor: 'pointer'
      });
    }
    
    /* jquery.draggable-patched.js */
    (function($) {
      var __dx, __dy;
      var __recoupLeft, __recoupTop;
    
      var parseIntSafe = function(value) {
        return (function(n) {
          return isNaN(n) ? 0 : n;
        })(parseInt(value, 10));
      }
    
      $.fn.draggablePatched = function(options) {
        options = options || {};
        return this.draggable({
          cursor: options.cursor || 'move',
          zIndex: 100,
          drag: function(event, ui) {
            __dx = ui.position.left - ui.originalPosition.left;
            __dy = ui.position.top - ui.originalPosition.top;
            ui.position.left = ui.originalPosition.left + __dx + __recoupLeft;
            ui.position.top = ui.originalPosition.top + __dy + __recoupTop;
            if (options.drag) {
              options.drag(event, ui);
            }
          },
          start: function(event, ui) {
            var left = parseIntSafe($(this).css('left'));
            var top = parseIntSafe($(this).css('top'));
            __recoupLeft = left - ui.position.left;
            __recoupTop = top - ui.position.top;
            if (options.start) {
              options.start(event, ui);
            }
          },
          stop: function(event, ui) {
            $(this).animate({
              left: $(this).data('oriLeft'),
              top: $(this).data('oriTop')
            }, 1000);
            if (options.stop) {
              options.stop(event, ui);
            }
          },
          create: function(event, ui) {
            $(this).data({
              oriLeft: $(this).css('left'),
              oriTop: $(this).css('top')
            });
            if (options.create) {
              options.create(event, ui);
            }
          }
        });
      }
    })(jQuery);
    
    main();
    body {
      background-color: blue;
    }
    
    #draggable {
      position: absolute;
      left: 50px;
      top: 50px;
      width: 350px;
      height: 350px;
      
      background-color: rgba(0, 0, 0, 0.5);
      border: 1px solid black;
      color: white;
      
      font-size: 4em;
      line-height: 350px;
      text-align: center;
      
      -moz-transform: rotate(-45deg) scale(0.5);
      -webkit-transform: rotate(-45deg) scale(0.5);
      transform: rotate(-45deg) scale(0.5);
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
    <div id="draggable">
      Hello!
    </div>

    【讨论】:

      【解决方案5】:

      position:absolute; 确实有问题。然而,我找到了一种替代解决方案,通过在mousedown 上将 css 位置翻转为relative 并将其恢复为absolutemouseup 上,同时保持absolute 坐标和保持位置的基础,防止跳转,例如:

      $('#container').on('mousedown', 'canvas', function (e) {
          e.currentTarget.style.position = 'relative';
      }).on('mouseup', 'canvas', function (e) {
          if (e.currentTarget.style.position !== 'absolute'){
              e.currentTarget.style.position = 'absolute';
          }
      });
      

      它适用于鼠标事件。为了解决触摸事件以及“touchpunch”插件的问题,我还必须取消“点击”事件(仅适用于移动设备和启用触摸的模式)。

      【讨论】:

        【解决方案6】:

        扩展“raghugolconda”最佳答案:

        我在使用 jQueryUI 可拖动 和 CSS 变换时遇到了拖动速度和跳跃问题:scale()

        图像容器可通过缩放滑块进行缩放,红色方块可拖动。

        当我试图拖动红色元素时发生了什么:

        • 当您尝试拖动元素时,它发生了跳跃
        • 缩放超过 100% 时拖动速度过低
        • 缩放低于 100% 时拖动速度过快

        修复:

        1. 从 jQuery 滑块计算分数(比例值)。 这是我的滑块而不是转换图像容器:

          var fraction = 1;  
          
          $("#slider").slider({
              value: 0,
              min: -70,
              max: 70,
              step: 10,
              slide: function (event, ui) {
                  fraction = (1 + ui.value / 100);  
          
                  $("#infoSlider").text('Zoom: ' + Math.floor(fraction * 100) + '%');
          
                  $('.image_scalable_container').css({
                      '-webkit-transform': 'scale(' + fraction + ')',
                      '-moz-transform': 'scale(' + fraction + ')',
                      '-ms-transform': 'scale(' + fraction + ')',
                      '-o-transform': 'scale(' + fraction + ')',
                      'transform': 'scale(' + fraction + ')'
                  });
          
              }
          });
          
        2. 覆盖 jQuery UI 可拖动 dragstart 函数。

        drag 中修改拖动速度(比例 0.9 表示 drag_speed = 1 / 0.9 = 1.11)

        这是我的例子:

        $("#marker").draggable({
            //revert: true,
            zIndex: 100,
            drag: function (event, ui) {
                var drag_speed = 1 / fraction;
        
                __dx = (ui.position.left - ui.originalPosition.left) * drag_speed;
                __dy = (ui.position.top - ui.originalPosition.top) * drag_speed;
                ui.position.left = ui.originalPosition.left + (__dx);
                ui.position.top = ui.originalPosition.top + (__dy);            
                ui.position.left += __recoupLeft;
                ui.position.top += __recoupTop;
            },        
            start: function (event, ui) {            
                //resize bug fix ui drag
                var left = parseInt($(this).css('left'), 10);
                left = isNaN(left) ? 0 : left;
                var top = parseInt($(this).css('top'), 10);
                top = isNaN(top) ? 0 : top;
                __recoupLeft = left - ui.position.left;
                __recoupTop = top - ui.position.top;
            },
        });
        

        【讨论】:

          猜你喜欢
          • 2017-10-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-08
          • 2016-10-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多