gridstack.js icon indicating copy to clipboard operation
gridstack.js copied to clipboard

Resizing window causes grid items to be positioned out of order

Open harrington101 opened this issue 2 years ago • 10 comments

Subject of the issue

Resizing window causes grid items to be positioned to the right. And order changes when resizing.

Your environment

  • Version 5.1
  • Chrome Windows 10

Steps to reproduce

I have 4 items that are 1 column wide followed by 2 items that are 4 columns wide. With the following settings, and the window set to less than 992px, there are 2 columns but the last 2 items that were in the first row on a large screen (when there were 4 columns) are now stacked in the right column under the first 2 items like so: 1 2 _ 3 _ 4 5 6

var grid = GridStack.init({
    column: 4,
    cellHeight: "140px",
    disableOneColumnMode: true,
    float: false,
    handle: ".tile__heading"
});

setTimeout(function () {
    resizeGrid();
}, 1000);

function resizeGrid() {
    let width = document.body.clientWidth;
    let layout = "moveScale";
    if (width < 576) {
        grid.column(1, layout);
    } else if (width < 992) {
        grid.column(2, layout);
    } else if (width < 1100) {
        grid.column(3, layout);
    } else {
        grid.column(4, layout);
    }
}

window.addEventListener('resize', function () { resizeGrid(); });

Expected behavior

The last 2 items in the first row should flow under the first 2 items like so: 1 2 3 4 5 6

Actual behavior

Instead they flow leaving 2 blank spaces on the left like so: 1 2 _ 3 _ 4 5 6

harrington101 avatar Jun 07 '22 02:06 harrington101

I enabled compact mode which sort of solves the issue, except when changing the screen size back the order of the items is different than it originally was. It seems that it starts as: 1, 2, 3, 4 Then becomes: 1, 2 4, 3 Then when grown again is: 4, 1, 3, 2

It should be 1, 2, 3, 4 or 1, 2 3, 4

harrington101 avatar Jun 07 '22 03:06 harrington101

can you post a running example (use bug template). thanks.

adumesny avatar Jun 14 '22 21:06 adumesny

Here is a sample of my code on JS Fiddle. You'll notice that as you resize the pane where the grid is that the numbers get out of order. Also, on page load, tile 9 shows up before tile 8. JSFiddle

harrington101 avatar Jun 16 '22 22:06 harrington101

you need to reduce your example to just like the demos (init the grid with gs-x/gs-y values as html template, or load() with correct json) and not some convoluted template if you want me to take a look...

for one thing you have gs-x="0" gs-y="{{order}}" so they are all vertically placed and don't assume it will be this order as they have different real height, so when it comes to insert 9, it will be y LESS than actual 8 that was created (because things shift to fit for each element) which is why 9 is before 8 at the end. IFF you omit X or Y then it will be placed as the next open slot instead (what you want to create an ordered list).

Also, resizing the window will NOT in your case reflow the items as you and only you know that you have a 0-9 order list of items that fill the space. I suppose it would need a custom grid.column(x, 'list') kind of layout that keeps the items order the same and reflow is all each time, which we don't support, but could for the right donation.

adumesny avatar Jun 23 '22 21:06 adumesny

Unfortunately I can't save the X and Y position in the database because the X and Y position is different depending on the screen size which controls the number of columns shown (1 on mobile, 2 on tablet, 3 on small desktop, 4 on large desktop). I did create a function called update positions that might be helpful. It loops through a presorted array of objects and finds the next available position that the item will fit in. I run this on page load and any time the screen or layout div changes size. An issue my code has at the moment is that if someone stacks two 1h tiles next to a 2h tile it doesn't preserve that stack. I am OK with preventing stacking if that is a setting somewhere.

Here is my helper function:

var tileSettings = [
{order: 0, title: "tile 1", colSpan: 1, rowSpan: 1, id: "tile1"}, 
{order: 1, title: "tile 2", colSpan: 1, rowSpan: 2, id: "tile2"},
{order: 1, title: "tile 3", colSpan: 1, rowSpan: 1, id: "tile3"},
];
function updatePositions() {
        tileSettings = sortObjectArray(tileSettings, "order");
        let newY = 0;
        let newX = 0;
        let rowHeight = 1;
        let columns = grid.getColumn();
        $.each(tileSettings, function (index, item) {
            if (item.colSpan > columns || newX + item.colSpan > columns) {
                newX = 0;
                newY = newY + rowHeight;
            }
            grid.update(`#tile_${tileSettings[index].id}`, { x: newX, y: newY });
            if (rowHeight < item.rowSpan) {
                rowHeight = item.rowSpan;
            }
            if (newX + item.colSpan >= columns) {
                newX = 0;
                newY = newY + rowHeight;
                rowHeight = 1;
            } else {
                newX = newX + item.colSpan;
            }
        });
    }

harrington101 avatar Jun 27 '22 15:06 harrington101

| I did create a function called update positions that might be helpful. It loops through a presorted array of objects and finds the next available position that the item will fit in.

that sounds like the compact() method that already exists.

I'll be closing this without a simple example of what you need showing either a bug or a feature request (with corresponding donations to make it happen)...

adumesny avatar Jun 27 '22 17:06 adumesny

This is actually different from compact(). I tried that one but it caused all of the tiles to be rearranged in an arbitrary order. This preserves the tiles in the original order.

harrington101 avatar Jun 27 '22 18:06 harrington101

ok, true it tries to fill any empty spot (hence the name) - could be an optional arg to keep order the same, or a different method altogether.

adumesny avatar Jun 27 '22 18:06 adumesny

could be related, but there's a bug in the code for sorting

where it says in updateNodeWidths

// finally re-layout them in reverse order (to get correct placement)
 newNodes = utils_1.Utils.sort(newNodes, -1, column); 

should be instead, so that oneColumnModeDomSort: true, get's respected

// finally re-layout them in reverse order (to get correct placement)
 if (!domOrder) newNodes = utils_1.Utils.sort(newNodes, -1, column); 

doktordirk avatar Jul 20 '22 16:07 doktordirk

Responding to the above comment:

could be related, but there's a bug in the code for sorting

I am experiencing a similar bug related to oneColumnModeDomSort: true - it seems this option is not being respected if the grid is initialized in oneColumnMode and the HTML GridStackElements have gs-x and gs-y attributes. It seems that these attributes are used even if they should be ignored because oneColumnModeDomSort: true.

However, sorting works as expected if the grid is initialized on a large screen (not using oneColumnMode) and then resized so that oneColumnMode kicks in.

I know this is departing perhaps from the original bug, but wanted to get a reply in here as the above comment seemed appropriate.

jjdinho avatar Jul 22 '22 13:07 jjdinho

fixing @doktordirk and @jjdinho bug above in next release, closing the remaining issue as not explicit about what needs to be long and too convoluted. @harrington101 if you need this fixed file a very simple separate bug again

adumesny avatar Oct 23 '22 15:10 adumesny