JavaScript:如何在不使用插件的情况下堆叠矩形元素俄罗斯方块风格?

时间:2013-11-09 11:42:35

标签: javascript html5 layout timeline tetris

我正在制作日程表。事件是水平块(Google Cal具有垂直块)。因为我在一个日期有大量的事件,我希望事件堆叠在一起而不浪费任何空间,如下所示: This is what I want

我确实找到了插件:
http://masonry.desandro.com/
http://isotope.metafizzy.co/
http://packery.metafizzy.co/
但我并不热衷于使用30kb的插件来做这件事。

澄清:因为这是一个时间轴,div事件不能左/右移动,但必须在其他div事件中垂直适应。

1 个答案:

答案 0 :(得分:0)

我自己的解决方案是一个2.6kb(注释)的jQuery脚本,它使用事件的绝对定位和div作为每行的容器。

此脚本生成随机大小的条形图。每个新栏都会自上而下检查每行中的空间。我正在使用百分比,因为计算条形位置与时间的关系很容易(100%/ 24h)。

Result

http://jsfiddle.net/cj23H/5/
虽然有效且足够高效,但感觉还是很笨重。欢迎你改进。

来自我的jsfiddle的jQuery代码:

function rand() {
    return Math.floor(Math.random() * 101);
}

function get_target_row(width, left) {
    var i = 0;
    var target_found = false;

    // Loop through all the rows to see if there's space anywhere
    while (target_found === false) {

        // Define current row selector
        var target_i = '.personnel#row' + i;

        // Add row if none
        if ($(target_i).length === 0) {
            $('body').append('<div class="personnel" id="row' + i + '"></div>');
        }
        // See if there's space
        if ($(target_i).children().length === 0) {
            target_found = $(target_i);
        } else {
            var spaceFree = false;

            // Check collision for each child
            $(target_i).children().each(function () {

                // Get left and right coordinates
                var thisWidthPx = parseFloat($(this).css('width'), 10);
                var thisWidthParentPx = parseFloat($(this).parent().css('width'), 10);
                var thisWidth = (thisWidthPx / thisWidthParentPx * 100);
                var thisLeftPx = parseFloat($(this).css('left'), 10);
                var thisLeftParentPx = parseFloat($(this).parent().css('left'), 10);
                var thisLeft = (thisLeftPx / thisWidthParentPx * 100);
                var thisRight = thisLeft + thisWidth;
                var right = left + width;

                // Sexy way for checking collision
                if ((right > thisLeft && right < thisRight) || (left < thisRight && left > thisLeft) || (thisLeft > left && thisLeft < right) || (thisRight < right && thisRight > left)) {
                    spaceFree = false;
                    return false;
                } else {
                    spaceFree = true;
                }
            });

            // If no children have collided break the loop
            if (spaceFree === true) {
                target_found = $(target_i);
            }
        }
        i++;
    }

    // If after all the while loops target is still not found...
    if (target_found === false) {
        return false;
    }

    // Else, if target is found, return it.
    return target_found;
}

// Generate random bars
for (var i = 0; i < 10; i++) {
    var width = rand()/2;
    var left = rand()/2;
    var right = left + width;
    var target = get_target_row(width, left);
    target.append('<div class="block" style="width:' + width + '%;position:absolute;left:' + left + '%;background-color:rgba(' + rand() + ',' + rand() + ',' + rand() + ',0.4)" id="bar'+i+'">' + 'b' + i + '</div>');
}

CSS:

.block {
    position: absolute;
    background-color: rgba(200, 100, 100, 0.4);
    height: 32px;
}
.personnel {
    position: relative;
    float: left;
    width: 100%;
    height: 33px;
}