Redimensionner le canevas HTML5 pour l'adapter à la fenêtre

400

Comment mettre automatiquement à l'échelle l' <canvas>élément HTML5 pour l'adapter à la page?

Par exemple, je peux obtenir une mise <div>à l'échelle en définissant les propriétés heightet widthà 100%, mais <canvas>pas une mise à l'échelle, n'est-ce pas?

devyn
la source
7
pourquoi la toile {largeur: 100%; hauteur: 100%} ne fonctionne pas?
zloctb
28
@zloctb - Cela agrandira directement la toile, ce qui étire votre image.
Derek 朕 會 功夫
8
Voir les principes de base de WebGL pour une explication détaillée sur ce qu'il faut faire et ce qu'il ne faut pas faire pour les problèmes connexes.
legends2k
2
Un canevas évoluera également très bien, il suffit d'ajouter le css {width: 100%}, son contenu ne sera pas cependant, c'est une autre affaire entièrement!
ejectamenta

Réponses:

372

Je crois avoir trouvé une solution élégante à cela:

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

Jusqu'à présent, cela n'a pas eu un grand impact négatif sur les performances.

devyn
la source
7
Vous devez probablement désactiver la marge avecbody, html { margin: 0px;}
Nicklas A.
45
Est-ce préférable à l'écoute de l'événement de redimensionnement?
Eric
25
@Elisabeth: Pour se débarrasser des barres de défilement, ajoutez "overflow: hidden" au style des éléments html et body. Voir thefutureoftheweb.com/blog/100-percent-height-interface
Denis Washington
17
J'ai fait cela et j'ai également défini canvas pour afficher: block (il semblait être par défaut pour afficher: inline qui créait de l'espace supplémentaire!).
Elisabeth
15
Cela peut être un anti-modèle; voir le troisième élément ici pour la raison et le remède.
legends2k
67

La solution suivante a fonctionné le mieux pour moi. Étant donné que je suis relativement nouveau dans le codage, j'aime avoir une confirmation visuelle que quelque chose fonctionne comme je m'y attend. Je l'ai trouvé sur le site suivant: http://htmlcheats.com/html/resize-the-html5-canvas-dyamically/

Voici le code:

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

La bordure bleue vous montre le bord de la zone de redimensionnement et se trouve toujours le long du bord de la fenêtre, visible sur les 4 côtés, ce qui n'était PAS le cas pour certaines des autres réponses ci-dessus. J'espère que cela aide.

Craig Morrison
la source
Cette réponse a résolu mon problème. Le overflow: hiddenet display: blockest ce qui me manquait pour que cela fonctionne correctement.
Deathicon
1
Le lien est rompu
Nic Scozzaro
22

Fondamentalement, ce que vous devez faire est de lier l'événement onresize à votre corps, une fois que vous avez attrapé l'événement, il vous suffit de redimensionner le canevas à l'aide de window.innerWidth et 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
la source
1
Vous pouvez simplement utiliser un écouteur d'événements.
David Corbin
Cela a des marges et affiche des barres de défilement, plus vous devez redimensionner l'écran avant de faire quoi que ce soit.
ArtOfWarfare
Que se passe-t-il si la zone de dessin est plus grande que la fenêtre d'affichage (lorsque la fenêtre est plus étroite ou plus courte)? Cette solution ne semble pas gérer cela.
Lars Gyrup Brink Nielsen
Les questions originales @ArtOfWarfare ne mentionnent rien sur les styles. Mais vous pouvez le styliser avec CSS et supprimer les marges et masquer les barres de défilement si vous le souhaitez. Et vous pouvez simplement ajouter `<body onload =" resize_canvas () ">` puis au chargement de la page puis redimensionner le canevas.
equiman
@LayZee original question saya bout scale the canvas to fit the page , not a viewport. C'est peut-être une autre question.
equiman
19

Pour définir la largeur et la hauteur de l'espace de coordonnées du canevas en fonction des dimensions du client du navigateur, vous devez redimensionner et redessiner chaque fois que le navigateur est redimensionné.

Une solution moins compliquée consiste à conserver les dimensions dessinables dans les variables Javascript, mais à définir les dimensions du canevas en fonction des dimensions screen.width, screen.height. Utilisez CSS pour ajuster:

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

La fenêtre du navigateur ne sera généralement jamais plus grande que l'écran lui-même (sauf lorsque la résolution de l'écran est mal déclarée, comme cela pourrait être le cas avec deux moniteurs non correspondants), donc l'arrière-plan ne s'affichera pas et les proportions de pixels ne varieront pas. Les pixels du canevas seront directement proportionnels à la résolution de l'écran, sauf si vous utilisez CSS pour mettre le canevas à l'échelle.

