Passen Sie die Größe der HTML5-Zeichenfläche an das Fenster an

400

Wie kann ich das HTML5- <canvas>Element automatisch an die Seite anpassen?

Zum Beispiel kann ich eine <div>Skalierung erhalten, indem ich die Eigenschaften heightund widthauf 100% setze, aber eine <canvas>wird nicht skaliert, oder?

Devyn
quelle
7
Warum funktioniert Canvas {Breite: 100%; Höhe: 100%} nicht?
Zloctb
28
@zloctb - Dadurch wird die Leinwand direkt vergrößert, wodurch Ihr Bild gestreckt wird.
Derek 2 會 功夫
8
In den WebGL-Grundlagen finden Sie eine ausführliche Erläuterung, was bei verwandten Problemen zu tun ist und was nicht.
Legends2k
2
Eine Leinwand lässt sich auch gut skalieren. Fügen Sie einfach das CSS {width: 100%} hinzu, der Inhalt jedoch nicht, das ist eine ganz andere Sache!
Auswurf

Antworten:

372

Ich glaube, ich habe eine elegante Lösung dafür gefunden:

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

Hat bisher keine großen negativen Auswirkungen auf die Leistung für mich gehabt.

Devyn
quelle
7
Sie müssen wahrscheinlich Marge mitbody, html { margin: 0px;}
Nicklas A.
45
Ist dies dem Abhören des Größenänderungsereignisses vorzuziehen?
Eric
25
@Elisabeth: Um die Bildlaufleisten zu entfernen, fügen Sie dem Stil der HTML- und Body-Elemente "overflow: hidden" hinzu. Siehe thefutureoftheweb.com/blog/100-percent-height-interface
Denis Washington
17
Ich habe dies getan und außerdem die Leinwand auf display: block eingestellt (standardmäßig wurde angezeigt: inline, wodurch zusätzlicher Speicherplatz geschaffen wurde!).
Elisabeth
15
Dies kann ein Anti-Muster sein; Siehe den dritten Punkt hier für den Grund und die Abhilfe.
Legends2k
67

Die folgende Lösung hat bei mir am besten funktioniert. Da ich relativ neu im Codieren bin, möchte ich eine visuelle Bestätigung haben, dass etwas so funktioniert, wie ich es erwartet habe. Ich habe es auf der folgenden Website gefunden: http://htmlcheats.com/html/resize-the-html5-canvas-dyamically/

Hier ist der 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>

Der blaue Rand zeigt Ihnen den Rand der Leinwand zum Ändern der Größe und befindet sich immer am Rand des Fensters, sichtbar auf allen 4 Seiten, was bei einigen der anderen oben genannten Antworten NICHT der Fall war. Ich hoffe es hilft.

Craig Morrison
quelle
Diese Antwort hat mein Problem gelöst. Das overflow: hiddenund display: blockist das, was mir gefehlt hat, damit das richtig funktioniert.
Deathicon
1
Die Verbindung ist unterbrochen
Nic Scozzaro
22

Grundsätzlich müssen Sie das Ereignis onresize an Ihren Körper binden. Sobald Sie das Ereignis erfasst haben, müssen Sie nur die Größe der Zeichenfläche mit window.innerWidth und window.innerHeight ändern.

<!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
quelle
1
Sie können einfach einen Ereignis-Listener verwenden.
David Corbin
Dies hat Ränder und zeigt Bildlaufleisten an. Außerdem müssen Sie die Größe des Bildschirms ändern, bevor er etwas tut.
ArtOfWarfare
Was ist, wenn die Leinwand größer als das Ansichtsfenster ist (wenn das Ansichtsfenster schmaler oder kürzer gemacht wird)? Diese Lösung scheint das nicht zu handhaben.
Lars Gyrup Brink Nielsen
@ArtOfWarfare Originalfragen erwähnen nichts über Stile. Sie können es jedoch mit CSS stilisieren, Ränder entfernen und Bildlaufleisten ausblenden, wenn Sie möchten. Und Sie können einfach `<body onload =" resize_canvas () ">` hinzufügen und dann beim Laden der Seite die Größe der Zeichenfläche ändern.
Equiman
@LayZee ursprüngliche Frage saya etwa skalieren Sie die Leinwand, um die Seite zu passen , nicht ein Ansichtsfenster. Das kann eine andere Frage sein.
Equiman
19

Wenn Sie die Breite und Höhe des Canvas-Koordinatenraums basierend auf den Abmessungen des Browser-Clients festlegen, müssen Sie die Größe ändern und neu zeichnen, wenn die Größe des Browsers geändert wird.

Eine weniger komplizierte Lösung besteht darin, die zeichnbaren Dimensionen in Javascript-Variablen beizubehalten, die Canvas-Dimensionen jedoch basierend auf den Dimensionen screen.width, screen.height festzulegen. Verwenden Sie CSS, um Folgendes anzupassen:

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

