Left alignment with element collision detection

Asked

Viewed 256 times

1

Alignment criteria:
- Align left from element with lower value of 'left'.
- Collision elements shall remain adjacent to the impacted element.

In the example the algorithm searches for the leftmost element in reference to the other elements and stores its position, then seeks to align all other elements from the stored data.

 arrayTopValue = [];
 arrayLeftValue = [];
 arrayLeftOriginal = [];
 arrayWidth = [];
 arrayHeight = [];
 arrayIdDivs = [];
 arrayAboutDivCollision = [];

$("#boxExample").children().each(function() {
//top
var position = $(this).css("top").indexOf("px");
var res = $(this).css("top").substr(0, position);
arrayTopValue.push(parseInt(res));


//left
var position = $(this).css("left").indexOf("px");
var res = $(this).css("left").substr(0, position);
arrayLeftValue.push(parseInt(res));
arrayLeftOriginal.push(parseInt(res));
arrayLeftValue.sort(function(a, b) {
  return a - b
});

//width
var position = $(this).css("width").indexOf("px");
var res = $(this).css("width").substr(0, position);
arrayWidth.push(parseInt(res));


//height
var position = $(this).css("height").indexOf("px");
var res = $(this).css("height").substr(0, position);
arrayHeight.push(parseInt(res));


//idDivs
var tempIds = $(this).attr("id");
arrayIdDivs.push(tempIds);

});

How does the algorithm know it’s going to collide or not? To know this the algorithm checks if the element that will align to the left is above the stored element:

          if (distTopPlusHeightRefNext < distTopRef) 
          {
            $("#" + arrayIdDivsFolllow[i]).css({'left': arrayLeftValue[0] + "px"
          });

If the element is above, it applies the stored left position to the element that will be left aligned.

The same happens if the element to be aligned is below the stored element.

if (distTopRefNext > distTopPlusHeightRef) 
{
    $("#" + arrayIdDivsFolllow[i]).css({'left': arrayLeftValue[0] + "px"
});

So when these two previous options are not possible to align, it means that the element will collide.

if (distTopPlusHeightRefNext > distTopRef && distTopRefNext < distTopPlusHeightRef) {
    var tempValue = marginLeftPlusWidthRef;
    tempValue = tempValue + 3; //Espaço entre os elementos em pixel
    $("#" + arrayIdDivsFolllow[i]).css({'left': tempValue + "px"
    });

Once the element collides, the reference values need to be updated, so that the element can align from the nearest element. Ex: getValDivs().

But there is an error because the div1 is not colliding with the div3, as can be seen in https://fiddle.jshell.net/43jwxh35/ as when also two elements have the same position generates an alignment bug, could someone tell me what is wrong? Thanks

  • I confess that I am also not getting around the problem rsrs. You accept a new code?

1 answer

1


As I really had difficulty manipulating your code, I made another option, which, although I haven’t had time to test many possible positions, I think is working right and meeting what you asked:

$(document).ready(function() {
  var leftList = []; // armazenará o left de todos os quadrados
  var minLeft; // receberá o menor left de todos os quadrados
  var topList = []; // armazenará o top de todos os quadrados
  var minTop; // armazenará o top de todos os quadrados
  var widthList = []; // armazenará o width de todos os quadrados
  var heightList = []; // armazenará o height de todos os quadrados
  var margin = 5; // espaçamentos entre os quadrados

  $('div').draggable(); // aplica o draggable a todos os quadrados, inclusive o grande

  function loadValues() { // carregará as variáveis supracitadas
    // loop que percorrerá todos o quadros
    $('#boxExample').children().each(function(i) { 
      var left = $(this).position().left; // captura o left do elemento em questão dentro do loop
      leftList[i] = left; // adiciona o left ao array
      var top = $(this).position().top; // captura o top 
      topList[i] = top; // adiciona o top ao array
      var height = $(this).height(); // captura o height 
      heightList[i] = height; // adiciona o height ao array
      var width = $(this).width(); // captura o width 
      widthList[i] = width; // adiciona o width ao array
    });
    minLeft = Math.min.apply(Math, leftList); // usa o Math.min em um array para retornar o menor left
    minTop = Math.min.apply(Math, topList); // retorna o menor top
  }

  function align() {
    loadValues(); // carrega a função passada
    // percorre novamente todos o quadros
    $('#boxExample').children().each(function(i) {
      loadValues(); // carrega os valores a cada mudança
      var thisLeft = leftList[i]; 
      // captura o left do elemento em questão usando o index do loop e aplicando ao array
      var thisTop = topList[i]; // faz o mesmo com o top
      var newLeft = minLeft; // deixa por padrão o left de cada elemento como sendo o menor
      var before = []; // array com as medidas dos quadros a esquerda do elemento em questão
      leftList.forEach(function(el, index) { // percorre o array de lefts
      // este primeiro if verifica a colisão somente em quadrados mais a esquerda que o em questão no primeiro loop
        if (el <= thisLeft && i != index) {
          // este verifica a colisão baseado no top
          if ((topList[index] >= thisTop && topList[index] <= thisTop + heightList[i]) || (topList[index] <= thisTop && topList[index] >= thisTop - heightList[index])) {
            // adiciona do before[] o left, o width e a margin, e subtrai o minLeft 
            before.push(el + widthList[index] - minLeft + margin);
          }
        }
      });
      // soma ao newLeft (que era por padrão o menor left) o maior valor do array before ou zero se ele for o elemento mais a esquerda
      newLeft += before.length == 0 ? 0 : Math.max.apply(Math, before);
      $(this).css({
        left: newLeft  // aplica o estilo
      })
    });
  }
  $('#btn2').click(function() {
    // este loop serve apenas para repetir a função várias vezes e o alinhamento funcione com eficácea
    $('#boxExample').children().each(function(i) {
      align();
    });
  });
})
#div1 {
  position: absolute;
  width: 30px;
  height: 30px;
  border: 1px solid black;
  left: 334px;
  top: 240px;
}
#div2 {
  position: absolute;
  width: 60px;
  height: 60px;
  border: 1px solid black;
  left: 198px;
  top: 41px;
}
#div3 {
  position: absolute;
  width: 80px;
  height: 80px;
  border: 1px solid black;
  left: 222px;
  top: 170px;
}
#div4 {
  position: absolute;
  width: 100px;
  height: 100px;
  border: 1px solid black;
  left: 86px;
  top: 106px;
}
#boxExample {
  position: relative;
  width: 460px;
  height: 360px;
  border: 1px solid black;
}
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<div id="boxExample">
  <div id="div1">1</div>
  <div id="div2">2</div>
  <div id="div3">3</div>
  <div id="div4">4</div>
</div>
<button id="btn2">goLeft</button>

Functions used:

  • @user31050, commented code ;)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.