Расслоение пересекающихся элементов с помощью jQuery - PullRequest
4 голосов
/ 08 октября 2009

У меня есть страница с перетаскиваемыми / сбрасываемыми элементами, которые после удаления должны вычислить их левое положение и ширину в отношении других перетаскиваемых объектов, к которым они могут прикасаться.

Это не так уж сложно само по себе, но когда у меня действительно возникают проблемы, это заставить их заполнить пустое пространство. Как я могу заставить draggables заполнять пустое пространство, не дублируя друг друга?

// $t is the element being added/dropped. 
// nd refers to New Dimensions, IE, the new dimensions for $t
// existingDivs gets any DIV's that have already been added to the dom
var $t = $(this), nd = {t:$t.position().top, h:$t.height(), l: 0, w: 95},
  existingDivs = $('#container .subContainer .draggable'), intersectArr = [],
  nonIntersectArr = [], finalArr = [];

// If there are no DIV's in the DOM you dont need to check if they intersect.
if (existingDivs.length > 0) {
// Find the DIV's that Intersect with the one being added
  intersectArr = $.grep(existingDivs, function(val,num){
    // xd is Existing Dimensions, for the current item being checked
    // verse the one being added.
    var $t2 = $(val), xd = {h:$t2.height(), w:parseFloat($t2.css('width')),
    l:parseFloat($t2.css('left')), t:$t2.position().top};
    // If they intersect add it to this array
    return ((xd.t <= nd.t && xd.t+xd.h > nd.t) ||
    (nd.t <= xd.t && nd.t+nd.h > xd.t));
  });
// Find the DIV's that DO NOT Intersect with the one being added
  nonIntersectArr = $.grep(existingDivs, function(val,num){
    // xd is Existing Dimensions, for the current item being checked
    // verse the one being added.
    var $t2 = $(val), xd = {h:$t2.height(), w:parseFloat($t2.css('width')),
    l:parseFloat($t2.css('left')), t:$t2.position().top};
    // If they DO NOT intersect add it to this array
    return ((xd.t > nd.t && xd.t > nd.t+nd.h) ||
    (nd.t > xd.t && nd.t > xd.t+xd.h));
  });
// For every element that does not intersect, check it verse the ones that do
  $(nonIntersectArr).each(function(){
    // nid is Non Intersecting Dimensions
    var $t2 = $(this), c = 0, nid = {h:$t2.height(),
    w:parseFloat($t2.css('width')),
    l:parseFloat($t2.css('left')), t:$t2.position().top};
    $(intersectArr).each(function(){
    // id is Intersecting Dimensions
      var $t3 = $(this), id = {h:$t3.height(), w:parseFloat($t3.css('width')),
      l:parseFloat($t3.css('left')), t:$t3.position().top};
    // if the non intersecting hits one that is intersecting, then there is no space
    // beneath/near it, so we add it to the final intersecting array then increment c
      if((id.t <= nid.t && id.t+id.h > nid.t) ||
      (nid.t <= id.t && nid.t+nid.h > id.t)){ finalArr.push(this); c++; }
      else { finalArr.push(this); }
    });
    // if c has been incremented, we cant use this nonIntersect, so add it to the final
    if(c > 0) { finalArr.push(this); }
  });
  // make sure all items in the final Array are unique
  finalArr = $.unique(finalArr);
  // iterate over the final array, processing the dimensions of each element in the
  // array layering them so you can see each one
  $(finalArr).each(function(num){
    // xd is Existing Dimensions, for the current item being checked
    // verse the one being added.
    var $t2 = $(this), xd = {h:$t2.height(), w:parseFloat($t2.css('width')),
    l:parseFloat($t2.css('left')), t:$t2.position().top};
    if(((xd.t <= nd.t && xd.t+xd.h > nd.t) ||
    (nd.t <= xd.t && nd.t+nd.h > xd.t))) {
      if(nd.l == xd.l){
        nd.w = ((95/(finalArr.length+1))*1.5);
        xd.l = ((nd.w)*(num));
        $(finalArr).each(function(ci){
          $(this).css({left:((nd.w*ci)*0.58)+'%',
          width:((95/(finalArr.length+1))*1.5)+'%'});
          nd.l = ((nd.w*ci)*0.58);
        });
      }
    }
  });
}
// Add the New Element to the container and position accordingly.
nd.l = ((nd.l/finalArr.length)*(finalArr.length+1))+'%';
nd.w = nd.w+'%';
$('#container .subContainer').append('<div style="top:'+nd.t+'px;left:'+nd.l+
';width:'+nd.w+';height:'+nd.h+'px;" class="dragId_'+$t.attr('id')+
' draggable"><div class="title">'+$t.attr('title')+'</div></div>');

Любые предложения / помощь будет принята с благодарностью. Спасибо.

1 Ответ

3 голосов
/ 08 октября 2009

Вот алгоритм для того, что вам нужно сделать:

  1. Пока есть соприкасающиеся фигуры, определите крайнюю правую фигуру (ту, которая имеет наибольшую правую x-координату), которая касается другой фигуры. Переместите его так, чтобы его левый край находился справа от самой правой формы, к которой он просто прикасался.
  2. Хотя рядом с чем-то слева от них есть фигуры, определите фигуру с наименьшей левой x-координатой, которая не находится рядом с чем-то слева от нее. Переместите его так, чтобы его левый край находился справа от фигуры с наибольшей правой x-координатой, лежащей в диапазоне y объекта.

Достаточно просто? Ну, вот упрощенная версия:

  1. Пока фигуры касаются друг друга, переместите крайнюю правую, чтобы она не касалась других фигур.
  2. Хотя есть фигуры, не прилегающие друг к другу, переместите крайнюю левую, чтобы она прилегала к ближайшей фигуре.

Редактировать: Например ...

Предположим, я взял квадрат 3 и положил его поверх квадрата 1 и квадрата 2:

1111   44
1111   44
1133333
1133333
  33333
  3333322
  3333322
     2222
     2222

Шаг 1. Найдите самую правую фигуру, которая что-то пересекает. В данном случае это форма 2. Переместите ее вправо от того, что она пересекает.

1111   44
1111   44
1133333
1133333
  33333
  333332222
  333332222
       2222
       2222

Есть ли трогательные фигуры сейчас? Да, и самый правый из них - фигура 3. Переместите ее вправо от фигуры, которой она касается, фигура 1:

1111   44
1111   44
111133333
111133333
    33333
    3333322
    3333322
       2222
       2222

Есть ли трогательные фигуры сейчас? Да, и самый правый из них - фигура 2. Переместите ее вправо от фигуры, которую она касается, фигура 3:

1111   44
1111   44
111133333
111133333
    33333
    333332222
    333332222
         2222
         2222

Есть ли фигуры, соприкасающиеся сейчас? Итак, мы сделали шаг 1.

Шаг 2: Найдите крайнюю левую фигуру, которая ни к чему не прилегала. В этом случае крайняя левая, не прилегающая к чему-либо, - это фигура 4. Переместите ее влево, чтобы она находилась справа от самой правой фигуры слева от нее, которая существует в тех же координатах y, что и она:

111144
111144
111133333
111133333
    33333
    333332222
    333332222
         2222
         2222

Что-нибудь не прижалось к чему-нибудь? Нету! Итак, вы сделали!

Как видите, в основном есть фаза расширения и фаза сокращения. Вы делаете фазу расширения справа налево, чтобы ничто не расширилось прямо через что-то еще. Вы выполняете фазу сокращения слева направо, чтобы ничто не сжималось через что-то еще.

...