Das Browserfenster wird im Allgemeinen nie größer als der Bildschirm selbst sein (außer wenn die Bildschirmauflösung falsch angegeben wird, wie dies bei nicht übereinstimmenden Doppelmonitoren der Fall sein könnte), sodass der Hintergrund nicht angezeigt wird und die Pixelproportionen nicht variieren. Die Leinwandpixel sind direkt proportional zur Bildschirmauflösung, es sei denn, Sie verwenden CSS zum Skalieren der Leinwand.

Jerseyboy
quelle
7
Das Neuskalieren der Zeichenfläche mit CSS ist problematisch. Zumindest in Chrome und Safari entsprechen die Maus- / Touch-Ereignispositionen nicht 1: 1 den Canvas-Pixelpositionen, und Sie müssen die Koordinatensysteme transformieren.
Jerseyboy
14

Ein reiner CSS- Ansatz, der zur obigen Lösung von @jerseyboy beiträgt.
Funktioniert in Firefox (getestet in Version 29), Chrome (getestet in Version 34) und Internet Explorer (getestet in Version 11).

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

Link zum Beispiel: http://temporaer.net/open/so/140502_canvas-fit-to-window.html

Aber seien Sie vorsichtig, wie @jerseyboy in seinem Kommentar feststellt:

Das Neuskalieren der Zeichenfläche mit CSS ist problematisch. Zumindest in Chrome und Safari entsprechen die Maus- / Touch-Ereignispositionen nicht 1: 1 den Canvas-Pixelpositionen, und Sie müssen die Koordinatensysteme transformieren.

Volker E.
quelle
5
Durch CSS wird die Leinwand gedehnt, sodass gerenderte Bilder gedehnt werden. Dies ist nicht gut im Vergleich zur Größenänderung der Leinwand. Mit wenig Anpassung funktioniert Craigs Antwort am besten.
Nayan
Ich mag diese Lösung, da dies die Leinwand zu 100% basierend auf der übergeordneten Breite macht.
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
quelle
Schön, wenn das Verhältnis wichtig ist
Sarkiroka
8

Wenn Sie nicht möchten, dass die Leinwand Ihre Bilddaten automatisch hochskaliert (das ist die Antwort von James Black, aber sie sieht nicht hübsch aus), müssen Sie die Größe selbst ändern und das Bild neu zeichnen. Leinwand zentrieren

Nickolay
quelle
4

Wenn Ihr Div die Webseite vollständig ausgefüllt hat, können Sie dieses Div ausfüllen und so eine Leinwand erstellen, die das Div ausfüllt.

Sie finden dies möglicherweise interessant, da Sie möglicherweise ein CSS verwenden müssen, um den Prozentsatz zu verwenden. Dies hängt jedoch davon ab, welchen Browser Sie verwenden und inwieweit er mit der Spezifikation übereinstimmt: http://www.whatwg.org/ specs / web-apps / current-work / mehrseitig / the-canvas-element.html # the-canvas-element

Die intrinsischen Abmessungen des Canvas-Elements entsprechen der Größe des Koordinatenraums, wobei die Zahlen in CSS-Pixeln interpretiert werden. Das Element kann jedoch durch ein Stylesheet beliebig dimensioniert werden. Während des Renderns wird das Bild auf diese Layoutgröße skaliert.

Möglicherweise müssen Sie die Offsetbreite und -höhe des Div oder die Fensterhöhe / -breite abrufen und als Pixelwert festlegen.

James Black
quelle
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
quelle
3

Wenn Sie daran interessiert sind, Seitenverhältnisse beizubehalten und dies in reinem CSS (angesichts des Seitenverhältnisses) zu tun, können Sie Folgendes tun. Der Schlüssel ist der padding-bottomauf dem ::contentElement, der die Größe des containerElements angibt. Die Größe ist relativ zur Breite des übergeordneten Elements festgelegt, die 100%standardmäßig verwendet wird. Das hier angegebene Verhältnis muss mit dem Verhältnis der Größen auf dem canvasElement übereinstimmen .

// 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
quelle
2

Mit jQuery können Sie die Größe des Fensters verfolgen und die Breite Ihrer Zeichenfläche auch mit jQuery ändern.

So ähnlich

$( 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
quelle
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();
    });

}());
Loker
quelle
0

Ich denke, genau das sollten wir tun: 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
quelle
-2

Ich verwende skizze.js. Nachdem ich den Befehl init für die Zeichenfläche ausgeführt habe, ändere ich die Breite und Höhe mit jquery. Die Bemaßungen basieren auf dem übergeordneten Element.

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

moeiscool
quelle