6

Ich habe folgende HTML:jQuery Ziehen mit Kollisionserkennung

<div class="list" id="list"> 
    <div class="item" id="i1">Item 1</div> 
    <div class="item" id="i2">Item 2</div> 
    <div class="item" id="i3">Item 3</div> 
</div> 
<div class="timeline" id="timeline"> 
</div> 

Was ich möchte in der Lage zu tun, mit jQuery, ist:

  1. der Lage sein, .item s vom #list ziehen in die #timeline
  2. .item s kann so oft wie erforderlich in die Timeline eingefügt werden, z. Es könnte 4 von Artikel #i1 in der Timeline sein.
  3. .item s in der Timeline dürfen nicht überlappen einander
  4. .item s entlang der Zeitleiste so lange an einer beliebigen Stelle positioniert werden, da sie alle anderen Elemente auf der Timeline nicht überlappen

So Ive gegangen für jQueryUIs Draggable und Droppable, und auch für die jQueryUI Draggable Collision Plugin gegangen.

$('#list .item').draggable({ 
    helper: 'clone', 
    revert: 'invalid', 
    //the following are for the jquery-ui-dragggable-collision plugin 
    obstacle: '#timeline .item', 
    preventCollision: true 
}); 
$('#timeline').droppable({ 
    accept: '.item' 
}); 

Mein Problem ist, dass die jQueryUI Ziehbare Kollision Plugin funktioniert nur, wenn Sie die ursprüngliche Div schleppen selbst und nicht ziehen einen Helfer:

Hier ist die jQuery Ich habe mit gestartet. Ich brauche Helfer, damit ich # 2 erreichen kann (mehrere Kopien eines Gegenstandes hinzufügen). Aber ich brauche etwas wie das Kollisions-Plugin, damit ich # 3 erreichen kann (Dinge, die sich nicht überschneiden).

Kennt jemand eine Lösung für dieses Problem? Gibt es ein weiteres Plugin, das Kollisionserkennung auf dem Helfer eines ziehbaren Objekts durchführt? Gibt es einen anderen Ansatz, mit dem ich versuchen kann, das zu erreichen, was ich erreichen möchte?

+0

