Search code examples
jqueryjquery-uijscrollpane

How to make the jQuery UI Draggable "auto scrolling" with jScrollPane


Just seeing if anyone ran into this issue. We are using the awesome new jScrollPane in combination with the jQuery UI Draggable element. One cool feature of the Draggable element, that we lost when moving to jScrollPane, is that when you are dragging near the edge of the containing element it will scroll that element if possible. It does not do that with jScrollPane. Has anyone else tried to fix this?

Thanks!


Solution

  • Unfortunately this isn't possible in a simple manner. Looking at the code in jquery.ui.draggable.js, the relevant part is:

    $.ui.plugin.add("draggable", "scroll", {
        start: function(event, ui) {
            var i = $(this).data("draggable");
            if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
        },
        drag: function(event, ui) {
    
            var i = $(this).data("draggable"), o = i.options, scrolled = false;
    
            if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
    
                if(!o.axis || o.axis != 'x') {
                    if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
                        i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
                    else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
                        i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
                }
    
                if(!o.axis || o.axis != 'y') {
                    if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
                        i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
                    else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
                        i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
                }
    
            } else {
    
                if(!o.axis || o.axis != 'x') {
                    if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
                        scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
                    else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
                        scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
                }
    
                if(!o.axis || o.axis != 'y') {
                    if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
                        scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
                    else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
                        scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
                }
    
            }
    
            if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
                $.ui.ddmanager.prepareOffsets(i, event);
    
        }
    });
    

    As you can see, it directly manipulates the scrollTop and scrollLeft properties of the scrollParent. Unfortunately, jScrollPane doesn't use those properties...

    It is possible that you could add an extra method to draggable, following the template of the one above. In the drag function instead of setting scrollTop or scrollLeft you would use the API scrollBy methods.

    If you manage to get this working please fork the plugin on github and submit a pull request. If you don't think you can then please open a feature request on github and I'll try and implement it when I have some spare time.