简体   繁体   中英

Resizing rotated rectangle on HTML canvas

I have an instance of HTML 5 canvas and a rectangle drawn on it.

My drawing function takes a resizing angle into account and uses relative coordinates.

Relative coordinates're based upon three variables: top left rectangle point, rectangle width and rectangle height.

Rectangle width and rectangle height're calculated using two points: top left rectangle point and bottom right rectangle point.

To sum up, drawing function depends on top left rectangle point, bottom right rectangle point and rotation. It's an important point for the following text!

Here's a code snippet:

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()
    }

Here's my rectangle with a bunch of controls: eight resizing handles (white) and one rotation handle (green):

在此处输入图像描述

Rotating works fine.

Resizing works fine.

And I also try to implement resizing after rotation. Here's my approach with a humble illustration:

在此处输入图像描述

  1. Grab the coordinates of the red point (it's mouse cursor coordiantes)
  2. Derotate the point using negative angle to get derotated coordinates
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. Update xTopLeft , yTopLeft and redraw
  2. Done

The idea behind this approach is simple. Since my drawing function depeneds on top left rectangle point and bottom right rectangle point I just need to get their new coordinates.

For instance, here's a simplified code for B point:

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

But it doesn't work as expected: while resizing my rotated rectangle shifts, jumps and totally misbehaves.

In search of insights I've stumbled upon this article . The article covers my problem, but I don't get author's approach and can't implement it.

Why should I always lock the coordinates of the A point? My top left handle is intended to resize the rectangle in a north-west direction, so it would be necessary to change the coordinates of the A point...

Why should we recalculate the center point before derotation? It breaks the idea of uniform matrix transformations...

What's the correct algorithm in my case?

I was also facing same problem. It turned out that the angle I was using was in degree. Try multiplying angle in rotatePoint function with (Math.PI / 180).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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