调整HTML5画布大小以适合窗口

dev*_*vyn 383 html javascript html5-canvas

如何自动缩放HTML5 <canvas>元素以适合页面?

例如,我可以<div>通过将heightwidth属性设置为100%来进行缩放,但是<canvas>不会缩放,是吗?

dev*_*vyn 356

我相信我找到了一个优雅的解决方案:

JavaScript的

/* important! for alignment, you should make things
 * relative to the canvas' current width/height.
 */
function draw() {
  var ctx = (a canvas context);
  ctx.canvas.width  = window.innerWidth;
  ctx.canvas.height = window.innerHeight;
  //...drawing code...
}
Run Code Online (Sandbox Code Playgroud)

CSS

html, body {
  width:  100%;
  height: 100%;
  margin: 0;
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,对我没有任何大的负面影响.

  • 这是否更适合收听调整大小事件? (42认同)
  • @Elisabeth:要摆脱滚动条,请在html和body元素的样式中添加"overflow:hidden".见http://www.thefutureoftheweb.com/blog/100-percent-height-interface (22认同)
  • 我做了这个加上我还设置画布显示:块(它似乎是默认显示:内联,这是创造额外的空间!). (16认同)
  • 这可能是反模式; 请参阅[此处的第三项](http://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html)了解原因和补救措施. (11认同)
  • 您可能必须使用`body,html {margin:0px;}`禁用边距 (6认同)
  • 如果有人能解释*为什么*这有效,那肯定会很好。 (3认同)
  • @dan:一些FF附加组件可以破坏innerWidth属性. (2认同)
  • 在firefox移动设备上使用它对我的Web应用程序产生了很大的性能影响,fps降到了无法忍受的水平,并最终导致浏览器崩溃.在"onresize"事件上执行调整大小而不是这样,使应用程序再次工作,没有任何明显的区别.除此之外,在没有必要的情况下调整每个drawcall是错误的. (2认同)
  • 仅供参考:如果您已经通过使用 DOM 获得了对画布的句柄,则无需通过上下文进行引用。IE`getElementById("MyCanvas") == ctx.canvas` (2认同)
  • 但是您需要缩放画布对象以适应新大小 (2认同)

小智 61

以下解决方案最适合我.由于我对编码比较陌生,我喜欢用视觉确认某些东西按照我期望的方式工作.我在以下网站找到了它:http: //htmlcheats.com/html/resize-the-html5-canvas-dyamically/

这是代码:

<!DOCTYPE html>

<head>
    <meta charset="utf-8">
    <title>Resize HTML5 canvas dynamically | www.htmlcheats.com</title>
    <style>
    html, body {
      width: 100%;
      height: 100%;
      margin: 0px;
      border: 0;
      overflow: hidden; /*  Disable scrollbars */
      display: block;  /* No floating content on sides */
    }
    </style>
</head>

<body>
    <canvas id='c' style='position:absolute; left:0px; top:0px;'>
    </canvas>

    <script>
    (function() {
        var
        // Obtain a reference to the canvas element using its id.
        htmlCanvas = document.getElementById('c'),
        // Obtain a graphics context on the canvas element for drawing.
        context = htmlCanvas.getContext('2d');

       // Start listening to resize events and draw canvas.
       initialize();

       function initialize() {
           // Register an event listener to call the resizeCanvas() function 
           // each time the window is resized.
           window.addEventListener('resize', resizeCanvas, false);
           // Draw canvas border for the first time.
           resizeCanvas();
        }

        // Display custom canvas. In this case it's a blue, 5 pixel 
        // border that resizes along with the browser window.
        function redraw() {
           context.strokeStyle = 'blue';
           context.lineWidth = '5';
           context.strokeRect(0, 0, window.innerWidth, window.innerHeight);
        }

        // Runs each time the DOM window resize event fires.
        // Resets the canvas dimensions to match window,
        // then draws the new borders accordingly.
        function resizeCanvas() {
            htmlCanvas.width = window.innerWidth;
            htmlCanvas.height = window.innerHeight;
            redraw();
        }
    })();

    </script>
</body> 
</html>
Run Code Online (Sandbox Code Playgroud)

蓝色边框显示调整大小画布的边缘,并始终沿着窗口的边缘,在所有4个边上都可见,而上述其他一些答案则不然.希望能帮助到你.

  • 链接已损坏 (4认同)
  • @Xan-KunClark-Davis 125% 通常与设备像素分辨率调整有关。基本上,如果您使用的是高像素密度设备,字体会显得比应有的小……因此它会放大以使字体达到正常大小。据我了解。您可以使用以下命令检查显示:window.devicePixelRatio。普通设备为 1,高 DPR 通常为 1.25。 (2认同)

equ*_*man 21

基本上你要做的是将onresize事件绑定到你的身体,一旦你捕获事件你只需要使用window.innerWidth和window.innerHeight来调整画布的大小.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Canvas Resize</title>

    <script type="text/javascript">
        function resize_canvas(){
            canvas = document.getElementById("canvas");
            if (canvas.width  < window.innerWidth)
            {
                canvas.width  = window.innerWidth;
            }

            if (canvas.height < window.innerHeight)
            {
                canvas.height = window.innerHeight;
            }
        }
    </script>
</head>

<body onresize="resize_canvas()">
        <canvas id="canvas">Your browser doesn't support canvas</canvas>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)


gma*_*man 20

2022年答案

2022 年检查元素大小是否调整的推荐方法是使用ResizeObserver

const observer = new ResizeObserver(myResizeTheCanvasFn);
observer.observe(someCanvasElement);
Run Code Online (Sandbox Code Playgroud)

它比window.addEventListener('resize', myResizeTheCanvasFn)or更好onresize = myResizeTheCanvasFn,因为它可以处理画布大小调整的所有情况,即使它与窗口大小调整无关。

同样,使用window.innerWidth,也是没有意义的window.innerHeight。您需要画布本身的大小,而不是窗口的大小。这样,无论您将画布放在哪里,您都会获得适合该情况的正确尺寸,而不必重新编写尺寸调整代码。

至于让画布填满窗口

html, body {
  height: 100%;
}
canvas {
  width: 100%;
  height: 100%;
  display: block;   /* this is IMPORTANT! */
}
Run Code Online (Sandbox Code Playgroud)

您需要的原因display: block是因为默认情况下画布inline意味着它在末尾包含额外的空间。没有的话display: block你会得到一个滚动条。许多人通过添加到文档正文来解决滚动条问题overflow: hidden,但这只是隐藏了画布 CSS 设置不正确的事实。最好修复错误(将画布设置为)display: block而不是隐藏错误overflow: hidden

完整示例

const observer = new ResizeObserver(myResizeTheCanvasFn);
observer.observe(someCanvasElement);
Run Code Online (Sandbox Code Playgroud)
html, body {
  height: 100%;
}
canvas {
  width: 100%;
  height: 100%;
  display: block;   /* this is IMPORTANT! */
}
Run Code Online (Sandbox Code Playgroud)
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');

const observer = new ResizeObserver((entries) => {
  canvas.width = canvas.clientWidth;
  canvas.height = canvas.clientHeight;
});
observer.observe(canvas)

// not import but draw something just to showcase

const hsla = (h, s, l, a) => `hsla(${h * 360}, ${s * 100}%, ${l * 100}%, ${a})`;

function render(time) {
  const {width, height} = canvas;

  ctx.clearRect(0, 0, width, height);
  ctx.save();
  ctx.translate(width / 2, height / 2);
  ctx.rotate(time * 0.0001);
  
  const range = Math.max(width, height) * 0.8;
  const size = 64 + Math.sin(time * 0.001) * 50;
  for (let i = 0; i < range; i += size) {
    ctx.fillStyle = hsla(i / range * 0.3 + time * 0.0001, 1, 0.5, 1);
    ctx.fillRect( i, -range, size, range * 2);
    ctx.fillRect(-i, -range, size, range * 2);
  }
  
  ctx.restore();

  requestAnimationFrame(render)
}
requestAnimationFrame(render)
Run Code Online (Sandbox Code Playgroud)

注意:还有与调整画布大小相关的其他问题。特别是如果您想处理不同的 devicePixelRatio 设置。请参阅这篇文章了解更多信息。


jer*_*boy 19

根据浏览器客户端的尺寸设置画布坐标空间的宽度和高度,需要在调整浏览器大小时调整大小和重绘.

一个不太复杂的解决方案是在Javascript变量中维护可绘制的维度,但是根据screen.width,screen.height维度设置画布尺寸.使用CSS来适应:

#containingDiv { 
  overflow: hidden;
}
#myCanvas {
  position: absolute; 
  top: 0px;
  left: 0px;
} 
Run Code Online (Sandbox Code Playgroud)

