HTML5 Canvas 100% Ancho Altura de Viewport?

151

Estoy tratando de crear un elemento de lienzo que ocupe el 100% del ancho y alto de la ventana gráfica.

Puede ver en mi ejemplo aquí lo que está ocurriendo, sin embargo, está agregando barras de desplazamiento en Chrome y Firefox. ¿Cómo puedo evitar las barras de desplazamiento adicionales y simplemente proporcionar exactamente el ancho y la altura de la ventana para que sea del tamaño del lienzo?

aherrick
fuente
1
Ver también: stackoverflow.com/questions/4037212
hippietrail
Me recuerda un boceto de comedia de Fonejacker bastante divertido: youtu.be/6oj_oLMD688?t=22s
Francis Booth

Respuestas:

258

Para hacer que el lienzo tenga siempre el ancho y la altura de la pantalla completa, lo que significa que incluso cuando se cambia el tamaño del navegador, debe ejecutar su ciclo de dibujo dentro de una función que redimensione el lienzo a window.innerHeight y window.innerWidth.

Ejemplo: http://jsfiddle.net/jaredwilli/qFuDr/

HTML

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

JavaScript

(function() {
    var canvas = document.getElementById('canvas'),
            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 */

Así es como se hace que el lienzo tenga el ancho y la altura completos del navegador. Solo tiene que poner todo el código para dibujar en el lienzo en la función drawStuff ().

jaredwilli
fuente
2
¿Por qué es necesario eliminar el relleno y establecer el ancho, la altura al 100%?
Kos
3
Creo que es principalmente para anular la hoja de estilo de usuario para la que el navegador tiene los valores predeterminados. Si está utilizando algún tipo de archivo CSS normalizar o restablecer, esto no es necesario ya que ya se habrá solucionado.
jaredwilli
2
Si espera un gran cambio de tamaño; en un dispositivo vertical / horizontal, por ejemplo, desea debouncecambiar el tamaño, de lo contrario, inundará el navegador.
dooburt
24
display: block: Esto no solo elimina las barras de desplazamiento, sino que elimina 2 píxeles de la altura del cuerpo del documento, que normalmente se agregan debajo de las líneas de texto dentro de un bloque. Entonces +1 para eso
Neptilo
2
plus one for no jQuery
Félix Gagnon-Grenier
26

Puede probar las unidades de ventana gráfica (CSS3):

canvas { 
  height: 100vh; 
  width: 100vw; 
  display: block;
}
Vitalii Fedorenko
fuente
55
Agregue display: block;y hace el trabajo.
superlukas
18
Intenté esto y descubrí que en Chrome y Firefox, el lienzo simplemente muestra la imagen extendida a la vista completa. Incluso los elementos recién dibujados también se estiran.
Vivian River
8
@Daniel tiene razón: esta respuesta es incorrecta . No establecerá la dimensión interna del contexto del lienzo, sino las dimensiones del elemento DOM. Para la diferencia, vea mi respuesta a una pregunta relacionada .
Dan Dascalescu
19
Este método no funciona, estira el texto. Desafortunadamente tienes que usar JS.
i336_
16

Contestaré la pregunta más general de cómo hacer que un lienzo se adapte dinámicamente en tamaño al cambiar el tamaño de la ventana. La respuesta aceptada maneja adecuadamente el caso en el que se supone que el ancho y la altura son del 100%, que es lo que se solicitó, pero que también cambiará la relación de aspecto del lienzo. Muchos usuarios querrán que el lienzo cambie el tamaño de la ventana, pero manteniendo intacta la relación de aspecto. No es la pregunta exacta, pero "encaja", simplemente colocando la pregunta en un contexto un poco más general.

La ventana tendrá una relación de aspecto (ancho / alto), y también el objeto del lienzo. La forma en que desea que estas dos relaciones de aspecto se relacionen entre sí es una cosa que tendrá que tener claro, no hay una respuesta de "talla única para todos" a esta pregunta. Revisaré algunos casos comunes de lo que podría querer.

Lo más importante que debe tener claro: el objeto de lienzo html tiene un atributo de ancho y un atributo de altura; y luego, el css del mismo objeto también tiene un atributo de ancho y alto. Esos dos anchos y alturas son diferentes, ambos son útiles para diferentes cosas.

Cambiar los atributos de ancho y alto es un método con el que siempre puede cambiar el tamaño de su lienzo, pero luego tendrá que volver a pintar todo, lo que llevará tiempo y no siempre es necesario, porque puede lograr una cierta cantidad de cambio de tamaño. a través de los atributos css, en cuyo caso no vuelve a dibujar el lienzo.

Veo 4 casos de lo que podría querer que suceda en el cambio de tamaño de la ventana (todos comenzando con un lienzo de pantalla completa)

1: desea que el ancho permanezca al 100%, y desea que la relación de aspecto permanezca como estaba. En ese caso, no necesita volver a dibujar el lienzo; Ni siquiera necesita un controlador de cambio de tamaño de ventana. Todo lo que necesitas es

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

donde ctx es su contexto de lienzo. violín: resizeByWidth

2: desea que el ancho y la altura se mantengan al 100%, y desea que el cambio resultante en la relación de aspecto tenga el efecto de una imagen estirada. Ahora, aún no necesita volver a dibujar el lienzo, pero necesita un controlador de cambio de tamaño de ventana. En el controlador, lo haces

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

violín: messWithAspectratio

3: desea que el ancho y la altura se mantengan al 100%, pero la respuesta al cambio en la relación de aspecto es algo diferente de estirar la imagen. Luego, debe volver a dibujar y hacerlo de la manera que se describe en la respuesta aceptada.

violín: redibujar

4: desea que el ancho y la altura sean del 100% en la carga de la página, pero permanezca constante a partir de entonces (no hay reacción al cambio de tamaño de la ventana.

violín: fijo

Todos los violines tienen un código idéntico, excepto la línea 63 donde se establece el modo. También puede copiar el código de violín para ejecutarlo en su máquina local, en cuyo caso puede seleccionar el modo mediante un argumento de cadena de consulta, como? Mode = redraw

Mathheadinclouds
fuente
1
digo: $(ctx.canvas).css("width", "100%");es equivalente a $(canvas).css("width", "100%"); (el lienzo del contexto es solo el lienzo)
Brad Kent
@BradKent cuando llama a una función auxiliar que hace las "cosas del lienzo" que desea hacer, puede, como argumento (s) 1) pasar el objeto del lienzo, 2) pasar el contexto del lienzo, 3) ambos. No me gusta 3), y ctx.canvases mucho más corto canvas.getContext('2d')que, por eso hago 2). Por lo tanto, no existe una variable llamada lienzo, pero sí ctx.canvas. De ahí proviene ctx.canvas.
mathheadinclouds
9

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

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

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

