JQuery UI: drag and drop multiple objects

My scenario: A container (div) with some objects (div). Objects can move inside the container (with the containment option set to parent ).

Now I need to move several objects at once. For this I found this useful plugin. Unfortunately this plugin does not handle the containment property as reported here .

My test on JSFiddle , disable this feature

$(".obj").on("drag", function(ev, ui)

      

Click objects to activate multi-drag. I managed to block the drag event.

My test problem:

At this point, I don't know how to activate drag and drop.

Note

I probably need to know the direction of the drag (with start-stop events). But at this point, I cannot stop the drag.

My solutions

But K Scandrett's solution is also very good. It is very difficult to apply in my particular case, which was simplified in this example.

Always using this plugin to enable multiple drag and drop. Every time I select multiple objects and drag them, in the dragstart event I do this (change the holding property of the object depending on the position of the selected objects):

//1024 * 648 is the width of the container
$(obj).unbind("dragstart").bind("dragstart" , function(ev, ui){

    var dimObjFirst = {
        x : parseInt($(this).css("left")),
        y : parseInt($(this).css("top"))
    };
    if($("blablabla > div.ui-selected").length > 1){

        var minLeft = 1024,maxRight = 0,minTop = 648,maxDown = 0;

        $("blablabla > div.ui-selected").each(function(){
            var elem = $(this);
            var dim = {
                w : parseInt(elem.css("width")),
                h : parseInt(elem.css("height")),
                l : parseInt(elem.css("left")),
                t : parseInt(elem.css("top")),
            };
            if(dim.l < minLeft) minLeft = dim.l;
            if(dim.l + dim.w > maxRight) maxRight = dim.l + dim.w;
            if(dim.t < minTop) minTop = dim.t;
            if(dim.t + dim.h > maxDown) maxDown = dim.t + dim.h;
        });

        var offsetContainer = $(".container").offset();
        $(this).draggable( "option" , "containment" , [
          (dimObjFirst.x - minLeft) + parseInt(offsetContainer.left),
          (dimObjFirst.y - minTop) + parseInt(offsetContainer.top),
          (dimObjFirst.x + (1024 - maxRight)) + parseInt(offsetContainer.left),
          (dimObjFirst.y) + (648 - maxDown) + parseInt(offsetContainer.top)
        ]);
    }           
});

$(obj).unbind("dragstop").on("dragstop", function(ev, ui) {

    if($("blablabla > div.ui-selected").length > 1) {
        $("blablabla > div.ui-selected").each(function(){
            $(this).draggable( "option" , "containment" , "parent" );
        });
    }
});

      

And add this line of code this._setContainment();

to the top of _mouseDrag

the jQuery UI plugin function .

+3


source to share


1 answer


Sounds like a fun project, so ....

I implemented it with a bounding box (similar to Twisty's comment).

I figured it was done in such a way that it would constrain all multiple selected objects to the bounds of the container.

The bounding box I colored so you can visualize how it works. Of course, you will probably leave it transparent in practice.



Code comments are built in, but are happy to answer any code questions if you have them.

No plugins were used (only jQuery and jQueryUI).

var disableclick = false;

var boundingBoxTop, boundingBoxBottom, boundingBoxLeft, boundingBoxRight;
var $container = $("#container");
var containerHeight = $container.height();
var containerWidth = $container.width();
var containerTop = $container.offset().top;
var containerLeft = $container.offset().left;

// add the bounding box to the container and make it draggable
var $boundingBox = $("<div id='boundingBox' style='position:absolute;background-color:#fcf5d4'>").prependTo($container);

$boundingBox.draggable({
  grid: [10, 10],
  containment: "parent",
  stop: function( event, ui ) {
    disableclick = true; // don't want to toggle selection when dragging
    setTimeout(function(e){
    	disableclick = false;
    },200);
  },
});

$(".obj").click(function(e) {

  if (!disableclick) {

    var $objClicked = $(this);
    $objClicked.toggleClass("ui-selected");

    var $selectedItems = $("#container .ui-selected");

    // move any items in bounding box back into container before we re-process them
    $boundingBox.find('*').each(function() {
      var $this = $(this);

      if ($this.parent().is($boundingBox)) {
        // adjust its positioning to be relative to the container
        $this.css("top", ($this.offset().top - containerTop) + "px");
        $this.css("left", ($this.offset().left - containerLeft) + "px");
        $container.append($this); // return it to the container
      }
    });

    // reversing co-ords to what might be expected here so that we can scale them back to what they need to be for a bounding box
    boundingBoxTop = containerHeight;
    boundingBoxBottom = 0;
    boundingBoxLeft = containerWidth;
    boundingBoxRight = 0;

    // find the bounds of the smallest rectangle that will cover all the currently selected objects
    $selectedItems.each(function() {
      var $this = $(this);

      var top = $this.offset().top - containerTop;
      var bottom = $this.offset().top - containerTop + $this.height();
      var left = $this.offset().left - containerLeft;
      var right = $this.offset().left - containerLeft + $this.width();

      boundingBoxTop = (top < boundingBoxTop) ? top : boundingBoxTop;
      boundingBoxBottom = (bottom > boundingBoxBottom) ? bottom : boundingBoxBottom;
      boundingBoxLeft = (left < boundingBoxLeft) ? left : boundingBoxLeft;
      boundingBoxRight = (right > boundingBoxRight) ? right : boundingBoxRight;
    });

    // get the height and width of bounding box
    var boundingBoxHeight = boundingBoxBottom -= boundingBoxTop;
    var boundingBoxWidth = boundingBoxRight -= boundingBoxLeft;

    if (boundingBoxBottom > 0) // will be negative when nothing is selected
    {
      // update the bounding box with its new position and size
      $boundingBox.css("top", boundingBoxTop + "px");
      $boundingBox.css("left", boundingBoxLeft + "px");
      $boundingBox.css("width", boundingBoxWidth + "px");
      $boundingBox.css("height", boundingBoxHeight + "px");

      // add each selected item to the bounding box so we can drag the box with them in it
      $selectedItems.each(function() {
        var $this = $(this);

        // correct the item position to be relative to the bounding box
        $this.css("top", ($this.offset().top - containerTop - boundingBoxTop) + "px");
        $this.css("left", ($this.offset().left - containerLeft - boundingBoxLeft) + "px");

        $boundingBox.append($this); // add item to bounding box
      });
    }
  }
});
      

#container {
  position: absolute;
  width: 400px;
  height: 150px;
  background: #eee;
}

.obj {
  position: absolute;
  background: #ccc;
}

.ui-selected {
  background: #1C90F3;
}

#obj1 {
  width: 20px;
  height: 20px;
  left: 20px;
  top: 20px;
}

#obj2 {
  width: 20px;
  height: 20px;
  left: 100px;
  top: 20px;
}

#obj3 {
  width: 20px;
  height: 20px;
  left: 20px;
  top: 100px;
}

#obj4 {
  width: 20px;
  height: 20px;
  left: 100px;
  top: 100px;
}
      

<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/jquery-3.2.1.min.js" />

<div style="margin-bottom:10px">
  Click boxes to select/deselect multiple items.<br/>Drag to move selection.
</div>

<div id="container">
  <div class="obj" id="obj1"></div>
  <div class="obj" id="obj2"></div>
  <div class="obj" id="obj3"></div>
  <div class="obj" id="obj4"></div>
</div>
      

Run codeHide result


+4


source







All Articles