It looks like that the 'grid' option in the constructor of Draggable is relatively bound to the original coordinates of the element being dragged - so simply put, if you have three draggable divs with their top set respectively to 100, 200, 254 pixels relative to their parent:
<div class="parent-div" style="position: relative;">
<div id="div1" class="draggable" style="top: 100px; position: absolute;"></div>
<div id="div2" class="draggable" style="top: 200px; position: absolute;"></div>
<div id="div3" class="draggable" style="top: 254px; position: absolute;"></div>
</div>
Adn all of them are getting enabled for dragging with 'grid' set to [1, 100]:
draggables = $('.draggable');
$.each(draggables, function(index, elem) {
$(elem).draggable({
containment: $('#parent-div'),
opacity: 0.7,
revert: 'invalid',
revertDuration: 300,
grid: [1, 100],
refreshPositions: true
});
});
Problem here is that as soon as you drag div3, say, down, it's top is increased by 100, moving it to 354px instead of being increased by just mere 46px (254 + 46 = 300), which would get it to the next stop in the grid - 300px, if we are looking at the parent-div as a point of reference and "grid holder".
I had a look at the draggable sources and it seem to be an in-built flaw - they just do all the calculations relative to the original position of the draggable element.
I would like to avoid monkey-patching the code of draggable library and what I am really looking for here is the way how to make the Draggable calculate the grid positions relative to containing parent. However if monkey-patching is unavoidable, I guess I'll have to live with it.
I got around this problem by simply adding my own script to drag: under draggable and setting it to divide math.Floor(x/100)*100 and the same for Y.
If you don't mind poking around in source look at http://labs.pezcuckow.com/solveit/game.html and the make draggable function! (game nonwhere near finished)
you'll also find a problem with revert, it doesn't put them back snapped to grid. So I wrote my own "check if invalid" function in end: of dragabble (again viewable on the game above).
Since @Pez's answer is lost (404), here's how I did it:
$('#elem').draggable({
....,
drag: function(e, ui) {
ui.position.left = Math.floor(ui.position.left / 10) * 10;
ui.position.top = Math.floor(ui.position.top / 10) * 10;
}
});
Demo: http://jsfiddle.net/ThiefMaster/yGsSE/
I've started using JQuery draggable over the last couple of days and found an easy fix to this.
Set the position property to absolute and add your widgets with top and left set to values that line up to your grid.
As the values for top/left are absolute they also make more sense when going off and storing them in a db.
Jquery Desktop:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js"></script>
<link rel="stylesheet/less" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/themes/base/jquery-ui.css">
<div class="parent-div" style="position: relative;">
<div id="div1" class="draggable" style="top: 100px; position: absolute;">1</div>
<div id="div2" class="draggable" style="top: 200px; position: absolute;">2</div>
<div id="div3" class="draggable" style="top: 254px; position: absolute;">3</div>
</div>
<script>
var Z_INDEX_APP = 0;
var Z_INDEX_WINDOW_COUNTER = 1;
var Z_INDEX_NOTE_COUNTER = 999;
var Z_INDEX_FOR_DRAGGED = 99999;
var Z_INDEX_FOR_NOTIF = 999999;
var ICONS_GRID_CELL_SIZE = 75;
var ICONS_GRID_PADDING_LEFT = 20;
var ICONS_GRID_PADDING_TOP = 50;
draggables = $('.draggable');
$.each(draggables, function(index, elem) {
$(elem).draggable({
containment: $('#parent-div'),
start: function(event) {
icon = $(this);
icon.css('z-Index', Z_INDEX_FOR_DRAGGED);
dragStartLeft = icon.css('left');
dragStartTop = icon.css('top');
icon.addClass('desktop-app-dragging');
icon.removeClass('desktop-app-pressed');
},
stop: function(event) {
icon.css('z-Index', Z_INDEX_APP);
var appId = icon.attr('id').split('_')[1];
icon.removeClass('desktop-app-dragging');
var alignedX = ICONS_GRID_PADDING_LEFT + Math.floor(parseInt(icon.css('left'))/ICONS_GRID_CELL_SIZE) * ICONS_GRID_CELL_SIZE;
var alignedY = ICONS_GRID_PADDING_TOP + Math.floor(parseInt(icon.css('top'))/ICONS_GRID_CELL_SIZE) * ICONS_GRID_CELL_SIZE;
if ( alignedX < ICONS_GRID_PADDING_LEFT ) alignedX = ICONS_GRID_PADDING_LEFT;
if ( alignedY < ICONS_GRID_PADDING_TOP ) alignedY = ICONS_GRID_PADDING_TOP;
var iconToSwitch = null;
$(".desktop-app").each(function(index, app) {
if ( app.style.top == ( alignedY + 'px' ) && app.style.left == ( alignedX + 'px' ) ) {
iconToSwitch = app;
}
});
if ( iconToSwitch != null ) {
var appToSwitchId = iconToSwitch.id.split('_')[1];
var updateUrl = 'api/desktop?cmd=update&id=' + appToSwitchId + '&x=' + parseInt(dragStartLeft) + '&y=' + parseInt(dragStartTop);
//$.getJSON(updateUrl);
iconToSwitch.style.left = dragStartLeft;
iconToSwitch.style.top = dragStartTop;
}
icon.css('left', alignedX + 'px');
icon.css('top', alignedY + 'px');
var updateUrl = 'api/desktop?cmd=update&id=' + appId + '&x=' + alignedX + '&y=' + alignedY;
//$.getJSON(updateUrl);
}
});
});
</script>