</body>
</html>

con CSS

body { 
       margin: 0; 
       padding: 0
     }
#c { 
     position: absolute; 
     width: 100%; 
     height: 100%; 
     overflow: hidden
   }
nonopolaridad
fuente
Esto funciona, pero deja mi lienzo sin una anchura y altura definidas. El ancho y la altura del lienzo deben definirse en el elemento que creo.
aherrick
@aherrick: No, no es necesario que tenga un ancho / alto explícito establecido en el elemento del lienzo para que funcione. Este código debería funcionar bien.
Jon Adams
18
En realidad sí, los elementos de lienzo necesitan un conjunto explícito de ancho / alto. Sin él, el tamaño predeterminado es un navegador preestablecido (en Chrome, creo que es de 300x150px). Todo el dibujo al lienzo se interpreta en este tamaño y luego se escala al 100% del tamaño de la ventana gráfica. Intenta dibujar algo en tu lienzo para ver a qué me refiero: estará distorsionado.
Mark Kahn
si está tratando de hacer que el lienzo sea 100% ancho y alto, eso ni siquiera importa en absoluto. de todos modos
simplemente cambia el
1
Las dimensiones intrínsecas del elemento canvas son iguales al tamaño del espacio de coordenadas, con los números interpretados en píxeles CSS. Sin embargo, el elemento puede ser dimensionado arbitrariamente por una hoja de estilo. Durante el renderizado, la imagen se escala para adaptarse a este tamaño de diseño.
jaredwilli
8

Estaba buscando encontrar la respuesta a esta pregunta también, pero la respuesta aceptada me estaba rompiendo. Aparentemente, usar window.innerWidth no es portátil. Funciona en algunos navegadores, pero noté que a Firefox no le gustaba.

Gregg Tavares publicó un gran recurso aquí que aborda este problema directamente: http://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html (Ver anti-patrón # 's 3 y 4).

El uso de canvas.clientWidth en lugar de window.innerWidth parece funcionar bien.

Aquí está el bucle de render sugerido de 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();
David
fuente
2

(Ampliando la respuesta de 動靜 能量)

Diseña el lienzo para llenar el cuerpo. Al renderizar en el lienzo, tenga en cuenta su tamaño.

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();
Vincent Scheib
fuente
1

Para móviles, es mejor usarlo

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

porque se mostrará incorrectamente después de cambiar la orientación. La "vista" aumentará al cambiar la orientación a vertical. Vea el ejemplo completo

dzanis
fuente