浏览器窗口通常不会大于屏幕本身(除非屏幕分辨率被误报,因为它可能与不匹配的双显示器一起),因此背景将不会显示,像素比例也不会变化.除非使用CSS缩放画布,否则画布像素将与屏幕分辨率成正比.

  • 使用CSS重新调整画布很麻烦.至少在Chrome和Safari上,鼠标/触摸事件位置不会与画布像素位置1:1对应,您必须转换坐标系. (7认同)

Vol*_* E. 13

一个纯CSS方法添加到@jerseyboy的解决方案上面.
适用于Firefox(在v29中测试),Chrome(在v34中测试)和Internet Explorer(在v11中测试).

<!DOCTYPE html>
<html>
    <head>
    <style>
        html,
        body {
            width: 100%;
            height: 100%;
            margin: 0;
        }
        canvas {
            background-color: #ccc;
            display: block;
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="500" height="500"></canvas>
    <script>
        var canvas = document.getElementById('canvas');
        if (canvas.getContext) {
            var ctx = canvas.getContext('2d');
            ctx.fillRect(25,25,100,100);
            ctx.clearRect(45,45,60,60);
            ctx.strokeRect(50,50,50,50);
        }
    </script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

链接到示例:http://temporaer.net/open/so/140502_canvas-fit-to-window.html

但请小心,正如@jerseyboy在评论中所述:

使用CSS重新调整画布很麻烦.至少在Chrome和Safari上,鼠标/触摸事件位置不会与画布像素位置1:1对应,您必须转换坐标系.

  • CSS方式拉伸画布,从而渲染图像得到拉伸。与调整画布大小相比,这是不好的。只要稍加调整,克雷格的答案就可以发挥最佳效果。 (4认同)

Nic*_*lay 8

除非您希望画布自动升级您的图像数据(这就是James Black的回答,但它看起来不太漂亮),您必须自己调整大小并重新绘制图像.居中画布


Pet*_*etr 8

function resize() {

    var canvas = document.getElementById('game');
    var canvasRatio = canvas.height / canvas.width;
    var windowRatio = window.innerHeight / window.innerWidth;
    var width;
    var height;

    if (windowRatio < canvasRatio) {
        height = window.innerHeight;
        width = height / canvasRatio;
    } else {
        width = window.innerWidth;
        height = width * canvasRatio;
    }

    canvas.style.width = width + 'px';
    canvas.style.height = height + 'px';
};

window.addEventListener('resize', resize, false);
Run Code Online (Sandbox Code Playgroud)


Ale*_*x V 6

设置初始大小。

const canvas = document.getElementById('canvas');

canvas.width  = window.innerWidth;
canvas.height = window.innerHeight;
Run Code Online (Sandbox Code Playgroud)

调整窗口大小时更新大小。

function windowResize() {
  canvas.width  = window.innerWidth;
  canvas.height = window.innerHeight;
};

window.addEventListener('resize', windowResize);
Run Code Online (Sandbox Code Playgroud)

  • 很好,这值得更多的爱。还有调整大小功能的道具。 (3认同)