From e13812938b066dbe1d0f4ec8cfb1ff5900cdaf18 Mon Sep 17 00:00:00 2001 From: Jakub Bialas Date: Wed, 11 Dec 2024 09:03:28 +0100 Subject: [PATCH] feat: improve no compact mode without collision prevent --- .../src/lib/grid.component.ts | 8 ++-- .../src/lib/utils/grid.utils.ts | 17 ++++++-- .../src/lib/utils/react-grid-layout.utils.ts | 43 +++++++++++++------ 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/projects/angular-grid-layout/src/lib/grid.component.ts b/projects/angular-grid-layout/src/lib/grid.component.ts index 73f9330..d06fde5 100644 --- a/projects/angular-grid-layout/src/lib/grid.component.ts +++ b/projects/angular-grid-layout/src/lib/grid.component.ts @@ -8,7 +8,7 @@ import { KtdGridItemComponent } from './grid-item/grid-item.component'; import { combineLatest, empty, merge, NEVER, Observable, Observer, of, Subscription } from 'rxjs'; import { exhaustMap, map, startWith, switchMap, takeUntil } from 'rxjs/operators'; import { ktdGetGridItemRowHeight, ktdGridItemDragging, ktdGridItemLayoutItemAreEqual, ktdGridItemResizing } from './utils/grid.utils'; -import { compact } from './utils/react-grid-layout.utils'; +import { cloneLayoutItem, compact } from './utils/react-grid-layout.utils'; import { GRID_ITEM_GET_RENDER_DATA_TOKEN, KtdGridBackgroundCfg, KtdGridCfg, KtdGridCompactType, KtdGridItemRenderData, KtdGridLayout, KtdGridLayoutItem } from './grid.definitions'; @@ -541,9 +541,11 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte * Set the new layout to be the layout in which the calcNewStateFunc would be executed. * NOTE: using the mutated layout is the way to go by 'react-grid-layout' utils. If we don't use the previous layout, * some utilities from 'react-grid-layout' would not work as expected. + * + * In non-compact mode it is best to use copy of original layout, to prevent items from spreading on the grid */ - const currentLayout: KtdGridLayout = newLayout || this.layout; - + const isCompactLayout = (['horizontal', 'vertical'] as KtdGridCompactType[]).includes(this.compactType) + const currentLayout: KtdGridLayout = isCompactLayout ? (newLayout || this.layout) : this.layout.map((l) => cloneLayoutItem(l)); // Get the correct newStateFunc depending on if we are dragging or resizing const calcNewStateFunc = type === 'drag' ? ktdGridItemDragging : ktdGridItemResizing; diff --git a/projects/angular-grid-layout/src/lib/utils/grid.utils.ts b/projects/angular-grid-layout/src/lib/utils/grid.utils.ts index e91e4aa..abf5c28 100644 --- a/projects/angular-grid-layout/src/lib/utils/grid.utils.ts +++ b/projects/angular-grid-layout/src/lib/utils/grid.utils.ts @@ -225,9 +225,20 @@ export function ktdGridItemResizing(gridItem: KtdGridItemComponent, config: KtdG } - const newLayoutItems: LayoutItem[] = config.layout.map((item) => { - return item.id === gridItemId ? layoutItem : item; - }); + const layoutItems: LayoutItem[] = config.layout; + const resizedLayoutItem: LayoutItem = layoutItems.find(item => item.id === gridItemId)!; + let newLayoutItems: LayoutItem[] = moveElement( + layoutItems, + resizedLayoutItem, + undefined, + undefined, + true, + config.preventCollision, + compactionType, + config.cols, + layoutItem.w, + layoutItem.h, + ); return { layout: compact(newLayoutItems, compactionType, config.cols), diff --git a/projects/angular-grid-layout/src/lib/utils/react-grid-layout.utils.ts b/projects/angular-grid-layout/src/lib/utils/react-grid-layout.utils.ts index ae6ebc0..a76ab2e 100644 --- a/projects/angular-grid-layout/src/lib/utils/react-grid-layout.utils.ts +++ b/projects/angular-grid-layout/src/lib/utils/react-grid-layout.utils.ts @@ -383,6 +383,8 @@ export function getStatics(layout: Layout): Array { * @param {LayoutItem} l element to move. * @param {Number} [x] X position in grid units. * @param {Number} [y] Y position in grid units. + * @param {Number} [w] width in grid units. + * @param {Number} [h] height in grid units. */ export function moveElement( layout: Layout, @@ -393,6 +395,8 @@ export function moveElement( preventCollision: boolean | null | undefined, compactType: CompactType, cols: number, + w: number | null | undefined = undefined, + h: number | null | undefined = undefined, ): Layout { // If this is static and not explicitly enabled as draggable, // no move is possible, so we can short-circuit this immediately. @@ -401,17 +405,24 @@ export function moveElement( } // Short-circuit if nothing to do. - if (l.y === y && l.x === x) { + if ((l.y === y || y === undefined) && (l.x === x || x === undefined) && (l.w === w || w === undefined) && (l.h === h || h === undefined)) { return layout; } - log( - `Moving element ${l.id} to [${String(x)},${String(y)}] from [${l.x},${ - l.y - }]`, - ); + if ((l.y !== y && y !== undefined) || (l.x !== x && x !== undefined)) { + log( + `Moving element ${l.id} to [${String(x)},${String(y)}] from [${l.x},${l.y}]`, + ); + } + if ((l.w !== w && w !== undefined) || (l.h !== h && h !== undefined)) { + log( + `Resizing element ${l.id} to ${String(w)} x ${String(h)} from ${l.w} x ${l.h}`, + ); + } const oldX = l.x; const oldY = l.y; + const oldW = l.w; + const oldH = l.h; // This is quite a bit faster than extending the object if (typeof x === 'number') { @@ -420,6 +431,12 @@ export function moveElement( if (typeof y === 'number') { l.y = y; } + if (typeof w === 'number') { + l.w = w; + } + if (typeof h === 'number') { + l.h = h; + } l.moved = true; // If this collides with anything, move it. @@ -443,6 +460,8 @@ export function moveElement( log(`Collision prevented on ${l.id}, reverting.`); l.x = oldX; l.y = oldY; + l.w = oldW; + l.h = oldH; l.moved = false; return layout; } @@ -503,8 +522,8 @@ export function moveElementAwayFromCollision( cols: number, ): Layout { const compactH = compactType === 'horizontal'; - // Compact vertically if not set to horizontal - const compactV = compactType !== 'horizontal'; + const compactV = compactType === 'vertical'; + const noCompact = !compactH && !compactV; const preventCollision = collidesWith.static; // we're already colliding (not for static items) // If there is enough space above the collision to put this element, move it there. @@ -519,12 +538,12 @@ export function moveElementAwayFromCollision( x: compactH ? Math.max(collidesWith.x - itemToMove.w, 0) : itemToMove.x, - y: compactV + y: (compactV || (noCompact && collidesWith.y + collidesWith.h / 2 >= itemToMove.y + itemToMove.h / 2)) ? Math.max(collidesWith.y - itemToMove.h, 0) : itemToMove.y, w: itemToMove.w, h: itemToMove.h, - id: '-1', + id: itemToMove.id, // do not compare with itself }; // No collision? If so, we can go up there; otherwise, we'll end up moving down as normal @@ -538,7 +557,7 @@ export function moveElementAwayFromCollision( layout, itemToMove, compactH ? fakeItem.x : undefined, - compactV ? fakeItem.y : undefined, + (compactV || noCompact) ? fakeItem.y : undefined, isUserAction, preventCollision, compactType, @@ -551,7 +570,7 @@ export function moveElementAwayFromCollision( layout, itemToMove, compactH ? itemToMove.x + 1 : undefined, - compactV ? itemToMove.y + 1 : undefined, + compactV ? itemToMove.y + 1 : (noCompact ? Math.max(itemToMove.y + 1, collidesWith.y + 1) : undefined), isUserAction, preventCollision, compactType,