4

This is an attempt to solve the problem of drag elements aligning to a grid (I outlined this in a previous question- Getting jQuery draggable to snap to specific grid)

So far I've established that the issue is that jQuery calculates the position of the element at the moment that .draggable() is called, and creates the grid relative to the element, instead of relative to the element's parent (which would be more intuitive).

In the following solution, we see 3 boxes:

  • Box 1 starts out at 0,0, and so will be aligned with the parent element's grid.
  • Box 2 starts out at a point not aligned with the grid, and so will never be aligned with it while dragging.
  • Box 3 also starts out at a point not aligned with the grid, but in this case we capture the mouse down event, and reposition the element to the nearest grid point, and only then to we call draggable().

Option 3 works in so far as the element will now snap in alignment with the grid. The problem is, it takes two mouse events: one to reposition the element, and only on the next mousedown event (after it's turned yellow) will a drag actually kick in.

How can I redo this so that the element can be repositioned and then have .draggable() called on it, all with a single mousedown event?

Aligning drag elements to grid

http://jsfiddle.net/8RnBf/34/

JS:

$('#box-1').draggable({
    grid: [ 20,20 ] 
});
$('#box-2').draggable({
    grid: [ 20,20 ] 
});

var isDraggable = false;
$('#box-3').mousedown(function(e){

    console.log('MOUSE DOWN');

    if (isDraggable == false) {
        var $this = $(this);

        // Reposition to nearest grid position:
        currentX = parseInt($this.css('left'));
        currentY = parseInt($this.css('top'));
        nearestGridX = Math.round(currentX/20) * 20;
        nearestGridY = Math.round(currentY/20) * 20;
        $this.css({left:nearestGridX+'px',top:nearestGridY+'px'});

        // Turn yellow:
        $this.css({background:'yellow'});

        // Make draggable:
        isDraggable = true;
        $this.draggable({
                grid: [ 20,20 ],
                start: function( event, ui ) {
                    console.log('START');
                }  
        });
        $this.trigger("mousedown");
    }

});
Community
  • 1
  • 1
Yarin
  • 173,523
  • 149
  • 402
  • 512
  • What a beautiful question. An interesting problem, a clear description of the issue, and a perfectly set up fiddle. hat: off. – Nate Dec 20 '13 at 21:43
  • It paid off- couldn't have asked for better answers! – Yarin Dec 20 '13 at 23:06

2 Answers2

8

Live Demo

You can implement a custom grid function much more easily than I would have guessed. This should simplify things for you, since you don't need to worry about repositioning and then using jQuery UI's grid.

// 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;
        }
    }  
});

Also, according to Scott Gonzalez, the grid option is going away in the future since it's the kind of thing that's trivial to implement on its own, so this sets you up better for the future, too.

Nate
  • 4,718
  • 2
  • 25
  • 26
  • Happy to. Your answer solves the problem every bit as much, but it does seem nice to strip away some complexity. – Nate Dec 20 '13 at 21:48
  • @Nate- This is in fact what I really wanted- a way to manipulate my own grid. I spent all day trying to hack different solutions, but now i've actually got something I can work with. THANKS! – Yarin Dec 20 '13 at 23:13
3

Instead of just passing type of event as parameter of trigger method, pass the event:

DEMO

$this.trigger(e);
A. Wolff
  • 74,033
  • 9
  • 94
  • 155
  • This works and is an easy fix. Gave it to Nate though as he really brought a better approach to the whole thing. Thanks-- – Yarin Dec 20 '13 at 23:15