Before suggesting bin packing algorithms, they assume you can re-order the elements and arrange them any way you please. Note as you read that I have a restriction on the ordering and arrangement.
So obviously there’s no such thing as kerning divs, but it’s the most appropriate term I could think of. Basically I have a lot of elements on a page, divs and imgs, with fixed width and height. They have to remain in order (they are chronological) and should be displayed left to right, top to bottom. I want to “kern” the elements in such a way as to make the whitespace as uniform as possible. It’s a very easy task to achieve horizontally, but vertical whitespace is more difficult. Uneven excess whitespace around the outermost edge of the packed elements is acceptable.
I was thinking as a really dumb solution, I could set the max width of the area to be packed to something like 1000px. Then I could keep an array with 1000 indices keeping track of the bottom of that column of pixels on the screen. When I add a new element, I see if it should be moved up a little into a gap and if shifting it left or right a little bit would allow it to be moved up.
As I said, that’s a really dumb solution. Are there any algorithms I could use or has anyone had to deal with a similar packing problem?
UPDATE:
Per questions in comments. The elements have random widths and heights. My test case is to create 100 image tags with images from placekitten.com with random widths and heights in the 200-300px range and arrange those images on the page in the order they are generated.
Create an html page and throw the below code in your head to get to where I am (please no comments on general code quality, I know there are some optimizations, I literally threw this together as a demo in under 10 minutes):
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script>
var maxwidth = window.innerWidth - 80;
function justify(row, filled)
{
var remaining = maxwidth - filled + 30,
imgs = $('img',row),
margin = Math.floor((remaining/imgs.length) / 2);
$(imgs).each(function(){ this.style.marginLeft=margin+"px";this.style.marginRight=margin+"px"});
}
$(function()
{
var row = document.createElement('div'),
filled = 0;
document.body.appendChild(row);
for (var i = 0; i < 100; ++i)
{
var img = document.createElement('img'),
width = Math.floor(200 + Math.random() * 100),
height = Math.floor(200 + Math.random() * 100);
if ((filled + width) > maxwidth)
{
justify(row, filled);
row = document.createElement('div');
filled = 0;
document.body.appendChild(row);
}
filled += width;
img.src = "http://placekitten.com/" + width + "/" + height;
row.appendChild(img);
}
justify(row,filled);
})
</script>
<style>
img{position:relative; vertical-align:middle}
</style>
Take a look at the beautiful Masonry Plugin I used for a similar problem.
Also, try similar plugins like Columnizer and jLayout.
Good luck.