feat(dees-dashboardgrid): implement collision detection during widget swap to prevent overlaps
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								readme.plan.md
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								readme.plan.md
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										28
									
								
								test/test.dashboardgrid-layout.node.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								test/test.dashboardgrid-layout.node.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| import { tap, expect } from '@push.rocks/tapbundle'; | ||||
|  | ||||
| import { | ||||
|   resolveWidgetPlacement, | ||||
|   collectCollisions, | ||||
| } from '../ts_web/elements/dees-dashboardgrid/layout.ts'; | ||||
| import type { DashboardWidget } from '../ts_web/elements/dees-dashboardgrid/types.ts'; | ||||
|  | ||||
| tap.test('dashboardgrid does not overlap widgets after swap attempt', async () => { | ||||
|   const widgets: DashboardWidget[] = [ | ||||
|     { id: 'w0', x: 6, y: 5, w: 1, h: 3 }, | ||||
|     { id: 'w1', x: 6, y: 1, w: 1, h: 3 }, | ||||
|     { id: 'w2', x: 3, y: 0, w: 2, h: 2 }, | ||||
|     { id: 'w3', x: 9, y: 0, w: 1, h: 2 }, | ||||
|     { id: 'w4', x: 4, y: 3, w: 1, h: 2 }, | ||||
|   ]; | ||||
|  | ||||
|   const placement = resolveWidgetPlacement(widgets, 'w0', { x: 6, y: 3 }, 12); | ||||
|   expect(placement).toBeTruthy(); | ||||
|  | ||||
|   const layout = placement!.widgets; | ||||
|   for (const widget of layout) { | ||||
|     const collisions = collectCollisions(layout, widget, widget.x, widget.y, widget.w, widget.h); | ||||
|     expect(collisions).toBeEmptyArray(); | ||||
|   } | ||||
| }); | ||||
|  | ||||
| export default tap.start(); | ||||
| @@ -164,9 +164,20 @@ export const resolveWidgetPlacement = ( | ||||
|         // Use the original position of the moving widget for a clean swap | ||||
|         // This prevents the "snapping together" issue where both widgets end up at the same position | ||||
|         const swapTarget = original; | ||||
|         const previousOtherPosition = { x: otherClone.x, y: otherClone.y }; | ||||
|         otherClone.x = swapTarget.x; | ||||
|         otherClone.y = swapTarget.y; | ||||
|         return { widgets: sourceWidgets, movedWidgets: [moving.id, otherClone.id], swappedWith: otherClone.id }; | ||||
|  | ||||
|         const swapValid = | ||||
|           collectCollisions(sourceWidgets, moving, moving.x, moving.y, moving.w, moving.h).length === 0 && | ||||
|           collectCollisions(sourceWidgets, otherClone, otherClone.x, otherClone.y, otherClone.w, otherClone.h).length === 0; | ||||
|  | ||||
|         if (swapValid) { | ||||
|           return { widgets: sourceWidgets, movedWidgets: [moving.id, otherClone.id], swappedWith: otherClone.id }; | ||||
|         } | ||||
|  | ||||
|         otherClone.x = previousOtherPosition.x; | ||||
|         otherClone.y = previousOtherPosition.y; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user