Изменить размер HTML5 холста, чтобы соответствовать окну

400

Как я могу автоматически масштабировать <canvas>элемент HTML5, чтобы он соответствовал странице?

Например, я могу получить <div>в масштабе, установив heightи widthсвойства на 100%, но <canvas>не будет масштабироваться, будет ли он?

Devyn
источник
7
почему холст {ширина: 100%; высота: 100%} не работает?
zloctb
28
@zloctb - это увеличит холст напрямую, который растянет ваше изображение.
Дерек 功夫 會 功夫
8
См. Основы WebGL для подробного объяснения того, что и что не следует делать для связанных с этим вопросов.
legends2k
2
Холст также будет хорошо масштабироваться, просто добавьте css {width: 100%}, но его содержимое не будет, это совсем другое дело!
ejectamenta

Ответы:

372

Я считаю, что нашел элегантное решение для этого:

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

До сих пор не оказал большого негативного влияния на производительность.

Devyn
источник
7
Вы, вероятно, должны отключить маржу сbody, html { margin: 0px;}
Никлас А.
45
Является ли это предпочтительным для прослушивания события изменения размера?
Эрик
25
@Elisabeth: чтобы избавиться от полос прокрутки, добавьте «overflow: hidden» к стилю элементов HTML и body. Смотрите thefutureoftheweb.com/blog/100-percent-height-interface
Денис Вашингтон,
17
Я сделал это плюс, я также установил canvas для display: block (он показался по умолчанию для display: inline, который создавал дополнительное пространство!).
Элизабет
15
Это может быть анти-паттерном; см. третий пункт здесь, чтобы узнать причину и способ устранения.
legends2k
67

Следующее решение сработало для меня лучше всего. Поскольку я относительно новичок в кодировании, мне нравится получать визуальное подтверждение того, что что-то работает так, как я ожидаю. Я нашел это на следующем сайте: http://htmlcheats.com/html/resize-the-html5-canvas-dyamically/

Вот код:

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

Синяя рамка показывает край изменяемого размера холста и всегда находится вдоль края окна, видимого со всех четырех сторон, что НЕ было случаем для некоторых других приведенных выше ответов. Надеюсь, поможет.

Крейг Моррисон
источник
Этот ответ решил мою проблему. overflow: hiddenИ display: blockто , что не хватает для меня , чтобы получить эту работу должным образом.
Deathicon
1
Ссылка не работает
Nic Scozzaro
22

По сути, вам нужно привязать событие onresize к своему телу. После того, как вы поймаете событие, вам просто нужно изменить размер холста, используя window.innerWidth и 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
источник
1
Вы можете просто использовать прослушиватель событий.
Дэвид Корбин
Это поля и показывает полосы прокрутки, плюс вы должны изменить размер экрана, прежде чем он что-то делает.
ArtOfWarfare
Что если холст больше, чем область просмотра (когда область просмотра становится уже или короче)? Это решение, похоже, не справляется с этим.
Ларс Гируп Бринк Нильсен
В оригинальных вопросах @ArtOfWarfare ничего не говорится о стилях. Но вы можете стилизовать его с помощью CSS и удалить поля и скрыть полосы прокрутки, если хотите. И вы просто можете добавить `<body onload =" resize_canvas () ">` затем при загрузке страницы, а затем изменить размер холста.
Эквиман
@LayZee оригинальный вопрос, скажем, масштабируем холст, чтобы он соответствовал странице , а не окну просмотра. Это может быть другой вопрос.
Эквиман
19

Установка ширины и высоты координатного полотна на основе размеров клиента браузера требует изменения размера и перерисовки при каждом изменении размера браузера.

Менее запутанное решение состоит в том, чтобы поддерживать прорисовываемые размеры в переменных Javascript, но устанавливать размеры холста на основе размеров screen.width, screen.height. Используйте CSS, чтобы соответствовать:

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

