2012-04-05 9 views
14

Sto lavorando su come mostrare le guide quando si spostano scatole come in Google Documenti. Preferirei un codice open source o qualsiasi tipo di guida prima di iniziare a scrivere la mia.Guide quando si spostano scatole jquery-trascinabili

  1. Non ho bisogno di trascinare il drag-n-drop su più finestre del browser, quindi non ho bisogno di HTML5 Drag-n-Drop.
  2. Inoltre sto usando jquery-ui-draggable per le scatole.

enter image description here

risposta

27

jQuery UI ha questo già integrato, vedere questa demo: http://jqueryui.com/demos/draggable/#snap-to

se insistete sui guidlines si sarebbe forse dovuto sborsare jQueryUI o guardare il sorgente e vedere se puoi estenderlo


in alternativa, si può solo aggiungere le proprie funzioni di aggancio-in cima jQuery UI, ho giocato con lui per un po ', e mentre non sembra divertente, almeno non lo fa anche sembra essere molto difficile.

è possibile visualizzare l'esempio su jsfiddle: http://jsfiddle.net/x7uMh/103/ aggiornamento: questo funziona ~ jQuery 1.9 + jQueryUI 1.9. si rompe nel più nuovo jquery + ui. non può essere disturbato per vedere quale sia esattamente il problema, in genere i suoi soli problemi minori però. solo nel caso che il sito va mai giù, ecco il codice:

css

body{ 
    font-family: courier new, courier; 
    font-size: 12px; 
} 

.draggable{ 
    border: 1px solid #ccc; 
    display: inline-block; 
    cursor: move; 
    position: absolute;   
} 

.guide{ 
    display: none; 
    position: absolute; 
    left: 0; 
    top: 0; 
} 

#guide-h{ 
    border-top: 1px dashed #55f; 
    width: 100%; 
} 

#guide-v{ 
    border-left: 1px dashed #55f; 
    height: 100%; 
} 
​ 

html

<div class="draggable">drag me!</div> 
<div class="draggable">you can drag me too, if you like</div> 
<div class="draggable">hep hep</div> 

<div id="guide-h" class="guide"></div> 
<div id="guide-v" class="guide"></div> 
​ 

javascript (assicurarsi di includere jQuery + jQuery UI)

var MIN_DISTANCE = 10; // minimum distance to "snap" to a guide 
var guides = []; // no guides available ... 
var innerOffsetX, innerOffsetY; // we'll use those during drag ... 

$(".draggable").draggable({ 
    start: function(event, ui) { 
     guides = $.map($(".draggable").not(this), computeGuidesForElement); 
     innerOffsetX = event.originalEvent.offsetX; 
     innerOffsetY = event.originalEvent.offsetY; 
    }, 
    drag: function(event, ui){ 
     // iterate all guides, remember the closest h and v guides 
     var guideV, guideH, distV = MIN_DISTANCE+1, distH = MIN_DISTANCE+1, offsetV, offsetH; 
     var chosenGuides = { top: { dist: MIN_DISTANCE+1 }, left: { dist: MIN_DISTANCE+1 } }; 
     var $t = $(this); 
     var pos = { top: event.originalEvent.pageY - innerOffsetY, left: event.originalEvent.pageX - innerOffsetX }; 
     var w = $t.outerWidth() - 1; 
     var h = $t.outerHeight() - 1; 
     var elemGuides = computeGuidesForElement(null, pos, w, h); 
     $.each(guides, function(i, guide){ 
      $.each(elemGuides, function(i, elemGuide){ 
       if(guide.type == elemGuide.type){ 
        var prop = guide.type == "h"? "top":"left"; 
        var d = Math.abs(elemGuide[prop] - guide[prop]); 
        if(d < chosenGuides[prop].dist){ 
         chosenGuides[prop].dist = d; 
         chosenGuides[prop].offset = elemGuide[prop] - pos[prop]; 
         chosenGuides[prop].guide = guide; 
        } 
       } 
      }); 
     }); 

     if(chosenGuides.top.dist <= MIN_DISTANCE){ 
      $("#guide-h").css("top", chosenGuides.top.guide.top).show(); 
      ui.position.top = chosenGuides.top.guide.top - chosenGuides.top.offset; 
     } 
     else{ 
      $("#guide-h").hide(); 
      ui.position.top = pos.top; 
     } 

     if(chosenGuides.left.dist <= MIN_DISTANCE){ 
      $("#guide-v").css("left", chosenGuides.left.guide.left).show(); 
      ui.position.left = chosenGuides.left.guide.left - chosenGuides.left.offset; 
     } 
     else{ 
      $("#guide-v").hide(); 
      ui.position.left = pos.left; 
     } 
    }, 
    stop: function(event, ui){ 
     $("#guide-v, #guide-h").hide(); 
    } 
}); 


