Search code examples
javascripthtmlcanvaskonvajskonva

Shapes going out of proportion in responsive canvas


I am trying to learn Konva.js to build a game and one of my biggest priorities is that the canvas should be responsive in width and height. I have managed to achieve that but when I resize my browser, the shapes strech out of proportion. I have a few guesses that I have to update the X and Y of the shape when the window resizes, but being new to this framework, I don't have a idea how to implement that. This is my code-

<!DOCTYPE html>
<html>

<head>
    <script src="https://unpkg.com/[email protected]/konva.min.js"></script>
    <meta charset="utf-8" />
    <title>Konva Responsive Canvas Demo</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            overflow: hidden;
            background-color: #f0f0f0;
            height: 100vh;
        }

        #stage-parent {
            width: 100%;
            height: 100vh;
        }
    </style>
</head>

<body>
    <div id="stage-parent">
        <div id="container"></div>
    </div>
    <script>
        let sceneWidth = 1000;
        let sceneHeight = 1000;

        let stage = new Konva.Stage({
            container: 'container',
            width: sceneWidth,
            height: sceneHeight,
        });

        let layer = new Konva.Layer();
        stage.add(layer);

        let circle = new Konva.Circle({
            radius: 50,
            fill: 'red',
            x: stage.width() / 2,
            y: stage.height() / 2,
        });
        layer.add(circle);

        let rect = new Konva.Rect({
            fill: 'green',
            x: stage.width() - 100,
            y: stage.height() - 100,
            width: 100,
            height: 100,
        });
        layer.add(rect);

        function fitStageIntoParentContainer() {
            const container = document.querySelector('#stage-parent');

            let containerWidth = container.offsetWidth;
            let containerHeight = container.offsetHeight

            let scaleX = containerWidth / sceneWidth;
            let scaleY = containerHeight / sceneHeight;

            stage.width(sceneWidth * scaleX);
            stage.height(sceneHeight * scaleY);
            stage.scale({ x: scaleX, y: scaleY });
        }

        fitStageIntoParentContainer();
        window.addEventListener('resize', fitStageIntoParentContainer);
    </script>
</body>

</html>

Solution

  • I must thank lavtron as it was his code that pushed me into the right direction. I hope this gets included in the docs!

            let container = document.querySelector('#stage-parent');
            let containerWidth = container.offsetWidth;
            let containerHeight = container.offsetHeight;
            let stage = new Konva.Stage({
                container: 'container',
                width: containerWidth,
                height: containerHeight,
            });
    
            let layer = new Konva.Layer();
            stage.add(layer);
    
            let circle = new Konva.Circle({
                radius: 50,
                fill: 'red',
            });
            layer.add(circle);
    
            let rect = new Konva.Rect({
                fill: 'green',
                width: 100,
                height: 100,
            });
            layer.add(rect);
    
            function fitStageIntoParentContainer() {
                container = document.querySelector('#stage-parent');
                containerWidth = container.offsetWidth;
                containerHeight = container.offsetHeight;
                rect.x(containerWidth - 100);
                rect.y(containerHeight - 100);
                circle.x(containerWidth / 2);
                circle.y(containerHeight / 2);
                stage.width(containerWidth);
                stage.height(containerHeight);
                stage.batchDraw();
            }
    
            fitStageIntoParentContainer();
            window.addEventListener('resize', fitStageIntoParentContainer);
            body {
                margin: 0;
                padding: 0;
                overflow: hidden;
                background-color: #f0f0f0;
                height: 100vh;
            }
    
            #stage-parent {
                width: 100%;
                height: 100vh;
            }
    <!DOCTYPE html>
    <html>
    
    <head>
        <script src="https://unpkg.com/[email protected]/konva.min.js"></script>
        <meta charset="utf-8" />
        <title>Konva Responsive Canvas Demo</title>
        </head>
    
    <body>
        <div id="stage-parent">
            <div id="container"></div>
        </div>
        </body>
    
    </html>