From ec4b07c09384ebe842cd722a23af7481943c1b24 Mon Sep 17 00:00:00 2001 From: amanosacrous Date: Wed, 17 Sep 2025 12:48:26 +0200 Subject: [PATCH] fix: move element horizontally between two others Closes #135. includes fix and test. --- .../utils/react-grid-layout-multiple.utils.ts | 14 +++++--- .../src/lib/utils/react-grid-layout.utils.ts | 11 +++++-- .../tests/react-grid-layout-utils.spec.ts | 33 +++++++++++++++++-- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/projects/angular-grid-layout/src/lib/utils/react-grid-layout-multiple.utils.ts b/projects/angular-grid-layout/src/lib/utils/react-grid-layout-multiple.utils.ts index b304a9f..961bef2 100644 --- a/projects/angular-grid-layout/src/lib/utils/react-grid-layout-multiple.utils.ts +++ b/projects/angular-grid-layout/src/lib/utils/react-grid-layout-multiple.utils.ts @@ -36,7 +36,7 @@ export function KtdMoveMultipleElements( compactType: CompactType, cols: number ): Layout { - let axes = compactType === 'vertical' ? 'y' : 'x'; + const axis = compactType === 'vertical' ? 'y' : 'x'; // Short-circuit if nothing to do. if (items.every((item) => item.l.y === item.y && item.l.x === item.x)) { return layout; @@ -83,11 +83,16 @@ export function KtdMoveMultipleElements( // can apply a repositioning if the collide item its on the first row/col let minAxe: number | undefined; if (itemsSorted && itemsSorted.length) { - minAxe = itemsSorted[0][axes]; + minAxe = itemsSorted[0][axis]; } // For each element, detect collisions and move the collided element by +1 itemsSorted.forEach((item) => { + const collisions: LayoutItem[] = getAllCollisions(sorted, item); + const minCollisionAxis: number | undefined = collisions.length + ? Math.min(collisions[0][axis], collisions[collisions.length - 1][axis]) // Take collision closest to 0; sorted but direction unknown + : undefined; + // Move each item that collides away from this element. for (let i = 0, len = collisions.length; i < len; i++) { const collision = collisions[i]; @@ -100,13 +105,14 @@ export function KtdMoveMultipleElements( if (collision.moved) { continue; } + const firstAxis: boolean = minAxe === item[axis] && minCollisionAxis===collision[axis]; // Don't move static items - we have to move *this* element away if (collision.static && !item.static) { layout = KtdMoveElementsAwayFromCollision( layout, collision, item, - minAxe === item[axes] ? isUserAction : false, // We only allow repositioning the "item" element if "collision" is in the first row of the moved block + firstAxis && isUserAction, // Allow repositioning "item" only if "collision" and "item" are in the first collision row/col compactType, cols ); @@ -115,7 +121,7 @@ export function KtdMoveMultipleElements( layout, item, collision, - minAxe === item[axes] ? isUserAction : false, // We only allow repositioning the "collision" element if "item" is in the first row of the moved block + firstAxis && isUserAction, // Allow repositioning "collision" only if "collision" and "item" are in the first collision row/col compactType, 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 58bf306..30e7ea3 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 @@ -429,6 +429,8 @@ export function moveElement( l.y }]`, ); + + const axis = compactType === 'vertical' ? 'y' : 'x'; const oldX = l.x; const oldY = l.y; @@ -475,6 +477,11 @@ export function moveElement( } at [${collision.x},${collision.y}]`, ); + const minCollisionAxis: number | undefined = + collisions.length + ? Math.min(collisions[0][axis], collisions[collisions.length - 1][axis]) // Take collision closest to 0; sorted but direction unknown + : undefined; + // Short circuit so we can't infinite loop if (collision.moved) { continue; @@ -486,7 +493,7 @@ export function moveElement( layout, collision, l, - isUserAction, + minCollisionAxis===collision[axis] && isUserAction, // Reposition "l" only if "collision" is in the first row/col of collisions list compactType, cols, ); @@ -495,7 +502,7 @@ export function moveElement( layout, l, collision, - isUserAction, + minCollisionAxis===collision[axis] && isUserAction, // Reposition "collision" only if is in the first row/col of collisions list compactType, cols, ); diff --git a/projects/angular-grid-layout/src/lib/utils/tests/react-grid-layout-utils.spec.ts b/projects/angular-grid-layout/src/lib/utils/tests/react-grid-layout-utils.spec.ts index 1b9b8e4..8ccd7a7 100644 --- a/projects/angular-grid-layout/src/lib/utils/tests/react-grid-layout-utils.spec.ts +++ b/projects/angular-grid-layout/src/lib/utils/tests/react-grid-layout-utils.spec.ts @@ -405,7 +405,7 @@ describe('compact horizontal', () => { }); }); -describe('moveElementAffectingOtherItems', () => { +describe('Test to move one element affecting other items', () => { function compactAndMove( layout, layoutItem, @@ -432,7 +432,7 @@ describe('moveElementAffectingOtherItems', () => { ); } - it('Move element up, pushing the rest of the grid down', () => { + it('Test that moving an element into the top push the rest of the grid down', () => { const layout = [ {id: '0', x: 1, y: 0, w: 24, h: 1}, {id: '1', x: 1, y: 1, w: 8, h: 1}, @@ -462,4 +462,33 @@ describe('moveElementAffectingOtherItems', () => { {id: '5', x: 17, y: 3+8, w: 8, h: 3, moved: false, static: false}, ]); }); + + it('keeps the original order when moving an element horizontally between two elements', () => { + const layout = [ + {id:"0", x:0, y:0, w:6, h:2}, + {id:"1", x:12, y:0, w:12, h:2}, + {id:"2", x:0, y:2, w:6, h:2}, + {id:"3", x:6, y:2, w:12, h:1}, + {id:"4", x:6, y:3, w:6, h:2} + ]; + const layoutItem = layout[2]; + expect( + compactAndMove( + layout, + layoutItem, + 6, // x + 2, // y + true, //isUserAction + false, // preventCollision + 'vertical', // compactType, + 30 // cols + ) + ).toEqual([ + {id:"0", x:0, y:0, w:6, h:2, moved: false, static: false}, + {id:"1", x:12, y:0, w:12, h:2, moved: false, static: false}, + {id:"2", x:0+6, y:0, w:6, h:2, moved: false, static: false}, + {id:"3", x:6, y:2, w:12, h:1, moved: false, static: false}, + {id:"4", x:6, y:3, w:6, h:2, moved: false, static: false}, + ]); + }); });