Search code examples
javascriptreactjscanvaskonvajsreact-konva

Resizing canvas to fit within container


Having some trouble trying to get my Canvas/Stage to resize and fit correctly within the parent container. I've found other similar posts and while the answers did help me with obtaining the new screen size it still doesn't want to fit within the container and instead goes right to the edges of the screen (which is expected from the examples), going over the parent container with the left/right content.

I've tried many different ways but still cannot find the correct way where it, doesn't go outside the parent container and the scale X/Y doesn't throw off the position of the shape within the canvas. The most obvious way for me was to set a constraint to the actual canvas/stage via CSS but that ends up throwing off the scaling making the shape appear outside the canvas.

In the code link, I included my hacky approach that I was trying to do and while it looks correct in some cases with smaller device screens, the canvas width will still go outside the parent container. I'm not sure if I'm overthinking this a lot or if there is a much simpler way to approach my issue, any help or tips would be great.

Live CodeSandbox: https://codesandbox.io/s/white-surf-yc2vh

Desired Result Image: https://i.sstatic.net/rRdBK.jpg


Solution

  • I think what you want / need is to resize the canvas so that it fits into the container, while keeping the aspect ratio which you have specified.

    You can use this function to resize some rectangle (rect) so that it fits into some other rectangle (container):

    // fit a rect into some container, keeping the aspect ratio of the rect
    export const fitRectIntoContainer = (rectWidth, rectHeight, containerWidth, containerHeight) => {
    
        const widthRatio = containerWidth / rectWidth;    // ratio container width to rect width
        const heightRatio = containerHeight / rectHeight; // ratio container height to rect height
    
        const ratio = Math.min( widthRatio, heightRatio ); // take the smaller ratio
    
        // new rect width and height, scaled by the same ratio
        return {
            width: rectWidth * ratio,
            height: rectHeight * ratio,
        };
    };
    

    Then you can resize the canvas so that it fits into the container:

    const canvasSize = fitRectIntoContainer( 700, 600, size.width, size.height );
    const canvasWidth = canvasSize.width;
    const canvasHeight = canvasSize.height;
    

    Then I guess you don't need any scaling anymore (so scaleX and scaleY can be both 1, or undefined)