javascriptjqueryjquery-uijquery-ui-draggablejquery-ui-droppable

Getting JQuery UI Draggable to snap to a specific grid (with a twist)


I am currently trying to apply a "drag and drop" - functionality to a bunch of elements using jQuery and jQuery UI. It should be noted, that the elements should always snap to a specific grid when being dragged. I was very happy to see that in this question @Nate already explained the functionality very well. The problem I'm facing is, that the grid the draggable elements should snap to should be oriented to the droppable element AND the draggable elements are no children to the droppable element.

In detail, the draggable elements of varying sizes should always snap to a grid consisting of 40x40 cells oriented to a droppable (in my example 400x400, so a 10x10 grid), thats in another part of my html. The main problem i'm facing is, that i can't seem to get the orientation of my snapping grid to align with my droppable. Here's my current approach in javascript:

$(document).ready(function(){

    $(".draggable").draggable({
        revert: true,
        revertDuration: 0,
        snap: true,
        snapTolerance: 40,
        containment: ".container",

        drag: function( event, ui ) {
            var snapTolerance = $(this).draggable('option', 'snapTolerance');

            //get positions of the own board and the currently dragged element relative to the document
            var ownBoardPositionRelToDoc = $("#droppable").offset();
            var uiPositionRelToDoc = ui.helper.offset();

            var topDiffToDoc = ui.helper.offset().top - ui.position.top;
            var leftDiffToDoc = ui.helper.offset().left - ui.position.left;

            console.log(ownBoardPosition);
            console.log(uiPosition);

            topRemainder = ownBoardPosition.top % 40;
            leftRemainder = ownBoardPosition.left % 40;

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

            if (leftRemainder <= snapTolerance) {
                ui.position.left = ui.helper.offset().left - leftRemainder;
            }
        }
    });

    $(".droppable").droppable({
        accept: ".draggable",
        tolerance: "fit",
        drop: function(event, ui) {
            $(ui.draggable).appendTo($(this));
        }
    });

});

I've constructed a JSFiddle to explain my idea further. Sadly it's not executable due to JQuery UI not being supported but you should get the idea.


Solution

  • Consider the following.

    JavaScript

    $(function() {
      $(".draggable").draggable({
        revert: true,
        revertDuration: 0,
        containment: ".container",
        grid: [40, 40]
      });
    
      $(".droppable").droppable({
        accept: ".draggable",
        tolerance: "fit",
        drop: function(event, ui) {
          $(ui.draggable).appendTo($(this));
        }
      });
    });
    

    https://jsfiddle.net/Twisty/rLx7jtob/

    You can use grid to make it easier.

    https://api.jqueryui.com/draggable/#option-grid

    Snaps the dragging helper to a grid, every x and y pixels. The array must be of the form [ x, y ].