Reputation: 5817
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?
Upvotes: 19
Views: 29545
Reputation: 81
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;
}
}
});
Upvotes: 1
Reputation: 47481
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;
});
}
}
});
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 )
Upvotes: 4
Reputation: 1133
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);
}
});
Upvotes: 2
Reputation: 61
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
Upvotes: 3
Reputation: 1510
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.
Upvotes: 3
Reputation: 4015
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.
Upvotes: 8
Reputation: 55372
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 });
Upvotes: 28
Reputation: 1613
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
Upvotes: 0