6

ho il seguente codice HTML:jQuery trascinamento con Collision Detection

<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> 

Quello che voglio essere in grado di fare, con jQuery, è:

  1. essere in grado di trascinare .item s dal #list nel #timeline
  2. .item s possono essere inseriti nella timeline tutte le volte necessarie, ad es. ci potrebbero essere 4 dell'articolo #i1 nella timeline.
  3. .item s nella timeline non devono sovrapporsi tra loro
  4. .item s possono essere posizionati in qualsiasi luogo lungo la linea temporale fintanto che non si sovrappongono tutti gli altri elementi sulla timeline

Così Ive andato per jQueryUI's Draggable and Droppable, e anche andato per il jQueryUI Draggable Collision Plugin.

Ecco l'jQuery ho iniziato con:

$('#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' 
}); 

mio problema è che il jQueryUI Draggable Collision plugin funziona solo quando si sta trascinando l'originale Div in sé, e non trascinando un aiutante. Ho bisogno di aiutanti per ottenere il n. 2 (aggiungendo più copie di un articolo). Ma ho bisogno di qualcosa come il Collision Plugin, così posso ottenere il n. 3 (elementi non sovrapposti).

Qualcuno sa di una soluzione a questo problema? Esiste un altro plug-in che rileva la collisione sull'helper di un oggetto trascinabile? C'è un altro approccio che posso provare ad ottenere ciò che voglio raggiungere?

+0

probabilmente è necessario utilizzare trascinabili come evento live [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 come sarà questo il rilevamento delle collisioni? – Jimmery

+1

Potrebbe essere necessario attendere la correzione di questo errore: http://sourceforge.net/p/jquidragcollide/bugs/3/ – mccannf

risposta

1

Ecco un esempio che ho scritto per questa domanda che mostra un semplice plugin drag and drop con rilevamento delle collisioni. Consente di rilasciare elementi su una timeline finché c'è spazio per l'elemento di esistere senza sovrapposizioni.

Non è affatto un prodotto finito, ma si spera che mostrerà che il codice come questo non è incredibilmente complesso da scrivere e tentare di hackerare insieme enormi plugin in conflitto non sono sempre l'opzione migliore. A volte è meglio iniziare da zero. È divertente e un ottimo modo per imparare.

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; 

       } 
      }); 

     } 

    }); 

} 

il codice 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

Se si preferisce un jsfiddle a che utilizza il jQueryUI Draggable collisione Plugin come lei ha suggerito, qui è qualcosa di giocare con: Link to jsfiddle

L'approccio utilizza l'assistente originale per fare uso di funzionalità di collisione. Il clone è generato in funzione di evento di avvio (e rimosso di nuovo in caso di arresto nel caso in cui il trascinamento non ha portato a un calo di successo):

$(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(); 
}); 

speranza che questo possa essere utile.