Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery UI Draggable, Snapping to a Grid

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?

like image 849
mellowsoon Avatar asked Aug 03 '11 17:08

mellowsoon


2 Answers

Check 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

like image 65
Chris Lucian Avatar answered Oct 15 '22 14:10

Chris Lucian


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/

like image 21
Capsule Avatar answered Oct 15 '22 14:10

Capsule