Aspect ratio behaviour of <canvas> - internal dimensions and element size

时光毁灭记忆、已成空白 提交于 2019-12-11 03:22:49

问题


As you know, the <canvas> element in HTML5 has an internal size, set via elm.width and elm.height where elm is the DOM element.

The element within the DOM itself can have a different box size, set via CSS.

When the two differ, the browser automatically stretches the contents of the <canvas> to fit the content box size. Can this behaviour be adjusted without an extra element? Can it be set to something like background-size: contain so that it keeps the aspect ratio of the inner canvas size?

As far as I know, there is no standard way to do this, so webkit-specific hacks are also accepted. But if there is no way to do it at all, what's the most elegant to do it with a wrapper element (we all know that we can wrap the element and adjust it via JS on resize)?

The one solution I can think of is actually using background-size: contain and background: element() but this is Firefox-specific, and I am looking for a WebKit solution.

Side question, can a difference in element box and canvas internal sizes impact performance? If so, how much?


回答1:


Yes, there is a new CSS property called object-fit. This allow you to set the content to for example cover which will then force aspect ratio to be kept at the same time as filling the DOM box.

Simply add this rule to the canvas element:

canvas {
  object-fit: cover;
  }

Support

(Updated) It is (partially) supported in Safari, but not in IE. Opera Mini needs a -o- prefix.

Does not seem to work with WebGL canvas (or video) in Chrome likely related to these issues: issue #1, issue #2, issue #3.

As a fallback the size can be calculated manually. This can be used with drawImage. If drawImage is not an option it will require a wrapper element with overflow set to hidden to work.

Example

Both canvas' below are using the default bitmap size of 300x150. They are then stretched by defining CSS size 300x300 pixels.

Normally this would make the circle an oval. However, the canvas on the right will use the new object-fit rule set to cover, the bitmap will be scaled considering aspect ratio so we still get a circle, but of course we'll also loose some of the edges (as well as sharpness).

var ctx1 = document.getElementById("c1").getContext("2d");
var ctx2 = document.getElementById("c2").getContext("2d");

drawCircle(ctx1, 150, 75, 70);   // draw circle to stretched canvas 1
drawCircle(ctx2, 150, 75, 70);   // draw circle to object-fit/cover canvas 2

function drawCircle(ctx, x, y, r) {
  ctx.moveTo(x + r, y);
  ctx.arc(x, y, 70, 0 , 6.28);
  ctx.closePath();
  ctx.stroke();
}
#c1, #c2 {
    width:300px;
    height:300px;
    }
#c2 {
    -o-object-fit: cover;  /* for Opera Mini */
    object-fit: cover;     /* W3C version (incl. FF/webkit) */
    }
<canvas id="c1"></canvas><canvas id="c2"></canvas>


来源:https://stackoverflow.com/questions/30483874/aspect-ratio-behaviour-of-canvas-internal-dimensions-and-element-size

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!