Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fit colliding elements in the container dynamically

I have absolutely positioned elements with different position.top and height generated from database.

All I'm trying to do is to un-collide these elements by shifting them to the right while adjusting width to fit inside the <body> container.

I'm having an issue applying 'left' position to the collided elements.

I use https://sourceforge.net/projects/jquerycollision/ to detect collision.

Here is how the final picture should look:

screenshot

$('div').each(function() {
  var name = $(this).text();
  var hits = $(this).collision('div').not(this); // Find colliding elements
  console.log(name + ' collides with: ' + hits.length + ' others');

  if (hits.length > 0) {
    var widthAll = 100 / (hits.length + 1);

    // Shift colliding elements to the right with equal width
    $(hits).add(this).each(function(i) {
      var name = $(this).text();
      $(this).css({ 'left': widthAll * i + '%', 'width': widthAll + '%' });
    });
  }
});
div {
  position: absolute;
  width: 10em;
  font-size: 0.75em;
  color: white;
}

.blue {
  top: 0;
  height: 80%;
  background-color: blue;
}

.red {
  top: 15%;
  height: 5%;
  background-color: red;
}

.yellow {
  top: 17%;
  height: 10%;
  background-color: yellow;
  color: black;
}

.green {
  top: 30%;
  height: 5%;
  background-color: green;
}

.magenta {
  top: 36%;
  height: 3%;
  background-color: magenta;
}

.cyan {
  top: 50%;
  height: 5%;
  background-color: cyan;
  color: black;
}

.brown {
  top: 81%;
  height: 5%;
  background-color: brown;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://rawgit.com/dsbaars/jquery-collision/master/js/jquery-collision.min.js"></script>

<div class='blue'>blue</div>
<div class='red'>red</div>
<div class='yellow'>yellow</div>
<div class='green'>green</div>
<div class='magenta'>magenta</div>
<div class='cyan'>cyan</div>
<div class='brown'>brown</div>
like image 511
Alex G Avatar asked Nov 09 '22 02:11

Alex G


1 Answers

I think I have completed your code as you have requested. The idea is,

  1. First block of code shifts the divs to the right so that they don't overlap.
  2. Second block makes the width of the divs evenly distributed according to size of the body.
  3. Last block increases the width of rest of the divs to take remaining space.

"use strict";
var divs = $('div'),
  mx = 0,
  mxs = [0],
  bw = $("body").outerWidth(),
  steps = 1;
divs.each(function(i) {
  for (var j = i + 1; j < divs.length; j++) {
    if (!$(this).data("x")) $(this).data("x", 0);
    if (j < divs.length) {
      var hit = $(this).collision(divs[j]);
      if (hit.length) {
        hit = $(divs[j]);
        hit.css("left", "+=" + Math.ceil($(this).outerWidth()));
        hit.data("x", hit.position().left);
        if (mx < hit.data("x")) {
          mxs.push(mx = hit.data("x"));
          steps++;
        }
      }
    }
  }
});

divs.each(function(i) {
  let iw = $(this).outerWidth(),
    fw = bw / steps;
  $(this).outerWidth(fw);
  for (var j = i + 1; j < divs.length; j++) {
    $(this).collision(divs[j]).css("left", "+=" + Math.ceil((fw - iw) * mxs.indexOf($(divs[j]).data("x"))));
  }
});
divs.each(function() {
  var os = $(this).outerWidth(),
    ts = bw - $(this).position().left;
  $(this).outerWidth(ts);
  if ($(this).collision(divs).not(this).length) {
    $(this).outerWidth(os);
  }
});
body {
  margin: 0;
}
div {
  position: absolute;
  width: 10em;
  font-size: 0.75em;
  color: white;
  left: 0;
}
.blue {
  top: 0;
  height: 80%;
  background-color: blue;
}
.red {
  top: 15%;
  height: 5%;
  background-color: red;
}
.yellow {
  top: 17%;
  height: 10%;
  background-color: yellow;
  color: black;
}
.green {
  top: 20%;
  height: 50%;
  background-color: green;
}
.magenta {
  top: 36%;
  height: 3%;
  background-color: magenta;
}
.cyan {
  top: 50%;
  height: 5%;
  background-color: cyan;
  color: black;
}
.brown {
  top: 81%;
  height: 5%;
  background-color: brown;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/dsbaars/jquery-collision/master/js/jquery-collision.min.js"></script>

<div class='blue'>blue</div>
<div class='red'>red</div>
<div class='yellow'>yellow</div>
<div class='green'>green</div>
<div class='magenta'>magenta</div>
<div class='cyan'>cyan</div>
<div class='brown'>brown</div>

Above snippet is non-responsive. If you wish it to be responsive, then simply listen to resize event, change the value of bw and repeat code blocks 2 and 3.

As mentioned in the comments: jquery-collision.min.js had some unressolved bugs so, as suggested by Alex G, https://www.48design.de/de/news/2009/11/20/kollisionsabfrage-per-jquery-plugin-update-v11/ may be an alternative.

like image 74
Kiran Shakya Avatar answered Nov 14 '22 23:11

Kiran Shakya