【问题标题】:Resize HTML5 canvas to fit window调整 HTML5 画布大小以适应窗口
【发布时间】:2010-12-12 11:53:31
【问题描述】:

如何自动缩放 HTML5 <canvas> 元素以适应页面?

例如,我可以通过将 height 和 width 属性设置为 100% 来缩放 <div>,但 <canvas> 不会缩放,对吗?

【问题讨论】:

  • 为什么 canvas{width:100%;height:100%} 不起作用?
  • @zloctb - 这将直接放大画布,从而拉伸您的图像。
  • 请参阅WebGL Fundamentals,了解有关相关问题的详细说明。
  • 画布也可以很好地缩放,只需添加 css {width:100%},但它的内容不会,这完全是另一回事!

标签: javascript html html5-canvas


【解决方案1】:

以下解决方案最适合我。由于我对编码比较陌生,因此我喜欢通过视觉确认某些东西正在按我期望的方式工作。我在以下站点找到了它: http://htmlcheats.com/html/resize-the-html5-canvas-dyamically/

代码如下:

(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();
  }
})();
html,
body {
  width: 100%;
  height: 100%;
  margin: 0px;
  border: 0;
  overflow: hidden;
  /*  Disable scrollbars */
  display: block;
  /* No floating content on sides */
}
<canvas id='c' style='position:absolute; left:0px; top:0px;'></canvas>

蓝色边框向您显示调整大小画布的边缘,并且始终沿着窗口的边缘,在所有 4 个面上都可见,而上述其他一些答案并非如此。希望对您有所帮助。

【讨论】:

  • 这个答案解决了我的问题。 overflow: hidden 和 display: block 是让我正常工作所缺少的。
  • 链接失效
  • 这不起作用。它拉伸画布内容。
  • @Xan-KunClark-Davis 125% 通常与设备像素分辨率调整有关。基本上,如果您使用的是高像素密度设备,字体会显得比它应该的要小......所以它会放大以使字体正常大小。据我了解。您可以使用以下命令检查显示:window.devicePixelRatio。普通设备是 1,高 DPR 通常是 1.25。
  • @DoomGoober 确认!相关设备上的 window.devicePixelRatio 为 1.5625。
【解决方案2】:

设置初始大小。

const canvas = document.getElementById('canvas');

canvas.width  = window.innerWidth;
canvas.height = window.innerHeight;

在调整窗口大小时更新大小。

function windowResize() {
  canvas.width  = window.innerWidth;
  canvas.height = window.innerHeight;
};

window.addEventListener('resize', windowResize);

【讨论】:

  • 很好,这值得多一点爱。调整大小功能的道具。
  • 适用于 SignaturePad.JS。谢谢。
【解决方案3】:

这对我有用。 伪代码:

// screen width and height
scr = {w:document.documentElement.clientWidth,h:document.documentElement.clientHeight}
canvas.width = scr.w
canvas.height = scr.h

另外,正如 devyn 所说,您可以将“document.documentElement.client”替换为“inner”的宽度和高度:

**document.documentElement.client**Width
**inner**Width
**document.documentElement.client**Height
**inner**Height

它仍然有效。

