Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting jQuery draggable to snap to specific grid

(NOTE: Some have asked similar questions, but were too specific and yielded no usable answers)

jQuery UI's draggable widget has options for snapping to a grid, but no way to set what the grid is relative to.

For example, we've got a clearly defined 20x20 grid in our drop target. A drag item that starts at 0,0 within the drop target will snap in correspondence with the grid. But a drag item that starts at a different location, or outside the drop target, will not line up with that grid.

enter image description here

http://jsfiddle.net/FNhFX/5/

HTML:

<div class="drop-target">
    <div class="drag-item">Drag me</div>
    <div class="drag-item" style="left:87px;top:87px;">Drag me</div>
</div>
<div class="outside-drag-item">Drag me</div>

JS:

$(function() {
    $(".drag-item").draggable({
        grid: [20, 20]
    });
    $(".outside-drag-item").draggable({
        grid: [20, 20],
        helper:"clone"
    });
    $(".drop-target").droppable({
        accept: ".drag-item"
    });
});

Is there any way to snap to a specific grid using jQuery draggable?

like image 958
Yarin Avatar asked Dec 20 '13 03:12

Yarin


People also ask

How do I limit a draggable area?

Limit draggable area using 'containment' option We can restrict the draggable area. It is simple. All you have to do is, add an option called containment to the draggable() method. The containment option has a value parent.

What is jQuery draggable?

jQueryUI provides draggable() method to make any DOM element draggable. Once the element is draggable, you can move that element by clicking on it with the mouse and dragging it anywhere within the viewport.

Does jQuery draggable work on mobile?

jQuery UI wasn't originally written to handle mobile devices. It won't even play nicely with jQuery Mobile. some parts of it may still work well in mobile devices, but anything that has anything to do with dragging will fail.


2 Answers

I'm going to go ahead and post an answer here, too, though I came here via a followup question you asked.

You can create your own snap-to-grid functionality very easily inside the drag event on a jQuery UI draggable.

Basically, you want to check how close the current ui position is at any point that the draggable is being dragged to a grid. That proximity can always be represented as the remainder of the position divided by the grid. If that remainder is less than or equal to the snapTolerance, then just set the position to what it would be without that remainder.

That was weird to say in prose. In the code it should be more clear:

Live Demo

// Custom grid
$('#box-3').draggable({
    drag: function( event, ui ) {
        var snapTolerance = $(this).draggable('option', 'snapTolerance');
        var topRemainder = ui.position.top % 20;
        var leftRemainder = ui.position.left % 20;

        if (topRemainder <= snapTolerance) {
            ui.position.top = ui.position.top - topRemainder;
        }

        if (leftRemainder <= snapTolerance) {
            ui.position.left = ui.position.left - leftRemainder;
        }
    }  
});
like image 108
Nate Avatar answered Oct 20 '22 02:10

Nate


As an alternative to attempting to use the grid option in jQuery UI, I have created my own grid (that you can make visible or invisible using css), then use the snap option and specify the class of each of my grid lines.

To your original jsfiddle, I added the following css:

.gridlines {
display: none;
position:absolute;
background-color:#ccc;
}

and the following javascript:

function createGrid(size) {
  var i,
  sel = $('.drop-target'),
      height = sel.height(),
      width = sel.width(),
      ratioW = Math.floor(width / size),
      ratioH = Math.floor(height / size);

  for (i = 0; i <= ratioW; i++) { // vertical grid lines
    $('<div />').css({
        'top': 0,
        'left': i * size,
        'width': 1,
        'height': height
    })
      .addClass('gridlines')
      .appendTo(sel);
  }

  for (i = 0; i <= ratioH; i++) { // horizontal grid lines
    $('<div />').css({
        'top': i * size,
        'left': 0,
        'width': width,
        'height': 1
    })
      .addClass('gridlines')
      .appendTo(sel);
    }

  $('.gridlines').show();
}

createGrid(20);

Here is the jsFiddle (http://jsfiddle.net/madstop/46sqd/2/)

like image 22
madstop Avatar answered Oct 20 '22 02:10

madstop