JQuery Sortable and automatic scrolling
Asked Answered
H

9

19

I am trying to get JQuery Sortable to work but I have run into a slight usability problem.

The list that I am trying to sort is quite large (about 200 items). If the user tries to drag the top item right to the bottom, once the item reaches the bottom of the visible part of the screen, the page scrolls a tiny amount, then stops. To trigger more downward scrolling, you have to move the mouse in circular motions about until the item reaches the bottom.

Is there any method of tracking the position of the mouse while it is dragging an item and automatically scrolling the screen down?

Haldis answered 17/9, 2010 at 22:10 Comment(0)
D
28

I would take a look at the scroll, scrollSensativity, and scrollSpeed options.

You can do something like:

$("#sort").sortable({ scroll: true, scrollSensitivity: 100 });

or

$("#sort").sortable({ scroll: true, scrollSpeed: 100 });

or even

$("#sort").sortable({ scroll: true, scrollSensitivity: 100, scrollSpeed: 100 });
Distich answered 17/9, 2010 at 22:15 Comment(1)
This answer doesn't address what is actually desired in the question.Salpiglossis
M
8

While the value of the scrollSensitivity controls the scroll behaviour when the helper item approaches an edge (top or bottom), you can use the "sort" event to unconditionally scroll while you drag if you use the following code:

$(".sortable").sortable({
    scroll: true,
    scrollSensitivity: 80,
    scrollSpeed: 3,
    sort: function(event, ui) {
        var currentScrollTop = $(window).scrollTop(),
            topHelper = ui.position.top,
            delta = topHelper - currentScrollTop;
        setTimeout(function() {
            $(window).scrollTop(currentScrollTop + delta);
        }, 5);
    }
});

Not sure if this completely addresses the issue you're seeing, but I found that usability with larger list improves with this approach. Here is a link to jsfiddle.

Muscatel answered 25/2, 2014 at 0:31 Comment(2)
In case the scrolling speed is too fast (like it was in my case) you can add the following line inside setTimeout: if(delta > 7) delta = 7; and play with the number to adjust speedCrippling
you have a bug, when scrolling down and then up, the scrolling still goes downCrippling
T
4

Scroll window when an item is dragged close to the top or bottom.

I could not get any of the other answers working. Using Chrome and a sortable grid that needs to scroll vertically when an item is being dragged to the top or bottom edge of the window.

NOTE: This only works for scrolling the entire window. This will not work if you have a scrollable section inside of the window and need to scroll that.

I was able to get the following working flawlessly:

var currentlyScrolling = false;

var SCROLL_AREA_HEIGHT = 40; // Distance from window's top and bottom edge.

$(".sortable").sortable({
    scroll: true,

    sort: function(event, ui) {

      if (currentlyScrolling) {
        return;
      }

      var windowHeight   = $(window).height();
      var mouseYPosition = event.clientY;

      if (mouseYPosition < SCROLL_AREA_HEIGHT) {
        currentlyScrolling = true;

        $('html, body').animate({
          scrollTop: "-=" + windowHeight / 2 + "px" // Scroll up half of window height.
        }, 
        400, // 400ms animation.
        function() {
          currentlyScrolling = false;
        });

      } else if (mouseYPosition > (windowHeight - SCROLL_AREA_HEIGHT)) {

        currentlyScrolling = true;

        $('html, body').animate({
          scrollTop: "+=" + windowHeight / 2 + "px" // Scroll down half of window height.
        }, 
        400, // 400ms animation.
        function() {
          currentlyScrolling = false;
        });

      }
    }
});

Coffeescript Version

currentlyScrolling = false
SCROLL_AREA_HEIGHT = 40

sort: (event, ui) ->

  return if currentlyScrolling

  windowHeight = $( window ).height()

  mouseYPosition = event.clientY

  if mouseYPosition < SCROLL_AREA_HEIGHT # Scroll up.
    currentlyScrolling = true
    $( 'html, body' ).animate( { scrollTop: "-=" + windowHeight / 2 + "px" }, 400, () -> currentlyScrolling = false )

  else if mouseYPosition > ( windowHeight - SCROLL_AREA_HEIGHT ) # Scroll down.
    currentlyScrolling = true
    $( 'html, body' ).animate( { scrollTop: "+=" + windowHeight / 2 + "px" }, 400, () -> currentlyScrolling = false )
Ticon answered 7/4, 2018 at 19:13 Comment(2)
If you want to change the scroll speed just increase the number 2 in both these parts of the code windowHeight / 2 + "px" to make it slowerRoger
@SamiBirnbaum Good suggestion. Maybe we should change that to a constant, like SCROLL_SPEED or something? Let me know your thoughts.Ticon
T
3

I think that you can consider handling scrolling external to sortable. I suggest to use timer and 'out' event of sortable.

Here is piece of code based on jQueryUI demo page, you can use it as start point, if want to go this way:

