在HTML画布上调整旋转矩形的大小

3
我有一个 HTML 5 画布实例,上面画了一个矩形。
我的绘图函数考虑了缩放角度并使用相对坐标。
相对坐标基于三个变量:矩形左上角点、矩形宽度和矩形高度。
矩形宽度和矩形高度通过两个点计算得出:矩形左上角点和矩形右下角点。
总之,绘图函数依赖于矩形左上角点、矩形右下角点和旋转。这是以下文本的重要点!
以下是代码片段:
var canvas = document.getElementById('imageCanvas');
var ctx = canvas.getContext('2d');
var xTopLeft = 550; 
var yTopLeft = 200;
var xBottomRight = 750; 
var yBottomRight = 450; 
var w = Math.max(xTopLeft, xBottomRight) - Math.min(xTopLeft, xBottomRight);
var h = Math.max(yTopLeft, yBottomRight) - Math.min(yTopLeft, yBottomRight);
var r = 1;

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.save()
    ctx.translate(xTopLeft + w / 2, yTopLeft + h / 2);
    ctx.rotate(r);
    ctx.fillStyle = "yellow";
    ctx.fillRect(w / 2 * (-1), h / 2 * (-1), w, h);
    ctx.restore()
    }

这是我的矩形,带有许多控件:八个调整大小的手柄(白色)和一个旋转手柄(绿色):

enter image description here

旋转正常工作。

调整大小也正常工作。

我还尝试在旋转后实现调整大小。这是我的方法和一个简单的图示:

enter image description here

  1. 获取红色点的坐标(它是鼠标指针坐标)
  2. 使用负角度去旋转点来获得旋转前的坐标
function rotatePoint(x, y, center_x, center_y, angle) {
    var new_x = (x - cx) * Math.cos(angle) - (y - cy) * Math.sin(angle) + cx;
    var new_y = (x - cx) * Math.sin(angle) + (y - cy) * Math.cos(angle) + cy;
    return [new_x, new_y]
}
  1. 更新xTopLeftyTopLeft并重新绘制
  2. 完成

这种方法背后的思想很简单。由于我的绘图函数依赖于矩形左上角点和右下角点,我只需要获取它们的新坐标即可。

例如,这里是B点的简化代码:

if (point == 'B') {
    var newPointB = rotatePoint(mouse.x, mouse.y, center_x, center_y, -r);
    xBottomRight = newPointB[0];
    yTopLeft = newPointB[1];
}

但是它不能像预期的那样工作:当我调整大小时,我的旋转矩形会移动、跳跃并且完全不按要求运行。

在寻找解决方法时,我偶然发现了这篇文章。文章涵盖了我的问题,但我不理解作者的方法,无法实施。

为什么我应该始终锁定A点的坐标?我的左上角手柄旨在向西北方向调整矩形大小,因此需要更改A点的坐标...

为什么我们要在去旋转之前重新计算中心点?这破坏了统一矩阵变换的思想...

在我的情况下,正确的算法是什么呢?


当您“去旋转”鼠标点时,您使用的是矩形当前旋转的-angle,对吗?此外,在所引用的文章中,“A”点只是拖动点的相反点。在您的示例中,您将在拖动操作期间锁定“C”点... - Trentium
@Trentium 是的,对于去旋转,我使用负角度:newPoint = rotatePoint(mouse.x, mouse.y, center_x, center_y, -angle)。我尝试锁定相反的点,但矩形仍然会移动... - SagRU
1
请注意,当调整大小时,中心点的x和y会随着拖动变化的一半而改变(即,您的矩形正在增大或缩小,因此矩形的中心点正在改变),并且在这样做时,如果锁定拖动的相反角落,则需要更改矩形的位置以使锁定的角落相对于全局坐标保持不变。 - Trentium
1个回答

1

我之前也遇到过同样的问题。原来我使用的角度单位是度数。在rotatePoint函数中尝试将角度乘以(Math.PI / 180)。


你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community
谢谢!我自己也遇到了这个问题。 - Pierre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接