在应用程序中,用户可以单击矩形框的边缘,将其大小调整为该方向的“最小有效大小”。例如,如果他们单击右边缘,则框的大小将调整为最小有效宽度,而左边缘保持原样。如果他们点击底部,它会尽可能缩小底部边缘,而不会失效。 “有效”的标准并不重要,但需要一些工作来计算。
现在我已经编写了一些代码来使其适用于框的右边缘,使用二分搜索来接近最小的有效大小。但我需要一个通用的解决方案,它不涉及在四种不同的变体中重复我的代码,而且我不知道如何做到这一点。
现在的代码(仅支持右边缘):
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;
}
最佳答案
我能想到的一种方法是将矩形旋转所需的 90 度的倍数来变换矩形,以便您始终使用右边缘,而不是将其旋转回去以进行验证并在返回时结果。实际的旋转可以使用矩阵变换来完成,但现在我将把实际的旋转函数留给您编写。那么你的通用代码将如下所示:
function findMinValidZone(
zone: Zone,
minwidth: number,
maxWidth: number,
side: Side,
validator: (z: Zone) => Promise<boolean>
): Promise<Zone> {
let rotationAngle: number;
switch (side) {
case Side.bottom:
rotationAngle = -Math.PI / 2;
break;
case Side.left:
rotationAngle = Math.PI;
break;
case Side.right:
rotationAngle = 0;
break;
case Side.top:
rotationAngle = Math.PI / 2;
}
let d = maxWidth;
let step = maxWidth - minwidth;
// rotate the area so that you are always working on the width dimension
// while keeping other dimensions fixed. Then rotate area back again
// when validating and when returning the results
const area = rotateZone({...zone}, rotationAngle);
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(rotateZone(area, -rotationAngle));
if (ok) {
currentDirection = ResizeDirection.NEGATIVE;
lastGood = d;
} else {
currentDirection = ResizeDirection.POSITIVE;
}
step = step / 2;
} while (step >= 1);
area.width = lastGood;
return rotateZone(area, -rotationAngle);
}
我会考虑rotateZone函数本身,但原则上它应该足够简单,使用像https://www.npmjs.com/package/transformation-matrix这样的库。
关于javascript - 概括找到矩形所有四个边的最小尺寸解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68554728/