function computeGuidesForElement(elem, pos, w, h){ 
    if(elem != null){ 
     var $t = $(elem); 
     pos = $t.offset(); 
     w = $t.outerWidth() - 1; 
     h = $t.outerHeight() - 1; 
    } 

    return [ 
     { type: "h", left: pos.left, top: pos.top }, 
     { type: "h", left: pos.left, top: pos.top + h }, 
     { type: "v", left: pos.left, top: pos.top }, 
     { type: "v", left: pos.left + w, top: pos.top }, 
     // you can add _any_ other guides here as well (e.g. a guide 10 pixels to the left of an element) 
     { type: "h", left: pos.left, top: pos.top + h/2 }, 
     { type: "v", left: pos.left + w/2, top: pos.top } 
    ]; 
} 

​ 

speranza che aiuti, meglio, hansi.

+2

per riferimento: Ho giocato con un po 'di più, v'è un molto più versione più elegante per risolvere questo "ciclo di ricerca delle guide" interno semplicemente usando la stessa funzione computeGuides() sul target di trascinamento corrente. consente di aggiungere più marcatori (ad esempio allineare tramite centri, linee di base, ecc.) molto più facilmente e con minore ridondanza. dai un'occhiata qui: http://jsfiddle.net/kritzikratzi/x7uMh/1/ – kritzikratzi

+0

Sembra che funzionerà, ma il collegamento jsfiddle no. Ma ci proverò di sicuro. –

+0

ho provato solo sul chrome più recente, potrebbe essere necessario fare alcune adozioni in altri browser ... – kritzikratzi

10

Ho creato un semplice esempio con solo la linea di confine accanto alla casella trascinabile. Si presenta quando trasciniamo sulla scatola. View demo here

HTML:

<div id="canvas"> 
    <div id="box"> 
     <span class="topline"></span> 
     <span class="rightline"></span> 
     <span class="botline"></span> 
     <span class="leftline"></span> 
    </div> 
</div> 

CSS:

#canvas {width: 1000px;height: 800px;} 
.topline{ 
    position:absolute; 
    width: 1000%; 
    border-top:1px red dotted; 
    display:none; 
    vertical-align::middle; 
    margin-top:-7px; 
    margin-left:-250%; 
} 
.botline{ 
    position:absolute; 
    width: 1000%; 
    bottom:-2px; 
    border-bottom:1px red dotted; 
    display:none; 
    vertical-align::middle; 
    margin-top:500px; 
    margin-left:-250%; 
} 
.leftline{ 
    position:absolute; 
    height: 1000%; 
    left:-2px; 
    border-left:1px red dotted; 
    display:none; 
    vertical-align::middle; 
    margin-top:-250%; 

} 
.rightline{ 
    position:absolute; 
    height: 1000%; 
    right:-2px; 
    border-right:1px red dotted; 
    display:none; 
    vertical-align::middle; 
    margin-top:-250%; 

} 
#box { 
    cursor: move; 
    border:1px solid black; 
    width:150px; 
    height:100px; 
    min-width:80px; 
    min-height:80px; 
    padding:5px; 
    background-color:#1196c1; 

} 

JavaScript:

