How to scale a rotated rectangle in canvas
<p>What is the correct math formula to use to scale a rectangle by corner handles when the shape is rotated? </p>

<p>UPDATED: </p>

<p>The question is more about the math behind the mouse down event on the handles and the actual sizing of the shape. What is to proper math used to calculate the shape position and scaled size when the handle is being moved on a rotated shape?  </p>

<p>I have created a fiddle with the project to show an example: 
<a href="https://jsfiddle.net/8b5zLupf/38/" rel="nofollow noreferrer">https://jsfiddle.net/8b5zLupf/38/</a> </p>

<p>The gray shape on the canvas in the fiddle can be moved and scaled but because the shape is rotated, the math to scale the shape and keep the shape position when scaling is being calculated incorrectly. </p>

<p>The project will scale but it does not lock the shape by the opposite point and scale uniformly. </p>

<p>The area of code I use to scale a shape with aspect is below:  </p>

<pre><code>resizeShapeWithAspect: function(currentHandle, shape, mouse)
{
    var self = this;
    var getModifyAspect = function(max, min, value)
    {
        var ratio = max / min;
        return value * ratio;
    };

    var modify = {
        width: 0,
        height: 10
    };
    var direction = null,
        objPos = shape.position,
        ratio = this.getAspect(shape.width, shape.height);
    switch (currentHandle)
    {
        case 'topleft':
            modify.width = shape.width + (objPos.x - mouse.x);
            modify.height = shape.height + (objPos.y - mouse.y);

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeX = (modify.width - shape.width);
            var changeY = (modify.height - shape.height);
            objPos.x = mouse.x + changeX;
            objPos.y = mouse.y + changeY;
            break;
        case 'topright':
            modify.width = mouse.x - objPos.x;
            modify.height = shape.height + (objPos.y - mouse.y);

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeY = (modify.height - shape.height);
            objPos.y = mouse.y + changeY;
            break;
        case 'bottomleft':
            modify.width = shape.width + (objPos.x - mouse.x);
            modify.height = mouse.y - objPos.y;

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeX = (modify.width - shape.width);
            objPos.x = mouse.x + changeX;
            break;
        case 'bottomright':
            modify.width = mouse.x - objPos.x;
            modify.height = mouse.y - objPos.y;

            this.scale(shape, modify);
            break;

        case 'top':
            var oldWidth = shape.width;
            modify.width = shape.width + (objPos.x + mouse.x);
            modify.height = shape.height + (objPos.y - mouse.y);

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeX = ((shape.width - oldWidth) / 2);
            var changeY = (modify.height - shape.height);
            objPos.x -= changeX;
            objPos.y = mouse.y + changeY;
            break;

        case 'left':
            var oldHeight = shape.height;
            modify.width = shape.width + (objPos.x - mouse.x);
            modify.height = getModifyAspect(modify.width, shape.width, shape.height);

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeX = (modify.width - shape.width);
            var changeY = ((shape.height - oldHeight) / 2);
            objPos.x = mouse.x + changeX;
            objPos.y -= changeY;
            break;

        case 'bottom':
            var oldWidth = shape.width;
            modify.height = mouse.y - objPos.y;
            modify.width = getModifyAspect(modify.height, shape.height, shape.width);

            this.scale(shape, modify);

            var changeX = ((shape.width - oldWidth) / 2);
            objPos.x -= changeX;
            break;

        case 'right':
            var oldHeight = shape.height;
            modify.width = mouse.x - objPos.x;
            modify.height = getModifyAspect(modify.width, shape.width, shape.height);

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeY = ((shape.height - oldHeight) / 2);
            objPos.y -= changeY;
            break;
    }
}
</code></pre>

<p>I have modified the code above to work with angles but it does not work correctly. </p>

