ChatGPT解决这个技术问题 Extra ChatGPT

HTML5 Canvas 100% 宽度视口高度?

我正在尝试创建一个占视口宽度和高度 100% 的画布元素。

您可以在我的示例 here 中看到正在发生的情况,但是它在 Chrome 和 FireFox 中都添加了滚动条。如何防止额外的滚动条,只提供窗口的宽度和高度作为画布的大小?


Y
Yoav Kadosh

为了使画布始终全屏宽度和高度,这意味着即使调整了浏览器的大小,您也需要在将画布大小调整为 window.innerHeightwindow.innerWidth 的函数中运行绘制循环。

示例:http://jsfiddle.net/jaredwilli/qFuDr/

HTML

<canvas id="canvas"></canvas>

JavaScript

(function() {
  const canvas = document.getElementById('canvas');
  const context = canvas.getContext('2d');

  // resize the canvas to fill browser window dynamically
  window.addEventListener('resize', resizeCanvas, false);
        
  function resizeCanvas() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
                
    /**
     * Your drawings need to be inside this function otherwise they will be reset when 
     * you resize the browser window and the canvas goes will be cleared.
     */
    drawStuff(); 
  }
  
  resizeCanvas();
        
  function drawStuff() {
    // do your drawing stuff here
  }
})();

CSS

* { margin:0; padding:0; } /* to remove the top and left whitespace */

html, body { width:100%; height:100%; } /* just to be sure these are full screen*/

canvas { display:block; } /* To remove the scrollbars */

这就是你如何正确地使画布的宽度和浏览器的高度。您只需将所有用于绘图的代码放在 drawStuff() 函数中即可。


为什么需要删除填充并将宽度、高度设置为 100%?
我相信这主要是为了覆盖浏览器默认的用户样式表。如果您正在使用某种规范化或重置 css 文件,则没有必要这样做,因为这已经被处理了。
如果您期望大量调整大小;例如,在纵向/横向设备上,您需要debounce调整大小,否则会淹没浏览器。
display: block:这不仅会删除滚动条,还会从文档正文的高度中删除 2px,通常添加在块内的文本行下方。所以+1
加一个没有 jQuery
V
Vitalii Fedorenko

您可以尝试 viewport units (CSS3):

canvas { 
  height: 100vh; 
  width: 100vw; 
  display: block;
}

添加 display: block; 即可完成工作。
我试过了,发现在 Chrome 和 Firefox 中,画布只是显示拉伸到完整视口的图像。即使是新绘制的元素也会被拉伸。
@Daniel 是对的 - 这个答案是错误的。它不会设置画布上下文的内部尺寸,而是设置 DOM 元素的尺寸。有关差异,请参见my answer to a related question
此方法不起作用,它会拉伸文本。不幸的是,您必须使用 JS。
在某些情况下您想要拉伸(即进度条)。谢谢,非常适合我的情况!
m
mathheadinclouds

我将回答更一般的问题,即如何让画布在调整窗口大小时动态调整大小。接受的答案适当地处理了宽度和高度都应该为 100% 的情况,这是所要求的,但也会改变画布的纵横比。许多用户希望画布在窗口调整大小时调整大小,但同时保持纵横比不变。这不是确切的问题,但它“适合”,只是将问题置于更一般的背景下。

窗口将具有一定的纵横比(宽度/高度),画布对象也是如此。你希望这两个纵横比如何相互关联是你必须清楚的一件事,这个问题没有“一刀切”的答案——我将通过一些常见的案例来说明你可能会遇到的情况想。

最重要的事情你要清楚:html canvas 对象有一个 width 属性和一个 height 属性;然后,同一个对象的 css 也有一个 width 和一个 height 属性。这两个宽度和高度是不同的,它们都对不同的东西有用。

更改宽度和高度属性是您始终可以更改画布大小的一种方法,但是您必须重新绘制所有内容,这需要时间并且并非总是必要的,因为您可以完成一些大小更改通过 css 属性,在这种情况下,您不会重绘画布。

我看到了 4 种您可能希望在调整窗口大小时发生的情况(全部从全屏画布开始)

1:您希望宽度保持 100%,并且希望纵横比保持原样。在这种情况下,您不需要重新绘制画布;您甚至不需要窗口调整大小处理程序。所有你需要的是

$(ctx.canvas).css("width", "100%");

其中 ctx 是您的画布上下文。小提琴:resizeByWidth

2:您希望宽度和高度都保持 100%,并且希望由此产生的纵横比变化具有拉伸图像的效果。现在,您仍然不需要重绘画布,但您需要一个窗口调整大小处理程序。在处理程序中,你做

