Cambiar el tamaño del lienzo HTML5 para que se ajuste a la ventana

400

¿Cómo puedo escalar automáticamente el <canvas>elemento HTML5 para que se ajuste a la página?

Por ejemplo, puedo obtener una <div>escala ajustando las propiedades heighty widthal 100%, pero una <canvas>escala no, ¿verdad?

devyn
fuente
77
¿Por qué el lienzo {ancho: 100%; altura: 100%} no funciona?
zloctb
28
@zloctb: eso escalará el lienzo directamente, lo que estira su imagen.
Derek 朕 會 功夫
8
Consulte los Fundamentos de WebGL para obtener una explicación detallada sobre qué y qué no hacer para los problemas relacionados.
legends2k
2
Un lienzo también escalará bien, solo agregue el css {ancho: 100%}, sin embargo, su contenido no lo hará, ¡eso es algo completamente diferente!
expulsión el

Respuestas:

372

Creo que he encontrado una solución elegante para esto:

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...
}

CSS

html, body {
  width:  100%;
  height: 100%;
  margin: 0;
}

No ha tenido ningún gran impacto negativo en el rendimiento para mí, hasta ahora.

devyn
fuente
77
Probablemente tenga que deshabilitar el margen conbody, html { margin: 0px;}
Nicklas A.
45
¿Es esto preferible a escuchar el evento de cambio de tamaño?
Eric
25
@Elisabeth: para deshacerse de las barras de desplazamiento, agregue "overflow: hidden" al estilo de los elementos html y body. Vea thefutureoftheweb.com/blog/100-percent-height-interface
Denis Washington el
17
Hice esto más, también configuré el lienzo para mostrar: bloque (parecía estar predeterminado para mostrar: ¡en línea, lo que estaba creando espacio adicional!).
Elisabeth
15
Esto puede ser un antipatrón; vea el tercer artículo aquí para ver la razón y el remedio.
legends2k
67

La siguiente solución me funcionó mejor. Como soy relativamente nuevo en la codificación, me gusta tener una confirmación visual de que algo funciona de la manera que espero. Lo encontré en el siguiente sitio: http://htmlcheats.com/html/resize-the-html5-canvas-dyamically/

Aquí está el código:

<!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>

El borde azul muestra el borde del lienzo de cambio de tamaño, y siempre está a lo largo del borde de la ventana, visible en los 4 lados, lo cual NO fue el caso para algunas de las otras respuestas anteriores. Espero eso ayude.

Craig Morrison
fuente
Esta respuesta resolvió mi problema. El overflow: hiddeny display: blockes lo que faltaba para que esto funcionara correctamente.
Deathicon
1
El enlace está roto
Nic Scozzaro
22

Básicamente, lo que tiene que hacer es vincular el evento onresize a su cuerpo, una vez que capta el evento solo necesita cambiar el tamaño del lienzo usando window.innerWidth y 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>
equiman
fuente
1
Podrías usar un oyente de eventos.
David Corbin
Esto tiene márgenes y muestra barras de desplazamiento, además tiene que cambiar el tamaño de la pantalla antes de que haga algo.
ArtOfWarfare
¿Qué sucede si el lienzo es más grande que la ventana gráfica (al hacerla más estrecha o más corta)? Esta solución no parece manejar eso.
Lars Gyrup Brink Nielsen
Las preguntas originales de @ArtOfWarfare no mencionan nada sobre estilos. Pero puede estilizarlo con css y eliminar márgenes y ocultar barras de desplazamiento si lo desea. Y simplemente puede agregar `<body onload =" resize_canvas () ">` luego, cuando la página cargue, cambie el tamaño del lienzo.
equiman
@LayZee pregunta original saya acerca de escalar el lienzo para que se ajuste a la página , no una ventana gráfica. Esa puede ser otra pregunta.
equiman
19

Establecer el ancho y la altura del espacio de coordenadas del lienzo en función de las dimensiones del cliente del navegador requiere que cambie el tamaño y vuelva a dibujar cada vez que cambie el tamaño del navegador.

Una solución menos complicada es mantener las dimensiones dibujables en las variables de Javascript, pero establecer las dimensiones del lienzo en función de las dimensiones screen.width, screen.height. Use CSS para encajar:

#containingDiv { 
  overflow: hidden;
}
#myCanvas {
  position: absolute; 
  top: 0px;
  left: 0px;
} 

La ventana del navegador generalmente nunca será más grande que la pantalla en sí misma (excepto donde la resolución de la pantalla no se informa correctamente, ya que podría ser con monitores duales no coincidentes), por lo que el fondo no se mostrará y las proporciones de píxeles no variarán. Los píxeles del lienzo serán directamente proporcionales a la resolución de la pantalla a menos que use CSS para escalar el lienzo.

jerseyboy
fuente
77
Cambiar el tamaño del lienzo con CSS es problemático. Al menos en Chrome y Safari, las posiciones de evento de mouse / touch no se corresponderán 1: 1 con las posiciones de píxeles del lienzo, y tendrá que transformar los sistemas de coordenadas.
jerseyboy
14

Un enfoque CSS puro que se agrega a la solución de @jerseyboy anterior.
Funciona en Firefox (probado en v29), Chrome (probado en v34) e Internet Explorer (probado en 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>

Enlace al ejemplo: http://temporaer.net/open/so/140502_canvas-fit-to-window.html

Pero tenga cuidado, como dice @jerseyboy en su comentario:

Cambiar el tamaño del lienzo con CSS es problemático. Al menos en Chrome y Safari, las posiciones de eventos de mouse / touch no se corresponderán 1: 1 con las posiciones de píxeles del lienzo, y tendrá que transformar los sistemas de coordenadas.

Volker E.
fuente
55
La forma CSS estira el lienzo, por lo que las imágenes renderizadas se estiran. Esto no es bueno en comparación con cambiar el tamaño del lienzo. Con poco ajuste, la respuesta de Craig funciona mejor.
Nayan
Me gusta esta solución, ya que hace que el lienzo esté 100% basado en el ancho principal.
Maihan Nijat
9
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);
Petr
fuente
Agradable, cuando la proporción es importante
sarkiroka
8