<pre><code>resizeShapeWithAspectAndRotate: function(currentHandle, shape, mouse)
{
    var self = this;
    var getModifyAspect = function(max, min, value)
    {
        var ratio = max / min;
        return value * ratio;
    };

    var modify = {
        width: 0,
        height: 10
    };
    var direction = null,
        objPos = shape.position,
        ratio = this.getAspect(shape.width, shape.height),
        handles = shape.getHandlePositions();
    switch (currentHandle)
    {
        case 'topleft':
            var handle = this.getHandleByLabel(handles, 'topleft');
            var opositeHandle = this.getOpositeHandle(handles, 'topleft');
            var distance = canvasMath.distance(handle, mouse);

            modify.width = shape.width + (distance);
            modify.height = shape.height + (distance);

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeX = (modify.width - shape.width);
            var changeY = (modify.height - shape.height);
            //shape.position.x = mouse.x + changeX;
            //shape.position.y = mouse.y + changeY;
            break;
        case 'topright':
            modify.width = mouse.x - objPos.x;
            modify.height = shape.height + (objPos.y - mouse.y);

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeY = (modify.height - shape.height);
            objPos.y = mouse.y + changeY;
            break;
        case 'bottomleft':
            modify.width = shape.width + (objPos.x - mouse.x);
            modify.height = mouse.y - objPos.y;

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeX = (modify.width - shape.width);
            objPos.x = mouse.x + changeX;
            break;
        case 'bottomright':
            modify.width = mouse.x - objPos.x;
            modify.height = mouse.y - objPos.y;

            this.scale(shape, modify);
            break;

        case 'top':
            var oldWidth = shape.width;
            modify.width = shape.width + (objPos.x + mouse.x);
            modify.height = shape.height + (objPos.y - mouse.y);

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeX = ((shape.width - oldWidth) / 2);
            var changeY = (modify.height - shape.height);
            objPos.x -= changeX;
            objPos.y = mouse.y + changeY;
            break;

        case 'left':
            var oldHeight = shape.height;
            modify.width = shape.width + (objPos.x - mouse.x);
            modify.height = getModifyAspect(modify.width, shape.width, shape.height);

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeX = (modify.width - shape.width);
            var changeY = ((shape.height - oldHeight) / 2);
            objPos.x = mouse.x + changeX;
            objPos.y -= changeY;
            break;

        case 'bottom':
            var oldWidth = shape.width;
            modify.height = mouse.y - objPos.y;
            modify.width = getModifyAspect(modify.height, shape.height, shape.width);

            this.scale(shape, modify);

            var changeX = ((shape.width - oldWidth) / 2);
            objPos.x -= changeX;
            break;

        case 'right':
            var oldHeight = shape.height;
            modify.width = mouse.x - objPos.x;
            modify.height = getModifyAspect(modify.width, shape.width, shape.height);

            this.scale(shape, modify);

            /* we need to setup the shape position by getting the
            offset from where the object would have been without the
            scale and add that to the position */
            var changeY = ((shape.height - oldHeight) / 2);
            objPos.y -= changeY;
            break;
    }
},

getHandleByLabel: function(handles, label)
{
    if (handles)
    {
        for (var i = 0, maxLength = handles.length; i &lt; maxLength; i++)
        {
            var handle = handles[i];
            if (label === handle.label)
            {
                return handle;
            }
        }
    }
    return false;
},

getOpositeHandle: function(handles)
{
    var handleLabel = this.currentHandle;
    if (handleLabel &amp;&amp; handles)
    {
        switch (handleLabel)
        {
            case 'topleft':
                return this.getHandleByLabel(handles, 'bottomright');
            case 'top':
                return this.getHandleByLabel(handles, 'bottom');
            case 'topright':
                return this.getHandleByLabel(handles, 'bottomleft');
            case 'right':
                return this.getHandleByLabel(handles, 'left');
            case 'bottomright':
                return this.getHandleByLabel(handles, 'topleft');
            case 'bottom':
                return this.getHandleByLabel(handles, 'top');
            case 'bottomleft':
                return this.getHandleByLabel(handles, 'topright');
            case 'left':
                return this.getHandleByLabel(handles, 'right');
        }
    }
    return false;
}
</code></pre>