skip to Main Content

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>

2

Answers


  1. Chosen as BEST ANSWER

    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>


  2. To maintain the correct proportions of shapes when resizing the canvas in Konva.js, ensure that the scaleX and scaleY values are the same. This way, both dimensions scale uniformly, preventing distortion. Also you can move stage to make sure virtual area is always visible.

    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: sceneWidth / 2,
                y: sceneHeight / 2,
            });
            layer.add(circle);
    
            let rect = new Konva.Rect({
                fill: 'green',
                x: sceneWidth - 100,
                y: sceneHeight - 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 scale = Math.min(containerWidth / sceneWidth, containerHeight / sceneHeight);
    
                let newWidth = sceneWidth * scale;
                let newHeight = sceneHeight * scale;
    
                let x = (containerWidth - newWidth) / 2;
                let y = (containerHeight - newHeight) / 2;
    
                stage.width(containerWidth);
                stage.height(containerHeight);
                stage.scale({ x: scale, y: scale });
                stage.position({ x: x, y: y });
                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;
            }
    <script src="https://unpkg.com/[email protected]/konva.min.js"></script>
    <div id="stage-parent">
            <div id="container"></div>
        </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search