jerseyboy
la source
7
Le redimensionnement du canevas avec CSS est problématique. Au moins sur Chrome et Safari, les positions des événements souris / tactiles ne correspondront pas à 1: 1 avec les positions des pixels du canevas, et vous devrez transformer les systèmes de coordonnées.
jerseyboy
14

Une approche CSS pure s'ajoutant à la solution de @jerseyboy ci-dessus.
Fonctionne sous Firefox (testé en v29), Chrome (testé en v34) et Internet Explorer (testé 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>

Lien vers l'exemple: http://temporaer.net/open/so/140502_canvas-fit-to-window.html

Mais attention, comme le dit @jerseyboy dans son commentaire:

Le redimensionnement du canevas avec CSS est gênant. Au moins sur Chrome et Safari, les positions des événements souris / tactile ne correspondront pas 1: 1 aux positions des pixels du canevas, et vous devrez transformer les systèmes de coordonnées.

Volker E.
la source
5
La manière CSS étend la toile, ainsi les images rendues sont étirées. Ce n'est pas bon par rapport au redimensionnement de la toile. Avec peu d'ajustement, la réponse de Craig fonctionne mieux.
Nayan
J'aime cette solution car cela rend la toile 100% basée sur la largeur du parent.
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
la source
Nice, quand le ratio est important
sarkiroka
8

À moins que vous ne vouliez que le canevas améliore automatiquement vos données d'image (c'est ce dont parle la réponse de James Black, mais ce ne sera pas joli), vous devez le redimensionner vous-même et redessiner l'image. Centrer une toile

Nickolay
la source
4

Si votre div a complètement rempli la page Web, vous pouvez remplir cette div et ainsi avoir une toile qui remplit la div.

Vous trouverez peut-être cela intéressant, car vous devrez peut-être utiliser un CSS pour utiliser le pourcentage, mais cela dépend du navigateur que vous utilisez et de son accord avec les spécifications: http://www.whatwg.org/ spécifications / applications web / travaux en cours / multipage / the-canvas-element.html # the-canvas-element

Les dimensions intrinsèques de l'élément canvas correspondent à la taille de l'espace de coordonnées, les nombres étant interprétés en pixels CSS. Cependant, l'élément peut être dimensionné arbitrairement par une feuille de style. Pendant le rendu, l'image est mise à l'échelle pour s'adapter à cette taille de mise en page.

Vous devrez peut-être obtenir l'offsetWidth et la hauteur de la div, ou obtenir la hauteur / largeur de la fenêtre et la définir comme valeur de pixel.

James Black
la source
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
la source
3

Si vous souhaitez conserver les proportions et le faire en CSS pur (compte tenu des proportions), vous pouvez faire quelque chose comme ci-dessous. La clé est padding-bottomsur l' ::contentélément qui dimensionne l' containerélément. Ceci est dimensionné par rapport à la largeur de son parent, qui est 100%par défaut. Le rapport spécifié ici doit correspondre au rapport des tailles sur l' canvasélément.

// 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
la source
2

À l'aide de jQuery, vous pouvez également suivre le redimensionnement de la fenêtre et modifier la largeur de votre toile à l'aide de jQuery.

Quelque chose comme ca

$( 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
la source
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
la source
0

Je pense que c'est ce que nous devons faire exactement: 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
la source
-2

J'utilise sketch.js donc après avoir exécuté la commande init pour la toile, je change la largeur et la hauteur avec jquery. Il base les dimensions sur l'élément parent.

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

moeiscool
la source