$(function() { 
    $("#box").draggable({ 
     containment: "#canvas", 
     drag: function() { 
      $(this).find($('.topline')).css('display', 'block'); 
      $(this).find($('.rightline')).css('display', 'block'); 
      $(this).find($('.botline')).css('display', 'block'); 
      $(this).find($('.leftline')).css('display', 'block'); 
     }, 
     start: function() { 
      $(this).find($('.topline')).css('display', 'block'); 
      $(this).find($('.rightline')).css('display', 'block'); 
      $(this).find($('.botline')).css('display', 'block'); 
      $(this).find($('.leftline')).css('display', 'block'); 
     }, 
     stop: function() { 
      $(this).find($('.topline')).css('display', 'none'); 
      $(this).find($('.rightline')).css('display', 'none'); 
      $(this).find($('.botline')).css('display', 'none'); 
      $(this).find($('.leftline')).css('display', 'none'); 
     } 
    }); 
}); 
+2

Non inserire solo un collegamento in una risposta. * QUANDO * il link interrompe la tua risposta sarà inutilizzabile. Fornire la fonte nella risposta per conferire rilevanza a lungo termine. –

+0

@Jnickz: questo è il fascino, il fascino assoluto! –

+0

Brillante abbastanza semplice e funziona perfettamente – Salman

1

per chi ancora cercando di trovare un modo per farlo, creo un violino

ho usato snap e $ (questo) .data ('trascinabile').snapElements;

drag: function(event, ui) 
     { 
      //var snapped = $(this).data('ui-draggable').snapElements; //## for new version of jquery UI 
      var snapped = $(this).data('draggable').snapElements; 
      /* Pull out only the snap targets that are "snapping": */ 
      var snappedTo = $.map(snapped, function(element) { 
       //return element.snapping ? element.item : null; 
       return element.snapping ? element : null; 
      }); 
      if((snappedTo[0].left + snappedTo[0].width) == $(this).offset().left) 
      { 
       console.log('right of snapped item'); 
       $('#guide-v').css({'left': $(this).offset().left}).show(); 
      }else 
      if((snappedTo[0].left) == $(this).offset().left) 
      { 
       console.log('left of snapped item'); 
       $('#guide-v').css({'left': $(this).offset().left}).show(); 
      }else $('#guide-v').hide(); 

      if((snappedTo[0].top) == $(this).offset().top) 
      { 
       console.log('top of snapped item'); 
       $('#guide-h').css({'top': $(this).offset().top}).show(); 
      }else 
      if((snappedTo[0].top + snappedTo[0].height) == $(this).offset().top) 
      { 
       console.log('bottom of snapped item'); 
       $('#guide-h').css({'top': $(this).offset().top}).show(); 
      }else $('#guide-h').hide(); 
      } 
     }); 

http://jsfiddle.net/j6zqN/1/

+0

Non riesco a farlo funzionare con la nuova versione di jQuery –

0

ho ricevuto una risposta da questa domanda: Javascript drag/drop - Illustrator style 'smart guides'

Credo che questo è ciò che stanno cercando. L'ho anche migliorato supportando la linea per lo stesso lato. Ecco l'JsFiddle: http://jsfiddle.net/yusrilmaulidanraji/A6CpP/120/

HTML

<div id="parent"> 
    <div class="object1 dropped" style="left:0px;top:300px;background:#a00;"></div> 
    <div class="object2 dropped"></div> 
    <div class="object3 dropped" style="left:400px;top:20px;"></div> 
    <div class="objectx"></div> 
    <div class="objecty"></div> 
</div> 

CSS:

#parent{ 
    width:600px; 
    height:500px; 
    border:1px solid #000; 
    position:relative; 
} 
.object1{ 
    background:#aaa; 
    width:100px; 
    height:100px; 
    display:block; 
    position:absolute; 
    left:140px; 
    top:50px; 
} 
.object2{ 
    background:#aaa; 
    width:100px; 
    height:150px; 
    display:block; 
    position:absolute; 
    left:140px; 
    top:50px; 
} 
.object3{ 
    background:#aaa; 
    width:150px; 
    height:100px; 
    display:block; 
    position:absolute; 
    left:140px; 
    top:50px; 
} 
.objectx{ 
    display:none; 
    //background:#fff; 
    width:0px; 
    height:100%; 
    position:absolute; 
    top:0px; 
    left:10px; 
    border-left: 1px solid yellow; 
} 
.objecty{ 
    display:none; 
    //background:#fff; 
    width:100%; 
    height:0px; 
    position:absolute; 
    top:10px; 
    left:0px; 
    border-bottom: 1px solid yellow; 
} 

