Skip to content

Commit

Permalink
Improve flow detection when elements have one element is shorter than…
Browse files Browse the repository at this point in the history
… its siblings and vertically centered.
  • Loading branch information
cibernox committed Oct 25, 2024
1 parent cec478f commit bd3a0ad
Showing 1 changed file with 34 additions and 29 deletions.
63 changes: 34 additions & 29 deletions assets/svelte/utils/drag-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,44 +24,49 @@ export function mouseDiff(mouseMovement: CoordsDiff): Coords {
}
}

function centerInAxis(rect: DOMRect, axis: "x" | "y"): number {
return axis === "x" ? rect.x + rect.width / 2 : rect.y + rect.height / 2
}
// Detects if elements flow generally in an horizontal direction, a vertical one or
// both (e.g. they form a grid or overflow to the the next line)
function detectFlow(rects: DOMRect[]) {
let horizontal = false
let vertical = false
// Sort elements by their left position (to analyze horizontal arrangement)
const sortedByLeft = [...rects].sort((a, b) => a.left - b.left);
// Sort elements by their top position (to analyze vertical arrangement)
const sortedByTop = [...rects].sort((a, b) => a.top - b.top);

// Calculate the average horizontal and vertical spacing between elements
const avgHorizontalDiff = getAverageDifference(sortedByLeft, 'left');
const avgVerticalDiff = getAverageDifference(sortedByTop, 'top');

// Determine the dominant flow
if (avgHorizontalDiff > avgVerticalDiff) {
// Check if all elements are roughly centered vertically
const isCenteredHorizontally = checkVerticalCenterAlignment(sortedByLeft);
return isCenteredHorizontally ? 'horizontal' : 'both';
} else if (avgVerticalDiff > avgHorizontalDiff) {
return 'vertical';
}
return 'both';
}

const threshold = 5
// Helper to calculate average difference for a given property (top or left)
function getAverageDifference(rects, property) {
let totalDiff = 0;
for (let i = 1; i < rects.length; i++) {
let prevRect = rects[i - 1]
let currentRect = rects[i]

// Use the centers in each axis to determine flow, not the top/left corners because
// when elements have different heights/widths but are vertically/horizontally aligned
// their corners might not be aligned but the general direction is still clear
let xChange = Math.abs(centerInAxis(currentRect, "x") - centerInAxis(prevRect, "x"))
let yChange = Math.abs(centerInAxis(currentRect, "y") - centerInAxis(prevRect, "y"))

// Check for horizontal flow: significant x change with minimal y change
if (xChange > threshold && yChange < threshold) {
horizontal = true
}
if (yChange > threshold) {
vertical = true
}
totalDiff += Math.abs(rects[i][property] - rects[i - 1][property]);
}
return totalDiff / (rects.length - 1);
}

if (horizontal && vertical) {
return "both"
} else if (horizontal) {
return "horizontal"
} else {
return "vertical"
}
// Helper to check if elements are centered vertically relative to each other
function checkVerticalCenterAlignment(rects) {
const centers = rects.map(rect => (rect.top + rect.bottom) / 2);
const minCenter = Math.min(...centers);
const maxCenter = Math.max(...centers);
return (maxCenter - minCenter) < 17; // tolerance for alignment, adjust as needed
}




// Determines if the drag of the current element should vertical or horizontal based on the
// flow of its siblings
// If prefers a practical approach, checking if the last element is further down (or right)
Expand Down

0 comments on commit bd3a0ad

Please sign in to comment.