【问题标题】:Canvas grows in size when fitting to flex container size当适合 flex 容器大小时,画布的大小会增加
【发布时间】:2020-08-29 04:54:00
【问题描述】:

我想要实现的布局是(无需阅读,JSFiddle 不言自明。尝试调整大小):

  • #content 应该是屏幕/视口的 100% 高度,既不高也不低
  • 两行,#content-header 和#panels。 #panels 行应填满垂直空间
  • #panels 应该包含 div,其中一些是包裹的画布。画布应该是一个正方形,大小等于包装器的宽度和高度的最小值。

我有两个问题:

  1. 调整窗口大小会使画布的大小无限增长。 (尝试调整 JSFiddle 框架的大小)
  2. 内容已垂直溢出,我是从原始的 resize 调用中猜测的。

我尽量让例子简单,并注释了大部分代码,希望够用了。

test.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <title>Test</title>
        <link rel="stylesheet" href="normalize.css">
        <link rel="stylesheet" href="test.css">
        <script src="test.js"></script>
    </head>
    <body>
        <div id="content">
            <div id="content-header">HEADER</div>
            <div id="panels">
                <div class="canvas-wrapper">
                    <canvas id="test-canvas"></canvas>
                </div>
            </div>
        </div>
    </body>
</html>

test.css

/* Border box */

html {
    -webkit-box-sizing: border-box;
       -moz-box-sizing: border-box;
            box-sizing: border-box;
}

*,
*::before,
*::after {
    -webkit-box-sizing: inherit;
        -moz-box-sizing: inherit;
            box-sizing: inherit;
}

/* Full height #content */

html, body, #content {
    height: 100%;
}

/* #panels fills verical space */

#content {
    display: flex;
    flex-direction: column;
}

#content-header {
    flex: 0 1 0;
}

#panels {
    flex: 1 0 0;
}

/* #panels is flex row container */

#panels {
    display: flex;
    flex-direction: row;
}

/* Wrapping canvas to calculate size from flex container */

.canvas-wrapper {
    display: block;

    /* Can grow and can shrink */
    flex: 1 1 auto;

    background-color: rgba(0, 0, 255, 0.2);
}

canvas {
    display: block;
    
    /* Center horizontally */
    margin: 0 auto;

    border: 1px solid red;
}

test.js

// width X height -> size X size, size is min(parentWidth, parentHeight)
function fitToParent(element) {
    // parent element is the .canvas-wrapper
    const parentWidth = element.parentElement.clientWidth;
    const parentHeight = element.parentElement.clientHeight;

    const size = Math.min(parentWidth, parentHeight);

    // for debug
    console.log('Wrapper size = ' + parentWidth + 'x' + parentHeight + ' Canvas size = ' + size + 'x' + size);

    element.width = size;
    element.height = size;
}

window.addEventListener('load', function() {
    const canvas = document.getElementById('test-canvas');
    const ctx = canvas.getContext('2d');

    function resize() {
        fitToParent(canvas);

        // random draw operation, doesn't matter
        ctx.fillStyle = 'green';
        ctx.fillRect(10, 10, 150, 100);
    }

    window.addEventListener('resize', resize);

    resize();
});

JSFiddle here

【问题讨论】:

  • 这能回答你的问题吗? JavaScript event for canvas resize
  • 我特别用this answer
  • @MattEllen 不幸的是,没有。我实际上从我的实际代码中删除了去抖动功能,以使问题更加明显。使用去抖动,结果是相同的,但速度较慢,因为调用 resize 函数的次数要少得多。

标签: javascript html css canvas


【解决方案1】:

从更多测试来看,似乎是由于#panels flex 容器(或任何其他显示样式)将画布的大小视为最小值。

我发现的一种解决方法是在调整大小之前先将画布的宽度和高度设置为 0。 但我不确定这是否可以,它会导致一些我想避免的生涩动画。我会在接受这个答案之前等待,以防任何人想到其他事情。

另外,第二个问题(垂直溢出)依然存在。

// width X height -> size X size, size is min(parentWidth, parentHeight)
function fitToParent(element) {
    // WORKAROUND
    element.width = 0;
    element.height = 0;
    
    // parent element is the .canvas-wrapper
    const parentWidth = element.parentElement.clientWidth;
    const parentHeight = element.parentElement.clientHeight;

    const size = Math.min(parentWidth, parentHeight);

    // for debug
    console.log('Wrapper size = ' + parentWidth + 'x' + parentHeight + ' Canvas size = ' + size + 'x' + size);

    element.width = size;
    element.height = size;
}

JSFiddle 有解决方法

编辑

显然,画布宽度和高度属性不考虑框大小,因此从边框溢出。通过将 css 属性设置为与元素属性(宽度、高度 -> style.width、style.height)相同的值来修复。

所以,我认为第二个问题已经解决了。

// width X height -> size X size, size is min(parentWidth, parentHeight)
function fitToParent(element) {
    // WORKAROUND
    element.width = 0;
    element.height = 0;
    element.style.width = 0;
    element.style.height = 0;
    
    // parent element is the .canvas-wrapper
    const parentWidth = element.parentElement.clientWidth;
    const parentHeight = element.parentElement.clientHeight;

    const size = Math.min(parentWidth, parentHeight);

    // for debug
    console.log('Wrapper size = ' + parentWidth + 'x' + parentHeight + ' Canvas size = ' + size + 'x' + size);

    element.width = size;
    element.height = size;
    element.style.width = size + 'px';
    element.style.height = size + 'px';
}

Final JSFiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 2016-06-11
    • 2014-05-07
    • 2011-01-20
    • 2020-09-02
    • 2013-12-31
    • 2021-09-28
    相关资源
    最近更新 更多