$(ctx.canvas).css("height", window.innerHeight);

小提琴:messWithAspectratio

3:您希望宽度和高度都保持 100%,但纵横比变化的答案与拉伸图像不同。然后您需要重新绘制,并按照接受的答案中概述的方式进行。

小提琴:redraw

4:您希望页面加载时的宽度和高度为 100%,但此后保持不变(对窗口调整大小没有反应。

小提琴:fixed

所有小提琴都有相同的代码,除了第 63 行设置了模式。您还可以复制小提琴代码以在本地计算机上运行,在这种情况下,您可以通过查询字符串参数选择模式,如 ?mode=redraw


仅供参考:$(ctx.canvas).css("width", "100%"); 相当于 $(canvas).css("width", "100%");(上下文的画布只是画布)
@BradKent 当您调用一个辅助函数来执行您想要完成的“画布事物”时,您可以作为参数 1)传递画布对象,2)传递画布上下文,3)两者。我不喜欢 3),而且 ctx.canvascanvas.getContext('2d') 短很多——这就是我做 2) 的原因。因此,没有名为 canvas 的变量,但有 ctx.canvas。这就是 ctx.canvas 的来源。
M
Marc Audet

http://jsfiddle.net/mqFdk/10/

<!DOCTYPE html>
<html>
<head>
    <title>aj</title>
</head>
<body>

    <canvas id="c"></canvas>

</body>
</html>

与 CSS

body { 
       margin: 0; 
       padding: 0
     }
#c { 
     position: absolute; 
     width: 100%; 
     height: 100%; 
     overflow: hidden
   }

这可行,但它使我的画布没有定义的宽度和高度。画布宽度和高度必须在我相信的元素上定义。
@aherrick:不,您不必在画布元素上明确设置宽度/高度即可使其工作。这段代码应该可以正常工作。
实际上是的,画布元素确实需要明确的宽度/高度设置。没有它,它们默认为某些浏览器预设(在 chrome 中,我认为它是 300x150px)大小。画布上的所有绘图都以这个大小进行解释,然后缩放到视口大小的 100%。试着在你的画布上画任何东西,看看我的意思——它会被扭曲。
如果您试图使画布的宽度和高度为 100%,那么这根本不重要。无论如何你只要调整它的大小
画布元素的内在尺寸等于坐标空间的大小,数字以 CSS 像素解释。但是,可以通过样式表任意调整元素的大小。在渲染过程中,图像被缩放以适应此布局大小。
D
David

我也在寻找这个问题的答案,但接受的答案对我来说是个问题。显然使用 window.innerWidth 是不可移植的。它在某些浏览器中确实有效,但我注意到 Firefox 不喜欢它。

Gregg Tavares 在这里发布了一个很好的资源来直接解决这个问题:http://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html(参见反模式 # 的 3 和 4)。

使用 canvas.clientWidth 而不是 window.innerWidth 似乎效果很好。

这是 Gregg 建议的渲染循环:

function resize() {
  var width = gl.canvas.clientWidth;
  var height = gl.canvas.clientHeight;
  if (gl.canvas.width != width ||
      gl.canvas.height != height) {
     gl.canvas.width = width;
     gl.canvas.height = height;
     return true;
  }
  return false;
}

var needToRender = true;  // draw at least once
function checkRender() {
   if (resize() || needToRender) {
     needToRender = false;
     drawStuff();
   }
   requestAnimationFrame(checkRender);
}
checkRender();

V
Vincent Scheib

(扩展动静能量的答案)

为画布设置样式以填充主体。渲染到画布时,请考虑其大小。

http://jsfiddle.net/mqFdk/356/

<!DOCTYPE html>
<html>
<head>
    <title>aj</title>
</head>
<body>

    <canvas id="c"></canvas>

</body>
</html>

CSS:

body { 
       margin: 0; 
       padding: 0
     }
#c { 
     position: absolute; 
     width: 100%; 
     height: 100%; 
     overflow: hidden
   }

Javascript:

function redraw() {
    var cc = c.getContext("2d");
    c.width = c.clientWidth;
    c.height = c.clientHeight;
    cc.scale(c.width, c.height);

    // Draw a circle filling the canvas.
    cc.beginPath();
    cc.arc(0.5, 0.5, .5, 0, 2*Math.PI);
    cc.fill();
}

// update on any window size change.
window.addEventListener("resize", redraw);

// first draw
redraw();

d
dzanis

对于手机,最好使用它

canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;

因为更改方向后会显示不正确。将方向更改为纵向时会增加“视口”。查看完整example