2

私は、他のパネルに重ならない限り、ダッシュボードスペースの周りを自由にドラッグできるパネル/ウィジェットを備えたポータル/ダッシュボードタイプのインターフェイスに取り組んでいます。使用可能なすべてのパネルを含むメニューを介して新しいパネルをダッシュ​​ボードに追加できます。メニュー項目をクリックすると、パネルがダッシュボードに配置されます。ダッシュボードスペースを現在占有しているパネルはすべて、次のようなオブジェクトで表されます。

{
    'panel_1': { top: 0, left: 0, width: 300, height: 350 },
    'panel_2': { top: 0, left: 370, width: 200, height: 275 },
    'panel_3': { top: 370, left: 0, width: 275, height: 400 },
    ...
}

私の質問は、ユーザーがメニューの1つをクリックしたときに、左右(xとy)に最も近い空いているスペースに(指定された幅と高さの)新しいパネルを正しく配置する有効なアルゴリズムは何ですか?既存のパネルのいずれもオーバーラップせずに、0、0の値?

4

2 に答える 2

2

単純なブルートフォースアルゴリズムが適していると思います。私が覚えているように、長方形をフィットさせると別の問題が解決します

ダッシュボードの軸を繰り返し処理して、X < rectangle.widh + dashboard.widthYについて同じになるまで、長方形を配置できるかどうかを確認します。

ダッシュボード上のForeachX、Yは、すべてのパネルを繰り返し処理して、それらが重なっているかどうかを確認します。反復の量を減らすために、いくつかの最適化を適用できます。パネルが長方形に重なっている場合は、XまたはY(ネストされたループ内)を1ではなく、パネルの幅または高さで増やすことができます。

ほとんどの場合、dashboard.width*dashboard.height*panel.count反復は行われません。いくつかの最適化を行うと、かなり迅速に最適化が見つかります

于 2012-05-01T14:34:57.730 に答える
0

これは古い質問ですが、概念実証が必要な場合は、次のようになります。

function findSpace(width, height) {
    var $ul = $('.snap-layout>ul');
    var widthOfContainer = $ul.width();
    var heightOfContainer = $ul.height();
    var $lis = $ul.children('.setup-widget'); // The li is on the page and we dont want it to collide with itself

    for (var y = 0; y < heightOfContainer - height + 1; y++) {
        var heightOfShortestInRow = 1;
        for (var x = 0; x < widthOfContainer - width + 1; x++) {
            //console.log(x + '/' + y);
            var pos = { 'left': x, 'top': y };
            var $collider = $(isOverlapping($lis, pos, width, height));
            if ($collider.length == 0) {
                // Found a space
                return pos;
            }

            var colliderPos = $collider.position();
            // We have collided with something, there is no point testing the points within this widget so lets skip them
            var newX = colliderPos.left + $collider.width() - 1; // -1 to account for the ++ in the for loop
            x = newX > x ? newX : x; // Make sure that we are not some how going backwards and looping forever

            var colliderBottom = colliderPos.top + $collider.height();
            if (heightOfShortestInRow == 1 || colliderBottom - y < heightOfShortestInRow) {
                heightOfShortestInRow = colliderBottom - y; // This isn't actually the height its just the distance from y to the bottom of the widget, y is normally at the top of the widget tho
            }
        }
        y += heightOfShortestInRow - 1;
    }

    //TODO: Add the widget to the bottom
}


function isOverlapping($obsticles, tAxis, width, height) {
    var t_x, t_y;
    if (typeof (width) == 'undefined') {
        // Existing element passed in
        var $target = $(tAxis);
        tAxis = $target.position();
        t_x = [tAxis.left, tAxis.left + $target.outerWidth()];
        t_y = [tAxis.top, tAxis.top + $target.outerHeight()];
    } else {
        // Coordinates and dimensions passed in
        t_x = [tAxis.left, tAxis.left + width];
        t_y = [tAxis.top, tAxis.top + height];
    }

    var overlap = false;

    $obsticles.each(function () {
        var $this = $(this);
        var thisPos = $this.position();
        var i_x = [thisPos.left, thisPos.left + $this.outerWidth()]
        var i_y = [thisPos.top, thisPos.top + $this.outerHeight()];

        if (t_x[0] < i_x[1] && t_x[1] > i_x[0] &&
             t_y[0] < i_y[1] && t_y[1] > i_y[0]) {
            overlap = this;
            return false;
        }
    });
    return overlap;
}
于 2014-06-27T00:31:58.953 に答える