JS:

$.ui.plugin.add("draggable", "smartguides", { 
    start: function(event, ui) { 
     var i = $(this).data("draggable"), o = i.options; 
     i.elements = []; 
     $(o.smartguides.constructor != String ? (o.smartguides.items || ':data(draggable)') : o.smartguides).each(function() { 
      var $t = $(this); var $o = $t.offset(); 
      if(this != i.element[0]) i.elements.push({ 
       item: this, 
       width: $t.outerWidth(), height: $t.outerHeight(), 
       top: $o.top, left: $o.left 
      }); 
     }); 
    }, 
    stop: function(event, ui) { 
     $(".objectx").css({"display":"none"}); 
     $(".objecty").css({"display":"none"}); 
    }, 
    drag: function(event, ui) { 
     var inst = $(this).data("draggable"), o = inst.options; 
     var d = o.tolerance; 
     $(".objectx").css({"display":"none"}); 
     $(".objecty").css({"display":"none"}); 
      var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, 
       y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height, 
       xc = (x1 + x2)/2, yc = (y1 + y2)/2; 
      for (var i = inst.elements.length - 1; i >= 0; i--){ 
       var l = inst.elements[i].left, r = l + inst.elements[i].width, 
        t = inst.elements[i].top, b = t + inst.elements[i].height, 
        hc = (l + r)/2, vc = (t + b)/2; 
        var lss = Math.abs(l - x1) <= d; 
          var ls = Math.abs(l - x2) <= d; 
          var rss = Math.abs(r - x2) <= d; 
          var rs = Math.abs(r - x1) <= d; 
          var tss = Math.abs(t - y1) <= d; 
          var ts = Math.abs(t - y2) <= d; 
          var bss = Math.abs(b - y2) <= d; 
          var bs = Math.abs(b - y1) <= d; 
          var hs = Math.abs(hc - xc) <= d; 
          var vs = Math.abs(vc - yc) <= d; 
         if(lss) { 
          ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; 
          $(".objectx").css({"left":ui.position.left,"display":"block"}); 
         } 
         if(rss) { 
          ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; 
          $(".objectx").css({"left":ui.position.left + ui.helper.width(),"display":"block"}); 
         } 
         if(ls) { 
          ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; 
          $(".objectx").css({"left":ui.position.left + ui.helper.width(),"display":"block"}); 
         } 
         if(rs) { 
          ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; 
          $(".objectx").css({"left":ui.position.left,"display":"block"}); 
         } 
         if(tss) { 
          ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; 
          $(".objecty").css({"top":ui.position.top,"display":"block"}); 
         } 
         if(ts) { 
          ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; 
          $(".objecty").css({"top":ui.position.top + ui.helper.height(),"display":"block"}); 
         } 
         if(bss) { 
          ui.position.top = inst._convertPositionTo("relative", { top: b-inst.helperProportions.height, left: 0 }).top - inst.margins.top; 
          $(".objecty").css({"top":ui.position.top + ui.helper.height(),"display":"block"}); 
         } 
         if(bs) { 
          ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; 
          $(".objecty").css({"top":ui.position.top,"display":"block"}); 
         } 
         if(hs) { 
          ui.position.left = inst._convertPositionTo("relative", { top: 0, left: hc - inst.helperProportions.width/2 }).left - inst.margins.left; 
          $(".objectx").css({"left":ui.position.left + (ui.helper.width()/2),"display":"block"}); 
         } 
         if(vs) { 
          ui.position.top = inst._convertPositionTo("relative", { top: vc - inst.helperProportions.height/2, left: 0 }).top - inst.margins.top; 
          $(".objecty").css({"top":ui.position.top + (ui.helper.height()/2),"display":"block"}); 
         } 


      }; 
     } 
}); 
$('.dropped').draggable({ 
    containment: 'parent', 
    smartguides:".dropped", 
    tolerance:5 
});