I have two containers. A thumbnail container, and a "page" container. Both are divs. Thumbnails can be dragged back and forth between the two containers. I have revert on the thumbnails set to 'invalid', so they snap back to one of the two containers if they are dropped outside of either one of them.
The thumbnails must snap to a 20x20 grid inside the "page" container. This is so client the client can put the thumbnails in the "page" container in any place, but still be able to line them up neatly.
The problem is the draggable 'grid' option doesn't seem to work too well for this. It seems the "grid" is determined by the draggables location when you start dragging it, rather than acting as if the page has a real grid that can be snapped to.
Is there a way to fix this so the grid is based off the "page" container, rather than the position of the draggable when you start dragging it?
I have two containers. A thumbnail container, and a "page" container. Both are divs. Thumbnails can be dragged back and forth between the two containers. I have revert on the thumbnails set to 'invalid', so they snap back to one of the two containers if they are dropped outside of either one of them.
The thumbnails must snap to a 20x20 grid inside the "page" container. This is so client the client can put the thumbnails in the "page" container in any place, but still be able to line them up neatly.
The problem is the draggable 'grid' option doesn't seem to work too well for this. It seems the "grid" is determined by the draggables location when you start dragging it, rather than acting as if the page has a real grid that can be snapped to.
Is there a way to fix this so the grid is based off the "page" container, rather than the position of the draggable when you start dragging it?
Share Improve this question asked Aug 3, 2011 at 17:43 mellowsoonmellowsoon 23.3k19 gold badges58 silver badges76 bronze badges 4- I'm still interested to find if you found a solution for this. I've tried the 1 answer below, but it did not solve my problem. My problem is that each element seems to have it's own grid based on where it is dropped. – crush Commented Feb 14, 2013 at 18:43
- @crush, I've successfully achieved that using a custom rounding function on the stop event of the first drag. Once your object position is rounded to the nearest X pixels, you can apply a new grid parameter that will be based on the starting position which is know a multiple of your grid. – Capsule Commented Nov 18, 2013 at 20:36
- @Capsule that's basically what I ended up doing. – crush Commented Nov 18, 2013 at 20:39
- 1 With jQuery's native snap-to-grid it's pretty much impossible, but there's a great roll-your-own solution here: stackoverflow.com/a/20712561/165673 – Yarin Commented Dec 21, 2013 at 5:10
2 Answers
Reset to default 5Check the snapping example on the Jquery UI Site:
http://jqueryui.com/demos/draggable/#snap-to
You can take their same example and specify both a grid and a snap parameter.
Then the snap will be based off of the top left corner of the snap selector.
$( "#draggable5" ).draggable({ snap: ".ui-widget-header", grid: [ 80, 80 ] });
The example on the Jquery site will now let the "80x80" box snap based on the big container.
In your situation it might be easiest to create a div with 100% width and height, then set the snap: selector (using css selectors) to that div, then specifying a grid to snap to...
Good Luck
Maybe you could try to round the starting position to the nearest 20 pixels by using the start event on the draggable.
Something like (untested...):
$('#draggable').draggable(
{snap : grid: [20,20]},
{start : function(event, ui) {
var startPosition = $(ui.draggable).position();
$(ui.draggable).css({
'left' : (Math.round(startPosition.left/20)*20)+'px',
'top' : (Math.round(startPosition.top/20)*20)+'px'});
}
}
);
I'm trying myself to achieve that but I'm cloning the dragged element to another container so that's even more tricky ;-) I still have to figure out how to set the position of the helper in the start event...
Of course it will only work if the starting position is already absolute (like when dragged).
As a matter of fact, I've nearly achieved it by applying this method to the stop event and removing the grid property.
You don't get any visual feedback when moving the object around because there's no grid per se anymore, but when dropping it, it goes to your own grid:
stop: function(event, ui) {
var stopPosition = $(ui.draggable).position();
$(ui.draggable).css({'left' : (Math.round(stopPosition.left/20)*20)+'px', 'top' : (Math.round(stopPosition.top/20)*20)+'px'});
}
Here's a working example: http://jsfiddle.net/qNaHE/3/