Sie wahrscheinlich ziehbar als Live-Event verwenden müssen [http://stackoverflow.com/questions/1805210/jquery-drag-and-drop-using-live-events][1] [1]: http://stackoverflow.com/questions/1805210/jquery-drag-and-drop-using-live-events –

+0

@dwiekropki wie wird das mit der Kollisionserkennung umgehen? – Jimmery

+1

Möglicherweise müssen Sie warten, bis dieser Fehler behoben wurde: http://sourceforge.net/p/jquidragcollide/bugs/3/ – mccannf

Antwort

1

Hier ist ein Beispiel, das ich für diese Frage geschrieben habe und die ein einfaches Drag & Drop-Plugin mit Kollisionserkennung zeigt. Sie können Elemente auf einer Zeitleiste ablegen, solange Platz für das Objekt vorhanden ist, ohne dass es zu Überschneidungen kommt.

Es ist auf keinen Fall ein fertiges Produkt, aber hoffentlich wird zeigen, dass Code wie dieser ist nicht unglaublich komplex zu schreiben und zu versuchen, massive widersprüchliche Plugins zusammen zu hacken sind nicht immer die beste Option. Manchmal ist es am besten, bei Null anzufangen. Es macht Spaß und eine wirklich gute Art zu lernen.

Die jquery

/*----------ON DOCUMENT READY----------*/ 

$(document).ready(function(){ 

    $("#timeline").timeline({ 
     items : ".item" 
    }); 

}); 

/*----------THE TIMELINE PLUGIN----------*/ 

$.fn.timeline = function(options){ 

    var defaults = { 
     items : "div" 
    } 

    var options = $.extend(defaults,options) 

    return this.each(function(){ 

     //-----SETUP-----// 

     //define all the vars we will need later 
     var el   = $(this); 
     var items  = $(options.items); 
     var mousedown = false; 
     var dragging = false; 
     var activeItem = false; 
     var placedItems = new Array(); 

     //make everything unselectable so it dosne interfere with dragging 
     $("html").find("*").css({ 
      "user-select"   : "none", 
      "-moz-user-select"  : "none", 
      "-webkit-user-select" : "none", 
      "-ms-user-select"  : "none", 
      "-o-user-select"  : "none", 
     }).attr("unselectable","true").unbind("onselectstart"); 

     //-----EVENTS-----// 

     //log when the mouse is down anywhere on the doc 
     $(document).mousedown(function(){ 
      mousedown = true; 
     }); 

     //when the mouse is released 
     $(document).mouseup(function(e){ 
      //if was dragging an item attempt to place it 
      if(mousedown && dragging){ 
       placeItem(e); 
      } 
      //log that dragging has stopped 
      mousedown = false; 
      dragging = false; 
     }); 

     //log when the mouse is pressed over an item 
     items.mousedown(function(){ 
      dragging = true; 
      //clone the active item and hide it ready for dragging 
      activeItem = $(this).clone().appendTo("body").hide(); 
     }); 

     //when the mouse movers over the doc 
     $(document).mousemove(function(e){ 
      //if mouse was pressed over item attempt to drag 
      if(mousedown && dragging){ 
       dragItem(e); 
      } 
     }); 

     //-----FUNCTIONS-----// 

     //drag the item around the screen 
     function dragItem(e){ 

      //if no active item done do owt 
      if(!activeItem){ 
       return false; 
      } 

      //work out where the drag anchor is 
      var x = e.pageX-(activeItem.height()/2); 
      var y = e.pageY-(activeItem.width()/2); 

      //save the original position in case we cant place the item 
      if(!activeItem.origPos){ 
       activeItem.origPos = { 
        x : x, 
        y : y 
       } 
      } 

      //drag the item 
      activeItem.css({ 
       "position" : "absolute", 
       "top"  : y, 
       "left"  : x, 
       "z-index" : "999", 
       "opacity" : 0.6, 
       "display" : "block" 
      }); 

     } 

     //attempt to place the item 
     function placeItem(e){ 

      //if no active item dont do owt 
      if(!activeItem){ 
       return false; 
      } 

      //define som vars needed later on 
      var onTargetY = false; 
      var onTargetX = false; 
      var remove = false; 
      var collision = false; 

      //check if item is being relesed withing the timeline bounds 
      if(e.pageY > el.position().top && e.pageY < el.position().top+el.height()){ 
       onTargetY = true; 
      } 
      if(e.pageX > el.position().left && e.pageX < el.position().left+el.width()){ 
       onTargetX = true; 
      } 

      //if on target attempt to drop on timeline 
      if(onTargetX && onTargetY){ 

       //snap to the left or right if dropped at the left or right edges 
       var maxLeft = el.position().left; 
       var maxRight = el.position().left+el.width()-activeItem.width(); 
       x = e.pageX-(activeItem.width()/2); 
       if(x < maxLeft){ 
        x = maxLeft; 
       }else if(x > maxRight){ 
        x = maxRight; 
       } 

       //loop the items already on the timeline and check for collisions 
       $.each(placedItems,function(i,item){ 
        var itemMin = item.position().left; 
        var itemMax = item.position().left+item.width(); 
        if(x+activeItem.width() > itemMin && x < itemMax){ 
         collision = true; 
        } 
       }); 
       y = el.position().top; 

      } 

      //if there is a collision or the item is dropped outside the timeline 
      //set x and y back to original position and set removal flag to true 
      if(collision || !onTargetX || !onTargetY){ 
       x = activeItem.origPos.x; 
       y = activeItem.origPos.y; 
       remove = true; 
      //if dropped inside the timeline and no collisions add item to the 
      //array of items inside the timeline 
      }else{ 
       placedItems.push(activeItem); 
      } 

      //finally either animate the item back to where it started then remove it 
      //or snap it into the timeline in the space found 
      activeItem.animate({ 
       top  : y, 
       left : x 
      },{ 
       duration : 300, 
       queue : false, 
       complete : function(){ 

        //if remove flag set remove the item from the dom 
        if(remove){ 
         $(this).remove(); 
        } 

        //some tidying up 
        activeItem.css("opacity",1); 
        activeItem = false; 

       } 
      }); 

     } 

    }); 

} 

Die html

<div class="list" id="list"> 
    <div class="item item1">Item 1</div> 
    <div class="item item2">Item 2</div> 
    <div class="item item3">Item 3</div> 
</div> 

<div class="timeline" id="timeline"></div> 

Enjoy :).

2

Wenn Sie lieber ein jsfiddle zu, dass die jQueryUI Ziehbare Kollision Plugin verwendet, wie Sie vorgeschlagen, hier ist etwas zu spielen, um mit: Link to jsfiddle

Der Ansatz nutzt die Original-Helfer, um den Einsatz von Kollisions Funktionalität zu machen. Der Klon wird in der Startereignisfunktion erzeugt (und wieder im Stop-Ereignisse entfernt, falls das Ziehen nicht in einem erfolgreichen Rückgang geführt hat):

$(function(){ 
    var draggableSelector = ".list .item:not(.dropped)"; 
    var init = function() { 
     $(draggableSelector).each(function(i){ 
      $(this) 
       .draggable({ 
        //helper: 'clone', 
        revert: 'invalid', 
        start: function(event,ui) { 
         var $clone = ui.helper.clone(); 
         $clone 
          .removeClass("ui-draggable ui-draggable-dragging") 
          .insertAfter(ui.helper) 
         ; 
         $(this).data("clone",$clone); 
        }, 
        stop: function(event,ui) { 
         if($(".ui-draggable-dragging.dropped").length == 0) { 
          $(this).data("clone").remove(); 
         }; 
        }, 
        //the following are for the jquery-ui-draggable-collision plugin 
        refreshPositions: true, 
        obstacle: '.item.dropped', 
        preventCollision: true, 
       }) 
       .css("left", (($(this).width() + 5) * i) + "px") 
      ; 
     }); 

     $('.timeline').droppable({ 
      accept: '.item' 
      ,drop: function(event,ui) { 
       ui.draggable 
        .addClass("dropped") 
       ; 
       setTimeout(reinit, 500); 
      } 
     });     
    }; 

    var reinit = function() { 
     $(".list .item.ui-draggable").draggable("destroy"); 
     init(); 
    } 

    init(); 
}); 

Hoffnung, dass dies nützlich sein wird.