HTML5 Canvas 100% Largeur Hauteur de la fenêtre?

151

J'essaie de créer un élément de toile qui occupe 100% de la largeur et de la hauteur de la fenêtre.

Vous pouvez voir dans mon exemple ici que cela se produit, mais il ajoute des barres de défilement dans Chrome et FireFox. Comment puis-je éviter les barres de défilement supplémentaires et simplement fournir exactement la largeur et la hauteur de la fenêtre à la taille du canevas?

Aherrick
la source
1
Voir aussi: stackoverflow.com/questions/4037212
hippietrail
Cela me rappelle un sketch de comédie Fonejacker plutôt amusant: youtu.be/6oj_oLMD688?t=22s
Francis Booth

Réponses:

258

Pour que le canevas soit toujours plein écran en largeur et hauteur, c'est-à-dire même lorsque le navigateur est redimensionné, vous devez exécuter votre boucle de dessin dans une fonction qui redimensionne le canevas en window.innerHeight et window.innerWidth.

Exemple: 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 */

C'est ainsi que vous créez correctement le canevas sur toute la largeur et la hauteur du navigateur. Il vous suffit de mettre tout le code pour dessiner sur le canevas dans la fonction drawStuff ().

Jaredwilli
la source
2
Pourquoi est-il nécessaire de supprimer le rembourrage et de définir la largeur et la hauteur à 100%?
Kos
3
Je pense que c'est principalement pour remplacer la feuille de style utilisateur pour laquelle le navigateur a des valeurs par défaut. Si vous utilisez une sorte de fichier css de normalisation ou de réinitialisation, ce n'est pas nécessaire car cela sera déjà pris en charge.
jaredwilli
2
Si vous vous attendez à beaucoup de redimensionnement; sur un appareil portrait / paysage par exemple, vous voudriez debouncele redimensionner sinon vous inonderez le navigateur.
dooburt
24
display: block: Non seulement cela supprime les barres de défilement, mais cela supprime 2px de la hauteur du corps du document, qui sont normalement ajoutés sous les lignes de texte à l'intérieur d'un bloc. Donc +1 pour ça
Neptilo
2
plus un pour no jQuery
Félix Gagnon-Grenier
26

Vous pouvez essayer les unités de fenêtre (CSS3):

canvas { 
  height: 100vh; 
  width: 100vw; 
  display: block;
}
Vitalii Fedorenko
la source
5
Ajoutez display: block;et il fait le travail.
superlukas
18
J'ai essayé cela et j'ai trouvé que dans Chrome et Firefox, le canevas montre simplement l'image étirée dans la fenêtre complète. Même les éléments nouvellement dessinés sont également étirés.
Vivian River
8
@Daniel a raison - cette réponse est fausse . Il ne définira pas la dimension interne du contexte de canevas, mais plutôt les dimensions de l'élément DOM. Pour la différence, voir ma réponse à une question connexe .
Dan Dascalescu
19
Cette méthode ne fonctionne pas, elle étire le texte. Malheureusement vous devez utiliser JS.
i336_
16

Je répondrai à la question plus générale de savoir comment faire adapter dynamiquement la taille d'un canevas lors du redimensionnement de la fenêtre. La réponse acceptée gère de manière appropriée le cas où la largeur et la hauteur sont toutes deux supposées être de 100%, ce qui a été demandé, mais qui modifiera également le rapport hauteur / largeur de la toile. De nombreux utilisateurs voudront que le canevas soit redimensionné lors du redimensionnement de la fenêtre, mais tout en conservant le rapport hauteur / largeur intact. Ce n'est pas la question exacte, mais elle «s'intègre», mettant simplement la question dans un contexte un peu plus général.

La fenêtre aura un certain rapport hauteur / largeur (largeur / hauteur), tout comme l'objet canevas. Vous devez être clair sur la manière dont vous voulez que ces deux rapports d'aspect se rapportent l'un à l'autre. Il n'y a pas de réponse unique à cette question - je vais passer en revue certains cas courants de ce que vous pourriez vouloir.

La chose la plus importante sur laquelle vous devez être clair: l'objet canevas html a un attribut width et un attribut height; puis, le css du même objet a également un attribut width et height. Ces deux largeurs et hauteurs sont différentes, les deux sont utiles pour des choses différentes.

Changer les attributs de largeur et de hauteur est une méthode avec laquelle vous pouvez toujours changer la taille de votre toile, mais vous devrez alors tout repeindre, ce qui prendra du temps et n'est pas toujours nécessaire, car vous pouvez effectuer un certain changement de taille. via les attributs css, auquel cas vous ne redessinez pas le canevas.

Je vois 4 cas de ce que vous pourriez vouloir se produire lors du redimensionnement de la fenêtre (tous commençant par une toile en plein écran)