$(function() {
   var scroll = '';
   var $scrollable = $("#sortable");
   function scrolling(){
     if (scroll == 'up') {
       $scrollable.scrollTop($scrollable.scrollTop()-20);
       setTimeout(scrolling,50);
     }
     else if (scroll == 'down'){
       $scrollable.scrollTop($scrollable.scrollTop()+20);
       setTimeout(scrolling,50);
     }
   }

   $( "#sortable" ).sortable({
      scroll:false,
      out: function( event, ui ) {
        if (!ui.helper) return;
        if (ui.offset.top>0) {
          scroll='down';
        } else {
          scroll='up';
        }
        scrolling();
      },
      over: function( event, ui ) {
        scroll='';
      },
      deactivate:function( event, ui ) {
        scroll='';
      }
    });
    $( "#sortable").disableSelection(); 
});

Here is also working example: JSBIN

sorry
I did not lock example code and was destroyed incidentally. Now it's back to work.

Transient answered 21/2, 2014 at 9:28 Comment(0)
L
3

I have removed overflow-y: scroll from body to resolve it.

Limelight answered 1/8, 2014 at 18:49 Comment(1)
Thanks, Working perfectly after removing "overflow-x: initial" & "overflow-y: initial"Caesarism
S
3

I had a responsive table with bootstrap, this would not let it work.

not like this:

<div class="table-responsive">
   <table>
      ...
   </table>
</div>

like this yes:

 <table>
   ...
 </table>

and use these options:

scroll, scrollSensitivity, scrollSpeed

Shunt answered 9/11, 2016 at 15:30 Comment(0)
C
2

Based on @marty 's answer, here is a fine tuned code that will: 1. Control speed of the scrolling 2. Will scroll down and scroll up without glitches. 3. Default speed is 7px at a time 4. movements of less than 7px will be ignored

var previousLocation, previousDelta;
    $( ".selector" ).sortable({
        sort: function(event, ui) {
            var currentScrollTop = $(window).scrollTop(),
                topHelper = ui.position.top,
                delta = topHelper - currentScrollTop;
            setTimeout(function() {
                if((delta < 7 && delta >=0) || (delta > -7 && delta <=0))
                    return;
                if(delta > 7){
                    delta = 7;
                    if((topHelper - previousDelta) < previousLocation){
                        delta = (delta * -1);
                    }
                }
                if(delta < -7){
                    delta = -7;
                    if((topHelper - previousDelta) > previousLocation){
                        delta = (delta * -1);
                    }
                }

                $(window).scrollTop(currentScrollTop + delta);
                previousLocation = topHelper; previousDelta = delta;
            }, 5);
        }
    });
Crippling answered 18/2, 2018 at 11:13 Comment(0)
E
1

Old topic but here is an example of scroll with a custom scrollable element

var sortScrollInterval = null;
var scrollDelta = 0;
$('.selector').sortable({
    // [..]
    scroll: false,
    sort: function(event, ui) {
        var scrollContainer = $('#container');
        var vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);

        // Scroll top if cursor is into the first 20% of screen
        // Scroll bottom if cursor is into the last 20% of screen
        var top20 = vh * 0.2;
        var bottom20 = vh * 0.8;
        if ((ui.position.top <= top20) || (ui.position.top > bottom20)) {
            if (ui.position.top <= top20) {
                // Closer to the top = quicker scroll
                scrollDelta = -40 * ((top20 - ui.position.top) / top20);
            }
            else {
                // Closer to the bottom = quicker scroll
                scrollDelta = 40 * (1 - (ui.position.top - bottom20) / bottom20);
            }

            // Set interval
            if (null === sortScrollInterval) {
                sortScrollInterval = setInterval(function() {
                    if (Math.abs(scrollDelta) > 10) {
                            $(scrollContainer).scrollTop($(scrollContainer).scrollTop() + scrollDelta);
                        }
                }, 50);
            }
        }
        else if (null !== sortScrollInterval) {
            clearInterval(sortScrollInterval);
            sortScrollInterval = null;
        }
    },
    over: function(event, ui) {
        if (null !== sortScrollInterval) {
            clearInterval(sortScrollInterval);
            sortScrollInterval = null;
        }
    },
    deactivate: function(event, ui) {
        if (null !== sortScrollInterval) {
            clearInterval(sortScrollInterval);
            sortScrollInterval = null;
        }
    }
});
Equi answered 3/11, 2020 at 15:14 Comment(0)
S
0

You can trigger events based on the position returned by mouseMove. Here's a simple tutorial: http://jquery-howto.blogspot.com/2009/07/identifying-locating-mouse-position-in.html

This tutorial might help you get started: http://valums.com/vertical-scrolling-menu/ And this walks through the same effect: http://www.queness.com/resources/html/scrollmenu/index.html

Silvia answered 17/9, 2010 at 22:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.