JSFiddle - React, Tailwind, and code Playground

by blparker

HTML

<div class="items">
    <!--<div class="item">Foo</div>
    <div class="item">Bar</div>
    <div class="item">Biz</div>
    <div class="item">Baz</div>
    <div class="item">Qux</div>
    <div class="item">Quoo</div>-->
</div>

CSS

.item { border: 1px solid #aaa; background: #eee; text-align: center; }
.items { position: relative; border: 1px solid blue; width : 500px; height : 1000px; }

JavaScript

function setup(numBlocks) {
    var $cont = $('.items');
    $cont.css('position', 'relative');
    
    for(var i = 0; i < numBlocks; i++) {
        var $i = $('<div />')
                    .addClass('item')
                    .css({
                        'width' : random(100, 200),
                        'height' : random(100, 200),
                        'position' : 'absolute'
                    })
                    .html('Item ' + i);
        $cont.append($i);
    }
}

function random(min, max) {
    return Math.floor(Math.random() * (max - min) + min);
}

function Packer(w, h) {
    this.root = { x : 0, y : 0, w : w, h : h };
}

Packer.prototype = {
    fit : function(blocks) {
        var n, node, block;
        for(n = 0; n < blocks.length; n++) {
            block = blocks[n];
            if(node = this.findNode(this.root, block.w, block.h)) {
                block.fit = this.splitNode(node, block.w, block.h);
            }
        }
    },
    
    findNode : function(root, w, h) {
        if(root.used) {
            return this.findNode(root.right, w, h) || this.findNode(root.down, w, h);
        } else if((w <= root.w) && (h <= root.h)) {
            return root;
        } else {
            return null;
        }
    },
    
    splitNode : function(node, w, h) {
        node.used = true;
        node.down = { x : node.x, y : node.y + h, w : node.w, h : node.h - h };
        node.right = { x : node.x + w, y : node.y, w : node.w - w, h : h };
        return node;
    }
};

function getBlocks($blocks) {
    var blocks = [];
    $blocks.each(function() {
        var $t = $(this);
        blocks.push({
            w : $t.width(),
            h : $t.height()
        });
    });
    return blocks;
}

setup(5);
var p = new Packer(500, 1000);
var blocks = getBlocks($('.items .item'));
p.fit(blocks);
layout(blocks);
console.log(blocks);

function layout(blocks) {
    var $els = $('.items .item');
    for(var i = 0; i < blocks.length; i++) {
       ...