Skip to content

Commit

Permalink
Try new algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
Heenawter committed Dec 12, 2024
1 parent 598d3de commit 8fbdd94
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 37 deletions.
4 changes: 2 additions & 2 deletions examples/grid_example/public/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,8 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
layout={currentLayout}
gridSettings={{
gutterSize: DASHBOARD_MARGIN_SIZE,
rowHeight: DASHBOARD_GRID_HEIGHT,
columnCount: DASHBOARD_GRID_COLUMN_COUNT,
rowHeight: 100,
columnCount: 8,
}}
renderPanelContents={renderBasicPanel}
onLayoutChange={(newLayout) => {
Expand Down
20 changes: 5 additions & 15 deletions examples/grid_example/public/serialized_grid_layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,10 @@ export function setSerializedGridLayout(state: MockSerializedDashboardState) {

const initialState: MockSerializedDashboardState = {
panels: {
panel1: { id: 'panel1', gridData: { i: 'panel1', x: 0, y: 0, w: 12, h: 6, row: 0 } },
panel2: { id: 'panel2', gridData: { i: 'panel2', x: 0, y: 6, w: 8, h: 4, row: 0 } },
panel3: { id: 'panel3', gridData: { i: 'panel3', x: 8, y: 6, w: 12, h: 4, row: 0 } },
panel4: { id: 'panel4', gridData: { i: 'panel4', x: 0, y: 10, w: 48, h: 4, row: 0 } },
panel5: { id: 'panel5', gridData: { i: 'panel5', x: 12, y: 0, w: 36, h: 6, row: 0 } },
panel6: { id: 'panel6', gridData: { i: 'panel6', x: 24, y: 6, w: 24, h: 4, row: 0 } },
panel7: { id: 'panel7', gridData: { i: 'panel7', x: 20, y: 6, w: 4, h: 2, row: 0 } },
panel8: { id: 'panel8', gridData: { i: 'panel8', x: 20, y: 8, w: 4, h: 2, row: 0 } },
panel9: { id: 'panel9', gridData: { i: 'panel9', x: 0, y: 0, w: 12, h: 16, row: 1 } },
panel10: { id: 'panel10', gridData: { i: 'panel10', x: 24, y: 0, w: 12, h: 6, row: 2 } },
panel1: { id: 'panel1', gridData: { i: 'panel1', x: 0, y: 0, w: 4, h: 3, row: 0 } },
panel2: { id: 'panel2', gridData: { i: 'panel2', x: 0, y: 3, w: 4, h: 2, row: 0 } },
panel3: { id: 'panel3', gridData: { i: 'panel3', x: 0, y: 5, w: 8, h: 1, row: 0 } },
panel4: { id: 'panel4', gridData: { i: 'panel4', x: 4, y: 0, w: 4, h: 5, row: 0 } },
},
rows: [
{ title: 'Large section', collapsed: false },
{ title: 'Small section', collapsed: false },
{ title: 'Another small section', collapsed: false },
],
rows: [{ title: 'Large section', collapsed: false }],
};
4 changes: 2 additions & 2 deletions examples/grid_example/public/use_mock_dashboard_api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ export const useMockDashboardApi = ({
row: 0,
x: 0,
y: 0,
w: DEFAULT_PANEL_WIDTH,
h: DEFAULT_PANEL_HEIGHT,
w: 4,
h: 4,
},
},
});
Expand Down
3 changes: 2 additions & 1 deletion packages/kbn-grid-layout/grid/grid_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ export const GridLayout = ({
* the layout sent in as a prop is not guaranteed to be valid (i.e it may have floating panels) -
* so, we need to loop through each row and ensure it is compacted
*/
const { columnCount } = gridLayoutStateManager.runtimeSettings$.getValue();
newLayout.forEach((row, rowIndex) => {
newLayout[rowIndex] = resolveGridRow(row);
newLayout[rowIndex] = resolveGridRow(row, columnCount);
});
gridLayoutStateManager.gridLayout$.next(newLayout);
}
Expand Down
8 changes: 6 additions & 2 deletions packages/kbn-grid-layout/grid/use_grid_layout_events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,17 @@ export const useGridLayoutEvents = ({

// resolve destination grid
const destinationGrid = nextLayout[targetRowIndex];
const resolvedDestinationGrid = resolveGridRow(destinationGrid, requestedGridData);
const resolvedDestinationGrid = resolveGridRow(
destinationGrid,
columnCount,
requestedGridData
);
nextLayout[targetRowIndex] = resolvedDestinationGrid;

// resolve origin grid
if (hasChangedGridRow) {
const originGrid = nextLayout[lastRowIndex];
const resolvedOriginGrid = resolveGridRow(originGrid);
const resolvedOriginGrid = resolveGridRow(originGrid, columnCount);
nextLayout[lastRowIndex] = resolvedOriginGrid;
}
if (!deepEqual(currentLayout, nextLayout)) {
Expand Down
96 changes: 81 additions & 15 deletions packages/kbn-grid-layout/grid/utils/resolve_grid_row.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { without } from 'lodash';
import { GridPanelData, GridRowData } from '../types';

const collides = (panelA: GridPanelData, panelB: GridPanelData) => {
Expand Down Expand Up @@ -40,14 +41,14 @@ export const getKeysInOrder = (panels: GridRowData['panels'], draggedId?: string
const panelA = panels[panelKeyA];
const panelB = panels[panelKeyB];

// sort by row first
if (panelA.row > panelB.row) return 1;
if (panelA.row < panelB.row) return -1;

// if rows are the same. Is either panel being dragged?
if (panelA.id === draggedId) return -1;
if (panelB.id === draggedId) return 1;

// sort by row first
if (panelA.row > panelB.row) return 1;
if (panelA.row < panelB.row) return -1;

// if rows are the same and neither panel is being dragged, sort by column
if (panelA.column > panelB.column) return 1;
if (panelA.column < panelB.column) return -1;
Expand Down Expand Up @@ -79,30 +80,95 @@ const compactGridRow = (originalLayout: GridRowData) => {

export const resolveGridRow = (
originalRowData: GridRowData,
columnCount: number,
dragRequest?: GridPanelData
): GridRowData => {
const nextRowData = { ...originalRowData, panels: { ...originalRowData.panels } };

// Apply drag request
// apply drag request
if (dragRequest) {
nextRowData.panels[dragRequest.id] = dragRequest;
}
// return nextRowData;

// push all panels down if they collide with another panel
// calculate the total height of the grid
const panelRows = Object.values(nextRowData.panels).map(
({ row: panelRow, height: panelHeight }) => panelRow + panelHeight
);
const rowCount = Math.max(...panelRows);

// build an empty 2D array representing the current grid
const collisionGrid: string[][][] = new Array(rowCount)
.fill(null)
.map(() => new Array(columnCount).fill(null).map(() => new Array(0)));

// for each panel, push its ID into the grid cells that it occupies
const sortedKeys = getKeysInOrder(nextRowData.panels, dragRequest?.id);
let orderToMove = sortedKeys.reverse();
if (dragRequest) {
orderToMove = orderToMove.filter((key) => key !== dragRequest.id);
}
sortedKeys.forEach((panelKey) => {
const panel = nextRowData.panels[panelKey];
for (let row = panel.row; row < panel.row + panel.height; row++) {
for (let column = panel.column; column < panel.column + panel.width; column++) {
collisionGrid[row][column].push(panelKey);
}
}
});

for (const key of sortedKeys) {
const panel = nextRowData.panels[key];
const collisions = getAllCollisionsWithPanel(panel, nextRowData, sortedKeys);
// handle all collisions, row by row
const getCollisionsInOrder = (row: number) => {
let collisions: string[] = [];
collisionGrid[row].forEach((collisionArray) => {
if (collisionArray.length > 1) {
collisions = collisions.concat(
dragRequest ? collisionArray.filter((key) => key !== dragRequest.id) : collisionArray
);
}
});
const collisionsInOrder: string[] = [];
orderToMove.forEach((panelKey) => {
if (collisions.includes(panelKey)) {
collisionsInOrder.push(panelKey);
}
});
return collisionsInOrder;
};

for (let row = dragRequest?.row ?? 0; row < collisionGrid.length; row++) {
let collisions = getCollisionsInOrder(row);
while (collisions.length > 0) {
// don't move on to the next row until the current row has no more collisions
for (const panelKey of collisions) {
// move the panel down
const panel = nextRowData.panels[panelKey];
nextRowData.panels[panelKey].row += 1;

for (const collision of collisions) {
const rowOverlap = panel.row + panel.height - collision.row;
if (rowOverlap > 0) {
collision.row += rowOverlap;
// update the collision grid to keep it in sync
const currentGridHeight = collisionGrid.length;
if (row + panel.height >= currentGridHeight) {
collisionGrid.push(new Array(columnCount).fill(null).map(() => new Array(0)));
}
for (
let panelColumn = panel.column;
panelColumn < panel.column + panel.width;
panelColumn++
) {
collisionGrid[panel.row - 1][panelColumn] = without(
collisionGrid[panel.row - 1][panelColumn],
panelKey
);
collisionGrid[panel.row + panel.height - 1][panelColumn].push(panelKey);
}

collisions = getCollisionsInOrder(row);
if (collisions.length <= 0) {
// no more collisions; break out early of "push panel down" loop
break;
}
}
}
}

const compactedGrid = compactGridRow(nextRowData);
return compactedGrid;
};

0 comments on commit 8fbdd94

Please sign in to comment.