From 1a75e7bad0b6574fe674d94c08781b7ba178bca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Z=C3=ADpek?= Date: Wed, 24 Aug 2022 19:32:50 +0200 Subject: [PATCH] Fixed dragging not positioning properly --- .../src/pages/dashboard/hooks/useDragging.ts | 57 ++++++++++++------- client/src/utils/range.ts | 12 ++++ 2 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 client/src/utils/range.ts diff --git a/client/src/pages/dashboard/hooks/useDragging.ts b/client/src/pages/dashboard/hooks/useDragging.ts index ddadbe7..37d4080 100644 --- a/client/src/pages/dashboard/hooks/useDragging.ts +++ b/client/src/pages/dashboard/hooks/useDragging.ts @@ -2,6 +2,7 @@ import { useWindowEvent } from '@/utils/hooks/useWindowEvent' import { useState } from 'preact/hooks' import { BoxDefinition } from '../types' import { GRID_H_SNAP, GRID_WIDTH } from '../constants' +import { range } from '@/utils/range' type Props = { cellWidth: number @@ -26,22 +27,42 @@ export const useDragging = ({ cellWidth, boxes, box }: Props) => { const dragY = Math.max(0, Math.round(state.y / GRID_H_SNAP) * GRID_H_SNAP) - const gridHeights = Array(GRID_WIDTH) - .fill(null) - .map((_, index) => { - return boxes - .filter( - (b) => - b.id !== box.id && - b.x <= index && - b.x + b.w > index && - ((b.y < dragY + box.h && dragY < b.y + b.h) || b.y < dragY) - ) - .reduce( - (acc, item) => (item.y + item.h > acc ? item.y + item.h : acc), - 0 - ) + const maxHeight = Math.max( + ...range(actualX, actualX + box.w).map((x) => { + // All boxes that are in this column + const boxesAtColumn = boxes.filter( + (b) => b.id !== box.id && b.x <= x && b.x + b.w > x + ) + + // Find boxes that would be colliding at this position + const collisions = boxesAtColumn.filter( + (b) => b.y < dragY + box.h && dragY < b.y + b.h + ) + + if (collisions.length > 0) { + const upperBoxes = boxesAtColumn.filter((b) => b.y + b.h > dragY) + + // Try to find a space to fit somewhere up + for (let i = 1; i < upperBoxes.length; i++) { + const prevBox = upperBoxes[i - 1] + const thisBox = upperBoxes[i] + + if (thisBox.y - (prevBox.y + prevBox.h) >= box.h) { + return prevBox.y + prevBox.h + } + } + + // Nothing found, we'll have to stack to the upper box + const lastBox = boxesAtColumn[boxesAtColumn.length - 1] + + return lastBox ? lastBox.y + lastBox.h : 0 + } else { + const bottomBox = boxesAtColumn.reverse().find((b) => b.y < dragY) + + return bottomBox ? bottomBox.y + bottomBox.h : 0 + } }) + ) useWindowEvent('mousemove', (e) => { if (state.active) { @@ -58,11 +79,7 @@ export const useDragging = ({ cellWidth, boxes, box }: Props) => { setDragging: setState, draggingPosition: { x: actualX, - y: Math.max( - ...Array(box.w) - .fill(null) - .map((_, x) => gridHeights[actualX + x]) - ), + y: maxHeight, }, } } diff --git a/client/src/utils/range.ts b/client/src/utils/range.ts new file mode 100644 index 0000000..fee5401 --- /dev/null +++ b/client/src/utils/range.ts @@ -0,0 +1,12 @@ +export function range(length: number): number[] +export function range(start: number, end: number, step?: number): number[] + +export function range(a1: number, a2?: number, a3?: number): number[] { + const start = typeof a2 === 'undefined' ? 0 : a1 + const end = typeof a2 === 'undefined' ? a1 : a2 + const step = a3 ?? 1 + + return Array(end - start) + .fill(null) + .map((_, i) => start + i * step) +}