简体   繁体   English

在 HTML5 Canvas 上调整旋转形状的大小

[英]Resize rotated shape on HTML5 Canvas

I want to resize a rotated shape without it drifting away.我想调整旋转形状的大小而不让它飘走。 I'm aware that I need to adjust the shape coordinates depending on the rotation angle, but I can't seem to figure out the formula to do it.我知道我需要根据旋转角度调整形状坐标,但我似乎无法弄清楚这样做的公式。

This is what I've managed to do so far ( https://jsfiddle.net/9o3vefym/1/ )这是我迄今为止设法做的事情( https://jsfiddle.net/9o3vefym/1/

<!DOCTYPE html>
<html>
  <body style="margin: 0">
    <canvas
      id="canvas"
      width="400"
      height="400"
      style="border: 1px solid #d3d3d3"
    ></canvas>
    <script>
      const canvas = document.getElementById("canvas");
      const context = canvas.getContext("2d");
      const rect = {
        x: 100,
        y: 100,
        width: 50,
        height: 50,
        angle: 0
      };
      window.onkeydown = keyDown;

      draw();

      function keyDown(evt) {
        if (evt.key == "ArrowRight") {
          rect.width += 5;
        }
        if (evt.key == "ArrowLeft") {
          rect.x -= 5;
          rect.width += 5;
        }
        if (evt.key == "ArrowUp") {
          rect.y -= 5;
          rect.height += 5;
        }
        if (evt.key == "ArrowDown") {
          rect.height += 5;
        }
        if (evt.key == "a") {
          rect.angle -= (45 * Math.PI) / 180;
        }
        if (evt.key == "s") {
          rect.angle += (45 * Math.PI) / 180;
        }
        draw();
      }

      function draw() {
        context.setTransform(1, 0, 0, 1, 0, 0);
        context.clearRect(0, 0, canvas.width, canvas.height);

        const cx = (rect.x * 2 + rect.width) / 2;
        const cy = (rect.y * 2 + rect.height) / 2;
        context.translate(cx, cy);
        context.rotate(rect.angle);
        context.translate(-cx, -cy);

        context.fillRect(rect.x, rect.y, rect.width, rect.height);
      }
    </script>
  </body>
</html>

It works fine if the shape isn't rotated, but it breaks down if I try to resize a rotated shape.如果形状没有旋转,它工作正常,但如果我尝试调整旋转形状的大小,它会崩溃。

For example, If I rotate the rectangle by pressing the key "a" or "s" and then resize it using any of the arrow keys, the rectangle will "drift away".例如,如果我通过按“a”或“s”键旋转矩形,然后使用任何箭头键调整它的大小,矩形将“漂移”。 What I'm trying to do is to keep the rectangle still while resizing it, as it happens when it isn't rotated.我想要做的是在调整矩形大小时保持矩形静止,因为它在不旋转时会发生。

Also, I'm trying to find a solution that doesn't involve changing draw() , since I can't do that in the codebase I'm trying to fix this problem.此外,我正在尝试找到一个不涉及更改draw()的解决方案,因为我无法在代码库中执行此操作,因此我正在尝试解决此问题。

I'd really appreciate some help.我真的很感激一些帮助。

This is not fixable outside of draw() .这在draw()之外是不可修复的。 The problem is that the draw method always assumes the center of the rectangle is the rotation point, but what you want is to be able to shift the point of rotation based on which direction the rectangle is growing in. The only way to avoid drift WITHOUT changing draw() is to always keep the rectangle centered at the same point.问题是 draw 方法总是假设矩形的中心是旋转点,但你想要的是能够根据矩形的生长方向移动旋转点。避免漂移的唯一方法更改draw()是始终将矩形保持在同一点的中心。 See the commented portions of the code snippet.查看代码片段的注释部分。

The reason you can't fix it outside of draw() is because of the transform reset done on the first line.您无法在draw()之外修复它的原因是因为在第一行完成了转换重置。 Otherwise, you'd be able to adjust the transform before and after draw() to accommodate.否则,您可以在draw()之前和之后调整变换以适应。

 const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); const rect = { x: 100, y: 100, width: 50, height: 50, angle: 0 }; window.onkeydown = keyDown; draw(); function keyDown(evt) { if (evt.key == "ArrowRight") { //rect.x -= 2.5; rect.width += 5; } if (evt.key == "ArrowLeft") { rect.x -= 5; //2.5; rect.width += 5; } if (evt.key == "ArrowUp") { //rect.y -= 2.5; rect.height += 5; } if (evt.key == "ArrowDown") { rect.y -= 5; //2.5; rect.height += 5; } if (evt.key == "a") { rect.angle -= (45 * Math.PI) / 180; } if (evt.key == "s") { rect.angle += (45 * Math.PI) / 180; } draw(); } function draw() { // The next line is why you can't fix the drift outside of draw(). context.setTransform(1, 0, 0, 1, 0, 0); context.clearRect(0, 0, canvas.width, canvas.height); const cx = (rect.x * 2 + rect.width) / 2; const cy = (rect.y * 2 + rect.height) / 2; context.translate(cx, cy); context.rotate(rect.angle); context.translate(-cx, -cy); context.fillStyle = "#000"; context.fillRect(rect.x, rect.y, rect.width, rect.height); context.fillStyle = "#F00"; context.fillRect(cx, cy, 2, 2); }
 <!DOCTYPE html> <html> <body style="margin: 0"> <canvas id="canvas" width="400" height="400" style="border: 1px solid #d3d3d3" ></canvas> <script> </script> </body> </html>

Here's another snippet with a solution that requires changes inside of draw() .这是另一个需要在draw()内部进行更改的解决方案的片段。 The idea is that you define cx and cy first and keep them fixed.这个想法是你首先定义cxcy并保持它们固定。

 const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); const rect = { x: 100, y: 100, width: 50, height: 50, angle: 0 }; rect.cx = rect.x + rect.width / 2; rect.cy = rect.y + rect.height / 2; window.onkeydown = keyDown; draw(); function keyDown(evt) { if (evt.key == "ArrowRight") { rect.width += 5; } if (evt.key == "ArrowLeft") { rect.x -= 5; rect.width += 5; } if (evt.key == "ArrowUp") { rect.y -= 5; rect.height += 5; } if (evt.key == "ArrowDown") { rect.height += 5; } if (evt.key == "a") { rect.angle -= (45 * Math.PI) / 180; } if (evt.key == "s") { rect.angle += (45 * Math.PI) / 180; } draw(); } function draw() { context.setTransform(1, 0, 0, 1, 0, 0); context.clearRect(0, 0, canvas.width, canvas.height); context.translate(rect.cx, rect.cy); context.rotate(rect.angle); context.translate(-rect.cx, -rect.cy); context.fillStyle = "#000"; context.fillRect(rect.x, rect.y, rect.width, rect.height); context.fillStyle = "#F00"; context.fillRect(rect.cx, rect.cy, 2, 2); }
 <!DOCTYPE html> <html> <body style="margin: 0"> <canvas id="canvas" width="400" height="400" style="border: 1px solid #d3d3d3" ></canvas> <script> </script> </body> </html>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM