javascript - 概括找到矩形所有四个边的最小尺寸解决方案

标签 javascript typescript

在应用程序中,用户可以单击矩形框的边缘,将其大小调整为该方向的“最小有效大小”。例如,如果他们单击右边缘,则框的大小将调整为最小有效宽度,而左边缘保持原样。如果他们点击底部,它会尽可能缩小底部边缘,而不会失效。 “有效”的标准并不重要,但需要一些工作来计算。

现在我已经编写了一些代码来使其适用于框的右边缘,使用二分搜索来接近最小的有效大小。但我需要一个通用的解决方案,它不涉及在四种不同的变体中重复我的代码,而且我不知道如何做到这一点。

现在的代码(仅支持右边缘):

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/

相关文章:

javascript - 如何使用 Ajax 成功在新选项卡中打开 URL?

angular - 以 ECMAScript 2015 模块为目标时不能使用导入赋值

javascript - 在 Angular HttpClient 中实现接口(interface)有什么用?

javascript - $.ajax 调用无法识别其 url 中的动态变量

javascript - 在 vue.js 中使用 moment.js

javascript - react router v^4.0.0 Uncaught TypeError : Cannot read property 'location' of undefined

javascript - 错误 : Parse Objects not allowed here

typescript - 联合类型允许错误分配所用类型的属性

typescript - PIXI.js 加载器共享资源纹理检测名称中的拼写错误

angular - 如何循环使用部分元素以使用 ng-content 进行投影