2

I'm not sure how to do this. Im using jQuery draggable, and I need to capture grid position:

  $("#draggable .item").draggable({
      containment: "#dragablle",
      snap: '.gridlines',
      stop: function(event, ui) {
          console.log(ui)
      }
  });

Looking at the object receiver from stop event :

Object { top=178, left=950}

I need to convert top and left values into percentage, so I can apply to .item element as inline style. Parent "#draggable" width and height will be dynamic, so that's why I need percentage instead of pixel. So when screen is resized, everything will remain the same (position) within parent element

Mattia Nocerino
  • 1,474
  • 1
  • 16
  • 33
Alko
  • 1,421
  • 5
  • 25
  • 51

2 Answers2

15

If you are using jQueryUI Draggable

Try this:

$("#draggable .item").draggable({
    containment: "#draggable",
    snap: '.gridlines',
    stop: function () {
        var l = ( 100 * parseFloat($(this).position().left / parseFloat($(this).parent().width())) ) + "%" ;
        var t = ( 100 * parseFloat($(this).position().top / parseFloat($(this).parent().height())) ) + "%" ;
        $(this).css("left", l);
        $(this).css("top", t);
    }
});
Luka
  • 472
  • 4
  • 18
  • Thanks I tried tour solution but getting error "TypeError: $(...).position(...).left is not a function" – Alko Jun 19 '16 at 18:43
  • @Alko I made update above, try without brackets after left and top. That was mistake. – Luka Jun 19 '16 at 18:47
  • You might want to check out `outerWidth()` and `outerHeight()` for more percise calculations. – NonameSL May 30 '17 at 16:18
  • @Luka I have a similar [question](https://stackoverflow.com/questions/52880510/constantly-move-resizable-draggable-image-on-the-video-when-the-browser-is-resiz?noredirect=1#comment92674974_52880510). I am wondering if you can give me some pointers. – john Oct 18 '18 at 19:27
  • Works great. Thanks. – Patrick Mutuku Jan 10 '19 at 01:21
2

In order to capture grid position, you could use the option grid: [x,y]. You do not have to convert top and left values into percentage if you want to have snap to grid feature, by doing so you have to calculate the positions according to your dynamic width and height upon $(window).resize() event.

Try running the snippet below in Full Page mode,

var grid_x = 10; 
var grid_y = 10;
var snapThreshold = 5;
var snapWhileResizing = true;
var old_w, old_h;
$(function() {
    old_w = $("#draggable").width();
    old_h = $("#draggable").height();
    $("#label-old-dimen").html(old_w + ' x ' + old_h); 
    $("#draggable .item").draggable({
        containment: "parent",
        grid: [grid_x, grid_y],
        stop: function (){
            var l = $(this).position().left;
            var t = $(this).position().top;
            var mod_l = l % grid_x;
            var mod_t = t % grid_y;   
            l = (mod_l > snapThreshold) ? (l + (grid_x - mod_l)) : l - mod_l;
            t = (mod_t > snapThreshold) ? (t + (grid_y - mod_t)) : t - mod_t;    
            $(this).html(l + ' x ' + t);
            $(this).data("left", l);
            $(this).data("top", t);
            $(this).css("left", l);
            $(this).css("top", t);   
        }
    });

    $("#snapWhileResizing").change(function(){
        snapWhileResizing = $(this).is(':checked');
    });
});

$(window).resize(function() {
    var new_w = window.innerWidth;
    var new_h = window.innerHeight;
    $("#label-new-dimen").html(new_w + ' x ' + new_h);
    var mod_w = new_w % grid_x;
    var mod_h = new_h % grid_y;
    new_w = ((mod_w > snapThreshold) ? (new_w + (grid_x - mod_w)) : new_w - mod_w) - 40;
    new_h = ((mod_h > snapThreshold) ? (new_h + (grid_y - mod_h)) : new_h - mod_h) - 50;
    
    if(old_w != new_w)
        old_w = $("#draggable").width();
    if(old_h != new_h)
        old_h = $("#draggable").height();
    
    $("#draggable").width(new_w);
    $("#draggable").height(new_h);

    $("#label-old-dimen").html(new_w + ' x ' + new_h);    
    $("#draggable .item").each(function(){
        var old_l, l, new_l, mod_l;
        var old_t, t, new_t, mod_t;            
        old_l = l = $(this).data("left");
        old_t = t = $(this).data("top");
        new_l = $(this).position().left;
        new_t = $(this).position().top;
        
        l = (new_w / old_w) * old_l;
        t = (new_h / old_h) * old_t;            
        mod_l = l % grid_x;  
        mod_t = t % grid_y;            
        new_l = (mod_l > snapThreshold) ? (l + (grid_x - mod_l)) : l - mod_l; 
        new_t = (mod_t > snapThreshold) ? (t + (grid_y - mod_t)) : t - mod_t;            
        if(old_w != new_w){        
            $(this).data("left", l);            
            $(this).css("left", snapWhileResizing ? new_l : l);                
        }
        if(old_h != new_h && $("#draggable").height() > 200){    
                    $(this).data("top", t);
            $(this).css("top", snapWhileResizing ? new_t : t);
        }            

        $(this).html(parseInt(l) + ' x ' + parseInt(t) + '<br />' + parseInt(new_l) + ' x ' + parseInt(new_t));    
    });    
});
#draggable .item { 
    width: 100px; 
    height: 100px; 
    padding: 0.5em; 
    border: 1px solid #555;
    background-color:#efefef;
    position: absolute;
    top: 0;
    cursor: move;
}
#draggable {
    position: relative;
    min-width: 200px;
    height: 100%;
    min-height: 200px;
    overflow: hidden;
    background-image: url(https://dl.dropboxusercontent.com/u/1094060/bg-dots.png);
    background-repeat: repeat;
    background-position: left top;
}
#label-old-dimen, #label-new-dimen {
    background-color: white;
    border: 1px solid gray;
}
.no-select {
    -webkit-user-select: none;  
    -moz-user-select: none;    
    -ms-user-select: none;      
    user-select: none;
} 
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<span id="label-new-dimen"></span>
<span id="label-old-dimen"></span>
<input type="checkbox" id="snapWhileResizing" name="snapWhileResizing" checked />
<label for="snapWhileResizing" class="no-select">snapWhileResizing</label>
<div id="draggable" class="ui-widget-content">
    <div class="item">Drag me around</div>
    <div class="item">Drag me around</div>
</div>

Setting snapWhileResizing = false will disable snap to grid when resizing the window.

Note: converting top and left values into percentage will not snap to any grid when resizing. Also, enabling snapWhileResizing will cause slight shifting in items positions when resizing the windows many times.

Aung Myo Linn
  • 2,820
  • 3
  • 27
  • 38