Webkit and jQuery draggable jumping

后端 未结 8 1076
误落风尘
误落风尘 2020-11-28 23:40

As an experiment, I created a few div\'s and rotated them using CSS3.

    .items { 
        position: absolute;
        cursor: pointer;
        background:          


        
相关标签:
8条回答
  • 2020-11-29 00:20

    This is a result of draggable's reliance on the jquery offset() function and offset()'s use of the native js function getBoundingClientRect(). Ultimately this is an issue with the jquery core not compensating for the inconsistencies associated with getBoundingClientRect(). Firefox's version of getBoundingClientRect() ignores the css3 transforms (rotation) whereas chrome/safari (webkit) don't.

    here is an illustration of the issue.

    A hacky workaround:

    replace following in jquery.ui.draggable.js

    
    //The element's absolute position on the page minus margins
    this.offset = this.positionAbs = this.element.offset();
    

    with

    
    //The element's absolute position on the page minus margins
    this.offset = this.positionAbs = { top: this.element[0].offsetTop, 
                                       left: this.element[0].offsetLeft };
    

    and finally a monkeypatched version of your jsbin.

    0 讨论(0)
  • 2020-11-29 00:21

    the answer of David Wick was very helpful... thanks... here i coded the same workaround for the resizeable, because it has the same problem:

    search for the following in jquery.ui.resizable.js

    var o = this.options, iniPos = this.element.position(), el = this.element;
    

    and replace with:

    var o = this.options, iniPos = {top:this.element[0].offsetTop,left:this.element[0].offsetLeft}, el = this.element;
    
    0 讨论(0)
  • 2020-11-29 00:23

    I used a lot of the solutions to get dragging working correctly. BUT, it still reacted wrong to a dropzone (like it wasn't rotated). The Solution really is to use a parent container that is positioned relative.

    This saved me soooo much time.

    <div id="drawarea">
        <div class="rect-container h">
            <div class="rect"></div>
        </div>
    </div> 
    
    
    
    .rect-container {
        position:relative; 
    }
    

    Full Solution here (it's not from me): http://jsfiddle.net/Sp6qa/2/

    Also I researched a lot. And its just like this, jQuery doesn't have any plans to change that current behavior in the future. All submitted tickets about that topic were closed. So just start out with having parentcontainers that are positioned relative. It works like a charm and should be futureproof.

    0 讨论(0)
  • 2020-11-29 00:24

    David Wick is right about the general direction above, but computing the right coordinates is way more involved than that. Here's a more accurate monkey patch, based on MIT licensed Firebug code, which should work in far more situations where you have a complex DOM:

    Instead replace:

        //The element's absolute position on the page minus margins
        this.offset = this.positionAbs = this.element.offset();

    with the less hacky (be sure to get the whole thing; you'll need to scroll):

        //The element's absolute position on the page minus margins
        this.offset = this.positionAbs = getViewOffset(this.element[0]);
    
        function getViewOffset(node) {
          var x = 0, y = 0, win = node.ownerDocument.defaultView || window;
          if (node) addOffset(node);
          return { left: x, top: y };
    
          function getStyle(node) {
            return node.currentStyle || // IE
                   win.getComputedStyle(node, '');
          }
    
          function addOffset(node) {
            var p = node.offsetParent, style, X, Y;
            x += parseInt(node.offsetLeft, 10) || 0;
            y += parseInt(node.offsetTop, 10) || 0;
    
            if (p) {
              x -= parseInt(p.scrollLeft, 10) || 0;
              y -= parseInt(p.scrollTop, 10) || 0;
    
              if (p.nodeType == 1) {
                var parentStyle = getStyle(p)
                  , localName   = p.localName
                  , parent      = node.parentNode;
                if (parentStyle.position != 'static') {
                  x += parseInt(parentStyle.borderLeftWidth, 10) || 0;
                  y += parseInt(parentStyle.borderTopWidth, 10) || 0;
    
                  if (localName == 'TABLE') {
                    x += parseInt(parentStyle.paddingLeft, 10) || 0;
                    y += parseInt(parentStyle.paddingTop, 10) || 0;
                  }
                  else if (localName == 'BODY') {
                    style = getStyle(node);
                    x += parseInt(style.marginLeft, 10) || 0;
                    y += parseInt(style.marginTop, 10) || 0;
                  }
                }
                else if (localName == 'BODY') {
                  x += parseInt(parentStyle.borderLeftWidth, 10) || 0;
                  y += parseInt(parentStyle.borderTopWidth, 10) || 0;
                }
    
                while (p != parent) {
                  x -= parseInt(parent.scrollLeft, 10) || 0;
                  y -= parseInt(parent.scrollTop, 10) || 0;
                  parent = parent.parentNode;
                }
                addOffset(p);
              }
            }
            else {
              if (node.localName == 'BODY') {
                style = getStyle(node);
                x += parseInt(style.borderLeftWidth, 10) || 0;
                y += parseInt(style.borderTopWidth, 10) || 0;
    
                var htmlStyle = getStyle(node.parentNode);
                x -= parseInt(htmlStyle.paddingLeft, 10) || 0;
                y -= parseInt(htmlStyle.paddingTop, 10) || 0;
              }
    
              if ((X = node.scrollLeft)) x += parseInt(X, 10) || 0;
              if ((Y = node.scrollTop))  y += parseInt(Y, 10) || 0;
            }
          }
        }

    It's a shame the DOM doesn't expose these calculations natively.

    0 讨论(0)
  • 2020-11-29 00:24

    You have to set the parent container of the draggable element to "position: relative".

    0 讨论(0)
  • 2020-11-29 00:33

    I prefer this workaround as it preserves the original handler
    It removes the transform then restores it

    $(document).ready(function(){
    
        // backup original handler
        var _mouseStart = $.ui.draggable.prototype._mouseStart;
    
        $.ui.draggable.prototype._mouseStart = function(event) {
    
            //remove the transform
            var transform = this.element.css('transform');
            this.element.css('transform', 'none');
    
            // call original handler
            var result = _mouseStart.call(this, event);
    
            //restore the transform
            this.element.css('transform', transform);
    
            return result;
        };
    });
    

    demo (started from @Liao San-Kai jsbin)

    0 讨论(0)
提交回复
热议问题