拖放在主要区域

时间:2016-05-27 08:08:48

标签: jquery html css jquery-ui drag-and-drop

如图1所示。 我有一个主div - 这是Droppable

使用Four Draggables,即 A B C 适合。 在将A,B或C div拖动到可放置的主要Div中时 - 它占据空间,如图2 所示(当我将A拖入主要部分时显示)。现在,如果我拖动另一个div(A,B或C),那么它应该占据空间的宽度大小。 (高度与主要部分相同)

图1 Figure 1

图2 enter image description here

现在,如果我拖动第4个可拖动的div,即名称适合,则应在主div内形成div,其宽度等于空间留在Main div的两个相邻Div中。

例如:。假设A和B之间(主要内部)和B和c之间有10px空间,空间是40px,所以如果我在A和B之间放置FIT,那么应该形成一个div,它们的空间差异是10px,同样40px div应该是在FIT的阻力下形成在B和C之间

它不应该挤压主要Div中的div,也不应该溢出主要的DIv

请告诉我如何将可拖动的A,B和C放置在用户定位位置的主div内,而不会干扰主div宽度。

我所做的是 我把div的A,B,C作为可拖动的

$(".classname").draggable({
  helper: 'clone',
  stop: function(event, ui) {
  }
});

和主div Droppable:

$(".maindivclass").droppable();

并且在可拖动的下降中,我在主div中制作那些Divs Draggable

$("#" + Dropped_div_id).draggable({
  axis: 'x',
  containment: "#Main_divID",
});

但是在A,B和C的下降时,它总是占据中心位置,现在我可以在主div内删除任意数量的div s。请告诉我如何使draggables定位User掉落的确切位置,并且所有div s的宽度总和应始终等于Main div宽度。也许Grid是解决方案,但我有动态宽度div要删除。

我经常研究并找到了一些东西 - 与我的任务相关的10%是http://gridster.net/ - 但这里的容器不是固定的高度或宽度。在我的情况下,所有div的高度都是相同的。只有宽度不同。

在评论中询问更多其他信息时

1)当A,B或C被拖放到Main时,您希望将该项目附加到Main。

2)当拖动另一个时,不应该在Main中已存在的其他div上删除/重叠。

3)在Fit的拖动上,Main中剩余的空间应该被占用。我的意思是应该根据Main div中剩下的空间创建具有相应宽度的div

2 个答案:

答案 0 :(得分:2)

那很有趣又脏。

让你成为一个基本上做两件事的例子:

  • 跟踪" Dropped"元素位置。
  • 当您删除FIT元素时,计算两个元素(或边)之间的距离。

JSnippet "Drag and Fit" :)

代码显然需要改进,但我相信它会帮助你走上正轨。

JS代码:

$(function() {
    var set = {
        appendClass: 'added',
        area: { s:"#droppable", w:0, left:0 },
        added : [],
    };
    $( ".exact-pos, #drag_fit" ).draggable({
        revert: "invalid",
        appendTo: ".wrap",
        helper: "clone"
    });
    $( "#droppable" ).droppable({
      accept:".exact-pos, .fill",
      drop: function( event, ui ) {
        var $area = $(this);
        var $origin_ele = $(ui.draggable).clone();
        var $ele_clone = $area.closest('.wrap').find('.ui-draggable-dragging').eq(0);
        var mes = {};
        set.area.w = $area.outerWidth();
        set.area.l = $area.offset().left;
        if (!$origin_ele.hasClass("fill")) { // Handle non fit
             mes = { // measure
               s:$origin_ele.attr('class') + " " + set.appendClass,
               l:$ele_clone.offset().left - set.area.l,
               w:$(ui.draggable).outerWidth(),
               r:0
             }
             //Check borders:
             if (mes.l < 0) { mes.l = 0; }
             if (mes.l + mes.w > set.area.w) { mes.l = set.area.w - mes.w; }
             //Set right side:
             mes.r = mes.l + mes.w;
             var revert = false;
             //Check overlaping left:
             $.each(set.added, function(index, ele) {
                if (mes.l >= ele.l && mes.l <= ele.r) {
                   mes.l = ele.r;
                   mes.r = mes.l + mes.w;
                }
             });
             //Check overlapping right: will revert
             $.each(set.added, function(index, ele) {
                if (mes.r >= ele.l && mes.r <= ele.r) {
                    revert = true;
                } else if (mes.r >= ele.r && mes.l <= ele.l) {
                    revert = true;
                } else if (mes.r > set.area.w) {
                    revert = true;
                }
             });
             //append or revert
             if (!revert) {
                ui.draggable.draggable('option','revert',false);  
                $area.append($origin_ele.addClass("added").css({"left":mes.l}));
                set.added.push($.extend(true, {}, mes));
             } else {
                ui.draggable.draggable('option','revert',true);  
             }
        } else {
            var f = { l:0,w:0,r:0 };
            var c = $ele_clone.offset().left - set.area.l + ($(ui.draggable).outerWidth() / 2);
            var betw = -1;
            var fleft = 0;
            var fright = 0;
            var revert = false;
            //sort by position:
            set.added.sort(function(a, b) {
                return a.l - b.l;
            });
            //after which elemnt:
            $.each(set.added, function(index, ele) {
                if (ele.r < c) { betw = index; }
             });
            //calc dim:
            if (betw == -1 && set.added.length == 0) {
                fright = set.area.w;
            } else if (betw == -1 && set.added.length > 0) {
                fright = set.added[0].l;
            } else if (betw == set.added.length - 1) {
                fleft = set.added[betw].r;
                fright = set.area.w;
            } else if (typeof set.added[betw + 1] != 'undefined') {
                fleft = set.added[betw].r;
                fright = set.added[betw + 1].l;
            }
            if (fright - fleft > 1) {
                f.l = fleft;
                f.w = fright - fleft;
                f.r = f.l + f.w;
            } else {
              revert = true;
            }
            //append or revert:
            if (!revert) {
                ui.draggable.draggable('option','revert',false);  
                $area.append($origin_ele.addClass("added").css({"left":f.l, width:f.w}).text(""));
                set.added.push($.extend(true, {}, f));
             } else {
                ui.draggable.draggable('option','revert',true);  
             }
        }
      }
    });
    $('#resetAll').click(function resetAll() {
        set.added = [];
        $(set.area.s).find('div').fadeOut(function(){ $(this).remove(); });
    });
});

答案 1 :(得分:2)

这个答案并不完全,但它非常实用,我计划更新它。目前这将执行以下功能:

  • 将A,B,C或Fit对象拖到主区域
  • 拖动/移动已在主区域中的对象
  • 将其他A,B,C或Fit对象拖入主区域但不在现有对象的顶部
  • 重置以进行更多测试
  • 如果将Fit对象拖入主区域,并且不存在其他对象,则会填充整个区域
  • 如果将适合对象拖动到包含对象的主区域,将确定对象与主区域边界之间的剩余空间,并将填充现有对象的左侧或右侧区域

当前工作示例:https://jsfiddle.net/Twisty/35nd6y3g/10/

<强> HTML

<div class="wrapper">
  <div class="box droppable" id="main">Main Div - droppable</div>
  <div class="box draggable new" id="a">drag A</div>
  <div class="box draggable new" id="b">drag B</div>
  <div class="box draggable new" id="c">drag C</div>
  <div class="box draggable new" id="fit" data-width="150">fit</div>
</div>
<br />
<button id="resetBtn">Reset</button>
<input type="text" id="leftDetails" style="width: 75%" />

<强> CSS

body {
  overflow: hidden;
}

.wrapper {
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
  height: 450px;
}

.box {
  border: 1px solid black;
  display: flex;
  //justify-content: center;
  align-items: center;
}

#main {
  position: relative;
  width: 150px;
  height: 450px;
}

#main .box {
  background: #9d9d9d;
}

#a {
  width: 30px;
  height: 450px;
}

#b {
  width: 45px;
  height: 450px;
}

#c {
  width: 75px;
  height: 450px;
}

#fit {
  width: 30px;
  height: 40px;
}

<强>的jQuery

$(document).ready(function() {
  console.log("Main: " + $("#main").position().left + " Drag A: " + $("#a").position().left + "Drag B: " + $("#b").position().left + " Drag C: " + $("#c").position().left);
  var mainBoxes = {};
  $("#resetBtn").click(function() {
    $("#main").find("div.box").remove();
    mainBoxes = {};
  });
  var dragOrig;
  $(".draggable").draggable({
    containment: "#main",
    axis: "x",
    revert: true,
    start: function(e, ui) {
      dragOrig = ui.position;
    },
    drag: function(e, ui) {
      $("#leftDetails").val(ui.helper.text() + " pos left: " + ui.position.left + " off left: " + ui.offset.left);
      if (Object.keys(mainBoxes).length === 0) {
        return;
      }
      var offLeft = ui.offset.left - $("#main").offset().left;
      var offRight = offLeft + ui.helper.width();
      //var offMouse = e.clientX - $("#main").offset().left;
      $.each(mainBoxes, function(k, v) {
        if (offLeft >= v.left && offLeft <= v.right) {
          ui.position.left = ui.position.left + v.right;
          console.log("Info: Left Edge collided with ", k, ui.position);
        }
        if (offRight > v.left && offRight < v.right) {
          //ui.position.left = ui.position.left + (v.left - ui.helper.width());
          ui.position.left = ui.position.left + v.right;
          console.log("Info: Right Edge collided with ", k, ui.position);
        }
      });
    },
  });
  $(".droppable").droppable({
    hoverClass: "hover",
    accept: ".box",
    drop: function(event, ui) {
      // add functionality here
      //var pos = ui.position;
      var off = ui.offset;
      var c = $("#main .box").length + 1;
      var $newBox = ui.draggable.clone();
      if (ui.draggable.attr("id") === "fit") {
        console.log("Info: Adding 'fit' class");
        $newBox.addClass("fit");
        if (Object.keys(mainBoxes).length === 0) {
          console.log("Info: No other boxes found. Set Max Width.");
          $newBox.css({
            width: "150px",
            height: "450px",
            left: "-1px"
          });
        } else {
          var lefts = Object.keys(mainBoxes).map(function(k) {
            return mainBoxes[k].left;
          });
          var rights = Object.keys(mainBoxes).map(function(k) {
            return mainBoxes[k].right;
          });
          var minLeft = Math.min.apply(null, lefts);
          var maxRight = Math.max.apply(null, rights);
          if ((ui.offset.left - $("#main").offset().left) + ui.helper.width() < minLeft) {
            console.log("Info: 'fit' dropped left of boxes.");
            $newBox.css({
              width: minLeft + "px",
              height: "450px",
              left: "-1px"
            });
            $newBox.data("width", minLeft);
            console.log("Info: ", minLeft, maxRight, $newBox[0]);
          }
          if ((ui.offset.left - $("#main").offset().left) > maxRight) {
            console.log("Info: 'fit' dropped right of boxes.");
            $newBox.css({
              width: (150 - maxRight) + "px",
              height: "450px",
              left: maxRight + "px"
            });
            $newBox.data("width", 150 - maxRight);
            console.log("Info: ", minLeft, maxRight, (450 - maxRight), $newBox[0]);
          }
        }
      } else {
        $newBox = ui.draggable.clone();
        if ($newBox.hasClass("new")) {
          $newBox.removeClass("new");
        } else {
          return;
        }
      }
      console.log("Info: Removing .draggable");
      $newBox.removeClass("draggable");
      console.log("Info: Setting ID = box" + c);
      $newBox.attr("id", "box" + c);
      $newBox.draggable({
        containment: "#main",
        axis: "x",
        drag: function(e, ui) {
          if (Object.keys(mainBoxes).length === 0) {
            return;
          }
          var offLeft = ui.offset.left - $("#main").offset().left;
          var offRight = offLeft + ui.helper.width();
          $.each(mainBoxes, function(k, v) {
            if (k == ui.helper.attr("id")) {
              return false;
            }
            if (offLeft > v.left && offLeft < v.right) {
              ui.position.left = v.right;
              console.log("Left Edge Collison with ", k);
            }
            if (offRight > v.left && offRight < v.right) {
              ui.position.left = v.left - ui.helper.width();
              console.log("Info: Right Edge Collision with ", k);
            }
          });
        },
        stop: function(e, ui) {
          mainBoxes[ui.helper.attr("id")] = {
            left: ui.offset.left - $("#main").offset().left,
            right: (ui.offset.left - $("#main").offset().left) + ui.helper.width()
          };
          console.log("Info: Updating ", ui.helper.attr("id"), mainBoxes);
        }
      });
      if ($newBox.draggable("instance") !== "undefined") {
        console.log("box" + c + ": is draggable.");
      }
      $newBox.css({
        left: $newBox.hasClass("fit") ? $newBox.css("left") : (off.left - $("#main").offset().left) + "px",
        top: "-1px",
        position: 'absolute',
        height: "450px",
        width: $newBox.hasClass("fit") ? $newBox.css("width") : ui.draggable.width() + "px"
      });
      console.log("box" + c + ": ", $newBox[0], " now being appended.");
      $("#main").append($newBox);
      mainBoxes['box' + c] = {
        'width': $newBox.width(),
        'left': off.left - $("#main").offset().left,
        'right': (off.left - $("#main").offset().left) + $newBox.width()
      };
      console.log("Added: ", $newBox.attr("id"), mainBoxes);
    }
  });
});

如上所述,这几乎已经完成。由于使用了视口单元,定位正在被抛弃。这不是一个很好的用例,但它是我从提供的小提琴开始的。

为了跟踪对象,我创建了一个名为mainBoxes的对象。当对象被放入droppable时,这会更新。每个索引都包含从偏移左侧位置值填充的leftrightwidthmainBoxes is used for collision detection when dragging further objects and to calculate the width for适合`对象。

我们有2个拖动方案,将新项目拖动到主要区域或移动已存在的项目。当我们拖放一个新项目时,它会被更新,可拖动被破坏,可拖动会被新属性重置,我们会将其附加到#main。默认情况下,可拖动不附加元素,只是更改它在页面上的位置。因此,div将被移动,但永远不会是#main的孩子。

视口单元为碰撞检测和防止将对象拖动到另一个现有对象上带来了挑战。我已经向控制台添加了许多细节,以便清楚地了解所有活动。我打算通过将所有长度和位置转换为像素单位来解决这个问题。

这应该让你去。我还发现了以下插件:https://sourceforge.net/projects/jquidragcollide/我可能会调查这是否是一个更好的工具。