From 16bf8001ae8ae07e50fac53067f4ee07b8a41866 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Thu, 18 Sep 2025 12:37:52 +0000 Subject: [PATCH] feat(dees-dashboardgrid): implement collision detection during widget swap to prevent overlaps --- readme.plan.md | Bin 9119 -> 9364 bytes test/test.dashboardgrid-layout.node.ts | 28 +++++++++++++++++++ ts_web/elements/dees-dashboardgrid/layout.ts | 13 ++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 test/test.dashboardgrid-layout.node.ts diff --git a/readme.plan.md b/readme.plan.md index d0d0bc56024fe9ccc4588dad25ae56d084cbecfd..aa7a75e6bd1604e32cfad2544db2acfae9d62d43 100644 GIT binary patch delta 229 zcmXxeO$x#=5C!19cMu-B_7EZ{u5_h{2pyYg9Z8drpQ^a<5W4RbJfbP;cILg0*DYSl zcQ=0CN5jXeWv|I$F4w^XdmJz$7n5gru04k!)<6s>McYthg~%bIvL5zZbz*8bO(mbK zR_qZjwca$93Os*u( { + 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(); diff --git a/ts_web/elements/dees-dashboardgrid/layout.ts b/ts_web/elements/dees-dashboardgrid/layout.ts index 5c81473..696b922 100644 --- a/ts_web/elements/dees-dashboardgrid/layout.ts +++ b/ts_web/elements/dees-dashboardgrid/layout.ts @@ -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; } } }