1: vous voulez que la largeur reste à 100% et que le rapport hauteur / largeur reste tel qu'il était. Dans ce cas, vous n'avez pas besoin de redessiner le canevas; vous n'avez même pas besoin d'un gestionnaire de redimensionnement de fenêtre. Tout ce dont tu as besoin c'est

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

où ctx est votre contexte de canevas. violon: resizeByWidth

2: vous voulez que la largeur et la hauteur restent toutes les deux à 100%, et vous voulez que le changement de rapport hauteur / largeur qui en résulte ait l'effet d'une image étirée. Désormais, vous n'avez toujours pas besoin de redessiner le canevas, mais vous avez besoin d'un gestionnaire de redimensionnement de fenêtre. Dans le gestionnaire, vous faites

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

violon: messWithAspectratio

3: vous voulez que la largeur et la hauteur restent toutes les deux à 100%, mais la réponse au changement de rapport hauteur / largeur est quelque chose de différent de l'étirement de l'image. Ensuite, vous devez redessiner et le faire comme indiqué dans la réponse acceptée.

violon: redessiner

4: vous voulez que la largeur et la hauteur soient de 100% au chargement de la page, mais restent constantes par la suite (pas de réaction au redimensionnement de la fenêtre.

violon: fixe

Tous les violons ont un code identique, sauf pour la ligne 63 où le mode est défini. Vous pouvez également copier le code de violon à exécuter sur votre machine locale, auquel cas vous pouvez sélectionner le mode via un argument de chaîne de requête, comme? Mode = redraw

mathheads
la source
1
fyi: $(ctx.canvas).css("width", "100%");équivaut à $(canvas).css("width", "100%"); (le canevas du contexte n'est que le canevas)
Brad Kent
@BradKent lorsque vous appelez une fonction d'assistance qui fait les "choses-canevas" que vous voulez faire, vous pouvez soit, en tant qu'argument (s) 1) passer l'objet canevas, 2) passer le contexte canevas, 3) les deux. Je n'aime pas 3), et ctx.canvasc'est beaucoup plus court que canvas.getContext('2d')- c'est pourquoi je fais 2). Par conséquent, il n'y a pas de variable appelée canvas, mais il y a ctx.canvas. C'est de là que vient ctx.canvas.
mathheadinclouds
9

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

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

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

</body>
</html>

avec CSS

body { 
       margin: 0; 
       padding: 0
     }
#c { 
     position: absolute; 
     width: 100%; 
     height: 100%; 
     overflow: hidden
   }
non-polarité
la source
Cela fonctionne, mais cela laisse ma toile sans largeur ni hauteur définies. La largeur et la hauteur de la toile doivent être définies sur l'élément que je crois.
aherrick
@aherrick: Non, vous n'avez pas besoin d'avoir une largeur / hauteur explicite définie sur l'élément canvas pour que cela fonctionne. Ce code devrait fonctionner correctement.
Jon Adams le
18
En fait, oui, les éléments du canevas ont besoin d'un ensemble largeur / hauteur explicite. Sans cela, ils utilisent par défaut une taille de navigateur prédéfinie (en chrome, je pense que c'est 300x150px). Tous les dessins sur le canevas sont interprétés à cette taille, puis mis à l'échelle à 100% de la taille de la fenêtre. Essayez de dessiner n'importe quoi dans votre toile pour voir ce que je veux dire - il sera déformé.
Mark Kahn
si vous essayez de rendre la toile à 100% de largeur et de hauteur, cela n'a même pas d'importance. vous venez de le redimensionner de toute façon
jaredwilli
1
Les dimensions intrinsèques de l'élément canvas sont égales à la taille de l'espace de coordonnées, les nombres étant interprétés en pixels CSS. Cependant, l'élément peut être dimensionné de manière arbitraire par une feuille de style. Lors du rendu, l'image est mise à l'échelle pour s'adapter à cette taille de mise en page.
jaredwilli
8

Je cherchais aussi à trouver la réponse à cette question, mais la réponse acceptée était cassante pour moi. Apparemment, utiliser window.innerWidth n'est pas portable. Cela fonctionne dans certains navigateurs, mais j'ai remarqué que Firefox ne l'aimait pas.

Gregg Tavares a publié ici une excellente ressource qui traite directement de ce problème: http://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html (voir les anti-pattern # 3 et 4).

L'utilisation de canvas.clientWidth au lieu de window.innerWidth semble bien fonctionner.

Voici la boucle de rendu suggérée par 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
la source
2

(Développant la réponse de 動靜 能量)

Donnez du style à la toile pour qu'elle remplisse le corps. Lors du rendu sur le canevas, tenez compte de sa taille.

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
la source
1

Pour les mobiles, il vaut mieux l'utiliser

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

car il ne s'affichera pas correctement après avoir changé l'orientation. La «fenêtre» sera agrandie lors du changement d'orientation en portrait. Voir l' exemple complet

dzanis
la source