【问题标题】:canvas set to "clientWidth," does not shrink when nearby element resizes设置为“clientWidth”的画布在附近元素调整大小时不会缩小
【发布时间】:2020-10-07 16:07:10
【问题描述】:

我有一个基于 CSS 网格的 UI 的 Web 应用程序。在其中一个网格部分中,有一个可折叠的侧面板和一个我想始终调整大小以填充剩余空间的画布元素。画布每帧都会更新,所以我将canvas.width 设置为每帧上包装器 div 的clientWidth

面板折叠时画布会适当地展开以填充空间,但当面板再次打开时,画布不会缩小,而是溢出页面。我有一些关于为什么会发生这种情况的理论,例如一旦画布展开,包装器 div 拒绝收缩,但我不知道如何解决这个问题。

这是一个简单的问题模型:

<meta charset="utf-8" />

<script>
    let open = true;

    window.onload = () => {
        let canvas = document.getElementById("canvas");

        canvasUpdate(canvas);
    }

    function canvasUpdate(canvas){
        let ctx = canvas.getContext("2d");

        canvas.width = document.getElementById("canvasWrapper").clientWidth;
        canvas.height = document.getElementById("canvasWrapper").clientHeight;

        ctx.fillStyle = "gray";
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, 50, 50);

        ctx.fillStyle = "black";
        ctx.fillRect(canvas.width - 50, canvas.height - 50, 50, 50);

        window.requestAnimationFrame(()=>{canvasUpdate(canvas)});
    }

    function togglePanel(){
        if (open){
            document.getElementById("sidePanel").style.display = "none";
            document.getElementById("expandBtn").style.display = "block";
            open = false;
        }
        else{
            document.getElementById("sidePanel").style.display = "flex";
            document.getElementById("expandBtn").style.display = "none";
            open = true;
        }
    }
</script>

<style>
    html, body{
        margin: 0;
        padding: 0;
    }

    #gridWrapper{
        display: grid;
        grid-template-areas: 
            "header header"
            "col1 col2";
        grid-template-columns: 100pt 1fr;
        grid-template-rows: 50pt minmax(0, 1fr);
        width: 100%;
        height: 100%;
    }

    #header{
        grid-area: header;
        background: #AAFFAA;
    }

    #col1{
        grid-area: col1;
        background: #FFAAAA;
    }

    #col2{
        grid-area: col2;
        display: flex;
        flex-direction: row;
    }

    #sidePanel{
        display: flex;
        flex-direction: row;
        height: 100%;
    }

    #expandBtn{
        display: none;
        height: 100%;
    }

    #canvasWrapper{
        width: 100%;
        height: 100%;
    }
</style>

<body>
    <div id="gridWrapper">
        <div id="header">
            Header contents
        </div>
        <div id="col1">
            Col1 contents
        </div>
        <div id="col2">
            <div id="sidePanel">
                <div id="panelContents">
                    <div class="contents">Contents</div>
                    <div class="contents">Contents</div>
                    <div class="contents">Contents</div>
                    <div class="contents">Contents</div>
                    <div class="contents">Contents</div>
                </div>
                <button id="collapseBtn" onclick="togglePanel()">
                    &lt;
                </button>
            </div>
            <button id="expandBtn" onclick="togglePanel()">
                &gt;
            </button>
            <div id="canvasWrapper">
                <canvas id="canvas">
                    //Error loading canvas
                </canvas>
            </div>
        </div>
    </div>
</body>

如果我设置网格的overflow = hidden 它解决了它运行页面的问题,但画布仍然保持扩展宽度。

【问题讨论】:

    标签: javascript html css html5-canvas


    【解决方案1】:

    我想通了。无论您设置什么 CSS 设置,似乎块级元素都不会缩小到比画布元素小,但幸运的是我找到了一种解决方法,将画布 w/h 临时设置为 1,然后得到和存储包装器的尺寸,然后最终将画布设置为存储的尺寸。

        let wrapperBounds = {width:0,height:0};
    
        canvas.width = 1;
        canvas.height = 1;
    
        wrapperBounds.width = document.getElementById("canvasWrapper").clientWidth;
        wrapperBounds.height = document.getElementById("canvasWrapper").clientHeight;
    
        canvas.width = wrapperBounds.width;
        canvas.height = wrapperBounds.height;
    

    我最初认为这不会起作用,因为我认为自动宽度是在生命周期中与requestAnimationFrame() 不同的点计算的,但显然 CSS 是在更改后立即计算的。

    完整代码实现:

    <meta charset="utf-8" />
    
    <script>
        let open = true;
    
        window.onload = () => {
            let canvas = document.getElementById("canvas");
    
            canvasUpdate(canvas);
        }
    
        function canvasUpdate(canvas){
            let ctx = canvas.getContext("2d");
            let wrapperBounds = {width:0,height:0};
    
            canvas.width = 1;
            canvas.height = 1;
    
            wrapperBounds.width = document.getElementById("canvasWrapper").clientWidth;
            wrapperBounds.height = document.getElementById("canvasWrapper").clientHeight;
    
            canvas.width = wrapperBounds.width;
            canvas.height = wrapperBounds.height;
    
            ctx.fillStyle = "gray";
            ctx.fillRect(0, 0, canvas.width, canvas.height);
    
            ctx.fillStyle = "black";
            ctx.fillRect(0, 0, 50, 50);
    
            ctx.fillStyle = "black";
            ctx.fillRect(canvas.width - 50, canvas.height - 50, 50, 50);
    
            window.requestAnimationFrame(()=>{canvasUpdate(canvas)});
        }
    
        function togglePanel(){
            if (open){
                document.getElementById("sidePanel").style.display = "none";
                document.getElementById("expandBtn").style.display = "block";
                open = false;
            }
            else{
                document.getElementById("sidePanel").style.display = "flex";
                document.getElementById("expandBtn").style.display = "none";
                open = true;
            }
        }
    </script>
    
    <style>
        html, body{
            margin: 0;
            padding: 0;
        }
    
        #gridWrapper{
            display: grid;
            grid-template-areas: 
                "header header"
                "col1 col2";
            grid-template-columns: 100pt 1fr;
            grid-template-rows: 50pt minmax(0, 1fr);
            width: 100%;
            height: 100%;
        }
    
        #header{
            grid-area: header;
            background: #AAFFAA;
        }
    
        #col1{
            grid-area: col1;
            background: #FFAAAA;
        }
    
        #col2{
            grid-area: col2;
            display: flex;
            flex-direction: row;
        }
    
        #sidePanel{
            display: flex;
            flex-direction: row;
            height: 100%;
        }
    
        #expandBtn{
            display: none;
            height: 100%;
        }
    
        #canvasWrapper{
            width: 100%;
            height: 100%;
        }
    </style>
    
    <body>
        <div id="gridWrapper">
            <div id="header">
                Header contents
            </div>
            <div id="col1">
                Col1 contents
            </div>
            <div id="col2">
                <div id="sidePanel">
                    <div id="panelContents">
                        <div class="contents">Contents</div>
                        <div class="contents">Contents</div>
                        <div class="contents">Contents</div>
                        <div class="contents">Contents</div>
                        <div class="contents">Contents</div>
                    </div>
                    <button id="collapseBtn" onclick="togglePanel()">
                        &lt;
                    </button>
                </div>
                <button id="expandBtn" onclick="togglePanel()">
                    &gt;
                </button>
                <div id="canvasWrapper">
                    <canvas id="canvas">
                        //Error loading canvas
                    </canvas>
                </div>
            </div>
        </div>
    </body>
    

    【讨论】:

      猜你喜欢
      • 2012-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多