Окно браузера, как правило, никогда не будет больше, чем сам экран (за исключением случаев, когда разрешение экрана искажено, как это может быть при несовпадающих двойных мониторах), поэтому фон не будет отображаться и пропорции пикселей не будут меняться. Пиксели холста будут прямо пропорциональны разрешению экрана, если вы не используете CSS для масштабирования холста.

jerseyboy
источник
7
Масштабирование холста с помощью CSS проблематично. По крайней мере, в Chrome и Safari положения событий мыши / касания не будут соответствовать 1: 1 с позициями пикселей холста, и вам придется трансформировать системы координат.
Джерсибой
14

Чистый CSS подход добавление к раствору @jerseyboy выше.
Работает в Firefox (тестирование в v29), Chrome (тестирование в v34) и Internet Explorer (тестирование в 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>

Ссылка на пример: http://temporaer.net/open/so/140502_canvas-fit-to-window.html

Но будьте осторожны, как пишет @jerseyboy в своем комментарии:

Масштабирование холста с помощью CSS проблематично. По крайней мере, в Chrome и Safari положения событий мыши / касания не будут соответствовать 1: 1 с позициями пикселей холста, и вам придется трансформировать системы координат.

Фолькер Э.
источник
5
CSS-способ растягивает холст, поэтому растянутые изображения растягиваются. Это не хорошо по сравнению с изменением размеров холста. С небольшим изменением ответ Крэйга работает лучше всего.
Наян
Мне нравится это решение, так как это делает холст 100% на основе родительской ширины.
Майхан Ниджат
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
источник
Приятно, когда соотношение важно
саркирока
8

Если вы не хотите, чтобы холст автоматически масштабировал данные вашего изображения (об этом говорит ответ Джеймса Блэка, но он будет выглядеть не очень красиво), вам придется изменить его размер самостоятельно и перерисовать изображение. Центрирование холста

Nickolay
источник
4

Если ваш div полностью заполнил веб-страницу, то вы можете заполнить этот div и получить холст, который заполняет div.

Это может показаться вам интересным, так как вам может понадобиться использовать CSS для использования процентного соотношения, но это зависит от того, какой браузер вы используете, и насколько он соответствует спецификации: http://www.whatwg.org/ функции / веб-приложения / текущие работы / многостраничный / холст-element.html # холст-элемент

Внутренние размеры элемента canvas равны размеру координатного пространства, а числа интерпретируются в пикселях CSS. Тем не менее, размер элемента может быть изменен произвольно с помощью таблицы стилей. Во время рендеринга изображение масштабируется для соответствия размеру макета.

Вам может понадобиться получить offsetWidth и высоту div, или получить высоту / ширину окна и установить его в качестве значения пикселя.

Джеймс Блэк
источник
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();
});
Мартин Уитке
источник
3

Если вы заинтересованы в сохранении пропорций и в чистом CSS (учитывая соотношение сторон), вы можете сделать что-то вроде ниже. Ключ padding-bottomна ::contentэлемент , который изменяет размер containerэлемента. Это размер относительно ширины его родителя, который 100%по умолчанию. Указанное здесь соотношение должно совпадать с соотношением размеров canvasэлемента.

// 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
источник
2

Используя jQuery, вы можете отслеживать изменение размера окна и ширину холста, используя также jQuery.

Что-то такое

$( 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;">

Рафаэль Андраде
источник
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
источник
0

Я думаю, что именно это мы и должны делать: 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);
Арвинд Бхардвадж
источник
-2

Я использую sketch.js, поэтому после запуска команды init для canvas я изменяю ширину и высоту с помощью jquery. Размеры основываются на родительском элементе.

$ ( '# DrawCanvas'). Эскиз (). Attr ( 'высота', $ ( '# DrawCanvas'). Родитель (). Высота ()). Attr ( 'ширина', $ ( '# DrawCanvas'). Родитель () .width ());

moeiscool
источник