A menos que desee que el lienzo aumente la escala de sus datos de imagen automáticamente (de eso es de lo que habla la respuesta de James Black, pero no se verá bonito), debe cambiar el tamaño usted mismo y volver a dibujar la imagen. Centrando un lienzo

Nickolay
fuente
4

Si su div llenó completamente la página web, entonces puede llenar ese div y así tener un lienzo que llena el div.

Puede encontrar esto interesante, ya que puede necesitar usar un CSS para usar el porcentaje, pero depende de qué navegador esté usando y de cuánto esté de acuerdo con la especificación: http://www.whatwg.org/ specs / web-apps / current-work / multipage / the-canvas-element.html # the-canvas-element

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.

Es posible que deba obtener el offsetWidth y la altura del div, u obtener la altura / ancho de la ventana y establecerlo como el valor de píxel.

James Black
fuente
3

CSS

body { margin: 0; } 
canvas { display: block; } 

JavaScript

window.addEventListener("load", function()
{
    var canvas = document.createElement('canvas'); document.body.appendChild(canvas);
    var context = canvas.getContext('2d');

    function draw()
    {
        context.clearRect(0, 0, canvas.width, canvas.height);
        context.beginPath();
        context.moveTo(0, 0); context.lineTo(canvas.width, canvas.height); 
        context.moveTo(canvas.width, 0); context.lineTo(0, canvas.height); 
        context.stroke();
    }
    function resize()
    {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        draw();
    }
    window.addEventListener("resize", resize);
    resize();
});
Martin Wantke
fuente
3

Si está interesado en preservar las relaciones de aspecto y hacerlo en CSS puro (dada la relación de aspecto), puede hacer algo como a continuación. La clave está padding-bottomen el ::contentelemento que dimensiona el containerelemento. Esto tiene un tamaño relativo al ancho de su padre, que es 100%por defecto. La proporción especificada aquí tiene que coincidir con la proporción de los tamaños en el canvaselemento.

// Javascript

var canvas = document.querySelector('canvas'),
    context = canvas.getContext('2d');

context.fillStyle = '#ff0000';
context.fillRect(500, 200, 200, 200);

context.fillStyle = '#000000';
context.font = '30px serif';
context.fillText('This is some text that should not be distorted, just scaled', 10, 40);
/*CSS*/

.container {
  position: relative; 
  background-color: green;
}

.container::after {
  content: ' ';
  display: block;
  padding: 0 0 50%;
}

.wrapper {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
}

canvas {
  width: 100%;
  height: 100%;
}
<!-- HTML -->

<div class=container>
  <div class=wrapper>
    <canvas width=1200 height=600></canvas>  
  </div>
</div>

mrmcgreg
fuente
2

Usando jQuery puedes rastrear el tamaño de la ventana y cambiar el ancho de tu lienzo usando jQuery también.

Algo como eso

$( window ).resize(function() {
 		$("#myCanvas").width($( window ).width())
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #000000;">

Rafael Andrade
fuente
1
(function() {

    // get viewport size
    getViewportSize = function() {
        return {
            height: window.innerHeight,
            width:  window.innerWidth
        };
    };

    // update canvas size
    updateSizes = function() {
        var viewportSize = getViewportSize();
        $('#myCanvas').width(viewportSize.width).height(viewportSize.height);
        $('#myCanvas').attr('width', viewportSize.width).attr('height', viewportSize.height);
    };

    // run on load
    updateSizes();

    // handle window resizing
    $(window).on('resize', function() {
        updateSizes();
    });

}());
lokers
fuente
0

Creo que esto es exactamente lo que debemos hacer: http://www.html5rocks.com/en/tutorials/casestudies/gopherwoord-studios-resizing-html5-games/

function resizeGame() {
    var gameArea = document.getElementById('gameArea');
    var widthToHeight = 4 / 3;
    var newWidth = window.innerWidth;
    var newHeight = window.innerHeight;
    var newWidthToHeight = newWidth / newHeight;

    if (newWidthToHeight > widthToHeight) {
        newWidth = newHeight * widthToHeight;
        gameArea.style.height = newHeight + 'px';
        gameArea.style.width = newWidth + 'px';
    } else {
        newHeight = newWidth / widthToHeight;
        gameArea.style.width = newWidth + 'px';
        gameArea.style.height = newHeight + 'px';
    }

    gameArea.style.marginTop = (-newHeight / 2) + 'px';
    gameArea.style.marginLeft = (-newWidth / 2) + 'px';

    var gameCanvas = document.getElementById('gameCanvas');
    gameCanvas.width = newWidth;
    gameCanvas.height = newHeight;
}

window.addEventListener('resize', resizeGame, false);
window.addEventListener('orientationchange', resizeGame, false);
Arvind Bhardwaj
fuente
-2

Estoy usando sketch.js, así que después de ejecutar el comando init para el lienzo, cambio el ancho y la altura con jquery. Basa las dimensiones en el elemento padre.

$ ('# DrawCanvas'). Sketch (). Attr ('height', $ ('# DrawCanvas'). Parent (). Height ()). Attr ('width', $ ('# DrawCanvas'). Parent ().anchura());

Moeiscool
fuente