How to make jquery center an element while dragging it and snapping to another container?

I need square draggable objects (in this case, only <td> tags with numbers in them) in order to be able to snap to some empty cells of the table and snap to the center of these cells (empty td boxes), and not the (outer) edge of these cells, which apparently does by default.

Here is my script .:

 <script type="text/javascript"> $(document).ready(function () { $(".inputs div").draggable( { snap: ".spaces" }); }); </script> 

EDIT: Here is the whole file

  <!DOCTYPE html> <head> <title>Draggable</title> <script type="text/javascript" src="jquery-1.7.2.min.js"></script> <script type="text/javascript" src="jquery-ui-1.8.21.custom.min.js"></script> <script type="text/javascript" src="jquery.ui.touch-punch.min.js"></script> <style> .block { z-index:9999; cursor:move; } li { list-style:none; } tr { border: 2px solid black; } table { border: 2px solid black; } .inputs div { float:left; background-color:#FFFFFF; color:#004E66; font-size:x-large; margin:2px; padding:20px; border:1px solid black; } .spaces td { background-color:#666666; margin:2px; padding:36px; border:2px solid black; } </style> </head> <body> <form id="form1"> <div class="inputs"> <div>1</div> <div>2</div> <div>3</div> <div>4</div> <div>5</div> <div>6</div> </div> <br/> <table class="spaces"> <tr> <td></td> <td></td> <td></td> </tr> <tr> <td></td> <td></td> <td></td> </tr> </table> </form> <!-- here we are telling jquery to make each element inside of class 'inputs' draggable --> <script type="text/javascript"> $(document).ready(function () { $(".inputs div").draggable( { snap: ".spaces" }).center(); }); </script> 

Here's a rough textual illustration of what's going on.

  ----- + --------- +
 XXXXXXXXXXXX X |
      |  |
      |  Y x |
      |  X |
 ----- + ------- + X |
      |  X |
  • if the above field is a cell td in the right corner of the top row tr
  • then X is the place where the elements are currently sticking out (obviously, it's not that big, I just show the places where it holds ... in fact, I removed some of X to show how it snaps into a corner when he reaches a certain proximity to him ...)
  • basically, this model demonstrates that only the outer edges of the table have β€œgravity” in relation to the dragged item. What I really want to do is bind to the td cells with repulsion to all edges, and not with attraction to the outside.
  • Y is the desired snap location for the item to be dragged.
  • Finally, to explain the reasons, I would like the element to snap into place with some kind of transition, rather than a sharp jump ...
+4
source share
6 answers

I believe that this is what you want.

Obviously, you can change the positioning if you want, and it suits you better.

Demo here: DEMO

 $(document).ready(function () { $(".inputs div").draggable( { opacity: .4, create: function(){$(this).data('position',$(this).position())}, cursorAt:{left:15}, cursor:'move', start:function(){$(this).stop(true,true)} }); $('.spaces').find('td').droppable({ drop:function(event, ui){ snapToMiddle(ui.draggable,$(this)); } }); }); function snapToMiddle(dragger, target){ var topMove = target.position().top - dragger.data('position').top + (target.outerHeight(true) - dragger.outerHeight(true)) / 2; var leftMove= target.position().left - dragger.data('position').left + (target.outerWidth(true) - dragger.outerWidth(true)) / 2; dragger.animate({top:topMove,left:leftMove},{duration:600,easing:'easeOutBack'}); } 
+11
source

One note on the snapToMiddle function:

To make it work correctly, I had to change it to>

 function snapToMiddle(dragger, target){ var offset = target.offset(); var topMove = (target.outerHeight(true) - dragger.outerHeight(true)) / 2; var leftMove= (target.outerWidth(true) - dragger.outerWidth(true)) / 2; dragger.offset({ top: topMove + offset.top, left: leftMove + offset.left }) } 

In addition, I created an array that connected the drag and drop to the dropper and in the reSize window. I make sure that all my rocking chairs do not wander:

 $( window ).resize(function() { for( i = 0 ; i < assc.length - 1 ; i++ ) { var drp = assc[i].drop; var drg = assc[i].drag; snapToMiddle(drg,drp); } }); 
+5
source

http://jsfiddle.net/vtdhV/

I created a fiddle that solves your problem .. sort of (if I understand correctly).

Red divs are concentrated within td s, and instead you are attached to them. Just delete the border and it will appear to snap to the center of td. The character .draggable will cause the dragged objects to be attached to any edge, and not to all edges at the same time.

If this is not enough, you may need to implement a call handler for .stop , which will adjust the position of the element depending on your expectations.

+1
source

You need to specify a target that is the same size as your dragged item. It doesn't really matter if your drags are always the same size. Just add an empty, absolutely positioned div to your cell and adjust your CSS so that it is right in size and centered. Then set the snap selector as a div. To just snap the inside of your snap, set snapMode to "inner" .

 $(".inputs div").draggable({ snap: ".spaces td div", snapMode: "inner" }); 

But if the size of your draggable objects can be different, you will need to resize and reposition your target objects each time you drag an item. Do this on a mousedown draggable (use mousedown because dragstart too late and doesn't work):

 $(".inputs div").draggable({ snap: ".spaces td div", snapMode: "inner", }).mousedown(function(){ var targets = $(".spaces td div"); targets.height(this.offsetHeight); targets.width(this.offsetWidth); targets.each(function(){ $(this).position({ of: this.parentNode }); }); }); 

http://jsfiddle.net/gilly3/mPr3A/

+1
source

Add a div to these tds and center it, specifying a fixed width and height for the tds and newly added divs. Then drag and drop to these divs.

 $(document).ready(function () { $('<div></div>').appendTo('.spaces td'); $(".inputs div").draggable({ snap: ".spaces td div", snapMode:'inner' }); }); 

Also css for tds and divs will be next.

 .block { z-index:9999; cursor:move; } .productCode { } li { list-style:none; } tr { border: 2px solid black; } table { border: 2px solid black; } .inputs div { float:left; background-color:#FFFFFF; color:#004E66; font-size:x-large; margin:2px; padding:20px; border:1px solid black; } .spaces td { background-color:#666666; width:80px; height:80px; border:2px solid black; } .spaces td div { margin:0 auto; width:50px; height:70px; } 

Demo Screenshot - http://jsfiddle.net/nsjithin/u25Bs/1/

0
source

If I understood correctly, replace the current script as follows:

 $(document).ready(function () { // create a bunch of invisible divs var divs = $('<div></div><div></div><div></div><div></div>'); // make them 2/2 and add them to the existing tds divs.css({ width:'50%', float:'left' }).appendTo('.spaces td'); // snap to everything $(".inputs div").draggable({snap: ".spaces td, .spaces td div" }).center(); }); 

If I didn’t just say, and I will fix it.

-1
source

All Articles