Michael Emerson
Michael Emerson

Reputation: 1813

jQuery draggable moves when dropped

I have set up a simple drag and drop interface which implements the clone functionality. The issue I have is that when the element is dragged to the main canvas and then dropped, it suddenly shifts to the right, rather than dropping exactly where I drag it.

Here is the javascript:

$(function() {
  var x = null;

  $("#draggable").draggable({
    helper: 'clone',
    cursor: 'move',
    snap: '.snap-target'
  });

  $("#canvas").droppable({
    drop: function(e, ui) {
      if ($(ui.draggable)[0].id != "") {
        x = ui.helper.clone();
        ui.helper.remove();
        x.draggable({
          helper: 'original',
          containment: '#canvas',
          snap: '.snap-target'
        });
        x.appendTo('#canvas');
      }
    }
  });

});

I have created a jsfiddle:

https://jsfiddle.net/kuyn6gmc/

If you try and drag the blue box into the main canvas then release the mouse you will see how the box "pops" to the right slightly. When you move the box within the canvas, it works fine. On the fiddle it's not as bad as when it's full width on a browser, I think it's relative to the total width of the viewport.

If anyone knows why this may be happening I would appreciate it :)

Thank you Michael

Upvotes: 1

Views: 1192

Answers (2)

Josh Crozier
Josh Crozier

Reputation: 241248

The reason this is occuring is because the draggable element is absolutely positioned relative to the viewport while it is being dragged. Once the element is appended, the positioning is relative to the #canvas element (because of position: relative), which is why the element moves when you drop it.

As the other answer suggests, you could remove position: relative from the element, however, that probably won't work in all cases. I'd suggest taking the positioning of the element into account before appending the element.

Updated Example

For instance, you could subtract the offset top/left positioning, as well as the width of the border. In doing so, the #canvas element can still be relatively positioned.

var canvasOffset = {
  'top': parseInt($(this).offset().top, 10) + parseInt($(this).css('border-top-width'), 10),
  'left': parseInt($(this).offset().left, 10) + parseInt($(this).css('border-left-width'), 10)
}

$draggble.css({
  "top": parseInt($draggble.css('top'), 10) - canvasOffset.top + 'px',
  "left": parseInt($draggble.css('left'), 10) - canvasOffset.left + 'px'
}).appendTo('#canvas');

Upvotes: 7

dokgu
dokgu

Reputation: 6080

You have to put position: relative to the body instead of the canvas.

    .draggable { padding: 5px; float: left; margin: 0 10px 10px 0; font-size: .9em; position: relative; }
    .small { border: 1px solid slateblue; width: 115px; height: 115px; background: #c5cae9 }
    .ui-widget-header p, .ui-widget-content p { margin: 0; }
    .text-box { text-align: center; vertical-align: middle; }
    body { font-family: 'Helvetica Neue', Helvetica, Arial, serif; font-size: 13px }
    #canvas { width: 600px; height: 300px; border: 1px solid #cccccc; margin: auto;
        clear: both; }
    .draggable-selectors { margin: 10px auto; width: 1000px; }
    body { position: relative; margin: 0; }

<body class='snap-target'>

Upvotes: 3

Related Questions