【讨论】:

    【解决方案4】:

    这是一个包含所有答案的小而完整的代码片段。按:“运行代码片段”,然后按“整页”并调整窗口大小以查看它的实际效果:

    function refresh(referenceWidth, referenceHeight, drawFunction) {
      const myCanvas = document.getElementById("myCanvas");
      myCanvas.width = myCanvas.clientWidth;
      myCanvas.height = myCanvas.clientHeight;
    
      const ratio = Math.min(
        myCanvas.width / referenceWidth,
        myCanvas.height / referenceHeight
      );
      const ctx = myCanvas.getContext("2d");
      ctx.scale(ratio, ratio);
    
      drawFunction(ctx, ratio);
      window.requestAnimationFrame(() => {
        refresh(referenceWidth, referenceHeight, drawFunction);
      });
    }
    
    //100, 100 is the "reference" size. Choose whatever you want.
    refresh(100, 100, (ctx, ratio) => {
      //Custom drawing code! Draw whatever you want here.
      const referenceLineWidth = 1;
      ctx.lineWidth = referenceLineWidth / ratio;
      ctx.beginPath();
      ctx.strokeStyle = "blue";
      ctx.arc(50, 50, 49, 0, 2 * Math.PI);
      ctx.stroke();
    });
    div {
      width: 90vw;
      height: 90vh;
    }
    
    canvas {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }
    <div>
      <canvas id="myCanvas"></canvas>
    </div>

    这个 sn-p 使用 canvas.clientWidth 和 canvas.clientHeight 而不是 window.innerWidth 和 window.innerHeight 使 sn-p 在复杂布局中正确运行。但是,如果您只是将它放在使用全窗口的 div 中,它也适用于全窗口。这种方式更灵活。

    sn-p 使用新的 window.requestAnimationFrame 每帧重复调整画布大小。如果您不能使用它,请改用 setTimeout。而且,这是低效的。为了更高效,存储clientWidth和clientHeight,只有在clientWidth和clientHeight发生变化时才重新计算和重绘。

    “参考”分辨率的概念让您可以使用一种分辨率编写所有绘图命令......它会自动调整到客户端大小,而无需更改绘图代码。

    sn-p 是不言自明的,但如果您更喜欢用英文解释:https://medium.com/@doomgoober/resizing-canvas-vector-graphics-without-aliasing-7a1f9e684e4d

    【讨论】:

      【解决方案5】:

      我相信我已经找到了一个优雅的解决方案:

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

      到目前为止,对我的性能没有任何大的负面影响。

      【讨论】:

      • 您可能必须使用body, html { margin: 0px;} 禁用边距
      • 这比收听resize事件更可取吗?
      • @Elisabeth:要摆脱滚动条,请在 html 和 body 元素的样式中添加“溢出:隐藏”。见thefutureoftheweb.com/blog/100-percent-height-interface
      • 我这样做了,另外我还将画布设置为 display: block (它似乎默认为 display: inline ,它正在创建额外的空间!)。
      • 这可能是一种反模式;原因和补救措施见the third item here。
      【解决方案6】:

      使用 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;">

      【讨论】:

        【解决方案7】:

        一种纯 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 对应 画布像素位置,您必须转换坐标 系统。

        【讨论】:

        • CSS 方式拉伸画布,因此渲染的图像被拉伸。与调整画布大小相比,这并不好。只需稍加调整,克雷格的答案效果最佳。
        • 我喜欢这个解决方案,因为它使画布 100% 基于父宽度。
        【解决方案8】:

        如果您有兴趣保留纵横比并在纯 CSS 中这样做(给定纵横比),您可以执行以下操作。关键是 ::content 元素上的 padding-bottom 调整 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>

        【讨论】:

          【解决方案9】:

          我使用的是sketch.js,所以在为画布运行init 命令后,我使用jquery 更改了宽度和高度。它基于父元素的尺寸。

          $('#DrawCanvas').sketch().attr('height',$('#DrawCanvas').parent().height()).attr('width',$('#DrawCanvas' ).parent().width());

          【讨论】:

            【解决方案10】:

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

            【讨论】:

              【解决方案11】:
              (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();
                  });
              
              }());
              

              【讨论】:

                【解决方案12】:

                我认为这正是我们应该做的: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);
                

                【讨论】:

                  【解决方案13】:
                  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);
                  

                  【讨论】:

                  • 很好,当比率很重要时
                  【解决方案14】:

                  根据浏览器客户端的尺寸设置画布坐标空间的宽度和高度要求您在调整浏览器大小时调整大小并重绘。

                  一个不那么复杂的解决方案是在 Javascript 变量中维护可绘制尺寸,但根据 screen.width、screen.height 尺寸设置画布尺寸。使用 CSS 来适应:

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

                  浏览器窗口通常不会比屏幕本身大(除非屏幕分辨率被误报,因为它可能会出现在不匹配的双显示器上),因此不会显示背景并且不会显示像素比例'变化。除非您使用 CSS 来缩放画布,否则画布像素将与屏幕分辨率成正比。

                  【讨论】:

                  • 用 CSS 重新缩放画布很麻烦。至少在 Chrome 和 Safari 上,鼠标/触摸事件位置不会与画布像素位置 1:1 对应,您必须转换坐标系。
                  【解决方案15】:

                  基本上你要做的就是将 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>
                  

                  【讨论】:

                  • 你可以只使用事件监听器。
                  • 这有边距并显示滚动条,而且你必须在它做任何事情之前调整屏幕大小。
                  • 如果画布比视口大怎么办(当视口变窄或变短时)?此解决方案似乎无法处理。
                  • @ArtOfWarfare 原始问题没有提及任何关于样式的内容。但是您可以使用 css 对其进行样式化,并根据需要删除边距并隐藏滚动条。您只需添加``,然后在页面加载时调整画布大小。
                  • @LayZee 原始问题说缩放画布以适应页面,而不是视口。这可能是另一个问题。
                  【解决方案16】:

                  除非您希望画布自动放大您的图像数据(这就是 James Black 的回答所说的,但它看起来并不漂亮),否则您必须自己调整它的大小并重新绘制图像。 Centering a canvas

                  【讨论】:

                    【解决方案17】:

                    如果你的 div 完全填满了网页,那么你可以填满那个 div,这样就有一个可以填满 div 的画布。

                    您可能会觉得这很有趣,因为您可能需要使用 css 来使用百分比,但这取决于您使用的浏览器,以及它与规范的一致程度: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#the-canvas-element

                    画布的内在尺寸 元素的大小等于 坐标空间,带有数字 以 CSS 像素解释。然而, 元素可以任意调整大小 通过样式表。在渲染过程中, 图像被缩放以适合此布局 大小。

                    您可能需要获取 div 的 offsetWidth 和高度,或者获取窗口高度/宽度并将其设置为像素值。

                    【讨论】:

                      猜你喜欢
                      • 2013-10-06
                      • 2014-11-04
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-07-04
                      • 2020-06-07
                      • 1970-01-01
                      • 2021-04-06
                      相关资源
                      最近更新 更多