In an app, a user can click the edge of a rectangular box to resize it to the "smallest valid size" in that direction. For example, if they clicked the right edge, the box would resize to the smallest valid width, leaving the left edge where it is. If they clicked the bottom, it would shrink the bottom edge as far as possible without becoming invalid. The criteria for what "valid" is doesn't matter, but it takes some work to calculate.
Now I have written some code to make this work for the right edge of the box, using a binary search to close in on the smallest valid size. But I need a general solution which does not involve repeating my code in four different variations, and I can't figure out how to do it.
The code as it is now (supporting right edge only):
interface Zone {
x: number;
y: number;
width: number;
height: number;
}
enum Side {
'top',
'left',
'bottom',
'right',
}
enum ResizeDirection {
NEGATIVE = -1,
POSITIVE = 1,
}
async function findMinValidZone(
zone: Zone,
minWidth: number,
maxWidth: number,
side: Side,
validator: (z: Zone) => Promise<boolean>
): Promise<Zone> {
const area = {...zone};
let d = maxWidth;
let step = maxWidth - minWidth;
let currentDirection = ResizeDirection.NEGATIVE; // positive means widen the area, negative means narrow it
let lastGood: number = d;
do {
d += step * currentDirection;
if (d < minWidth || d > maxWidth) {
break;
}
area.width = d;
const ok = await validator(area);
if (ok) {
currentDirection = ResizeDirection.NEGATIVE;
lastGood = d;
} else {
currentDirection = ResizeDirection.POSITIVE;
}
step = step / 2;
} while (step >= 1);
area.width = lastGood;
return area;
}