12

编辑:我解决了。但是 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 和 jQuery 可拖动跳跃

4

6 回答 6

17
//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'));
    }
});
于 2013-09-04T05:56:34.330 回答
11

我找到了解决方案。

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

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

这是一个片段:

// 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);
    }
});
于 2013-06-14T03:42:52.607 回答
4

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

于 2014-07-18T21:53:32.020 回答
1

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

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

我将它全部打包到一个名为$.fn.draggablePatched.

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>

于 2021-02-03T19:24:48.737 回答
0

position:absolute;确实有问题。但是,我找到了一种替代解决方案,可以absolute通过将 css 位置翻转为relativeon并将其恢复为 on ,同时保持坐标和保持位置的基础mousedown,并将其恢复为absoluteon mouseup,例如以下:

$('#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”插件,我还必须取消“点击”事件(仅适用于移动和启用触摸的模式)。

于 2017-09-23T09:40:09.043 回答
0

扩展“ raghugolconda ”最佳答案:

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

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

在此处输入图像描述

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

  • 当您尝试拖动元素时,它会跳跃
  • 缩放超过 100% 时拖动速度过低
  • Zoom 低于 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 可拖动的拖动启动功能。

拖动中修改拖动速度(比例 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-19T13:12:22.253 回答