调整大小的画布 - 保持最大宽度或高度而不拉伸/填充 [英] Canvas on resize - keep a maximal width or height without stretching/padding

查看:170
本文介绍了调整大小的画布 - 保持最大宽度或高度而不拉伸/填充的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在javascript中使用canvas进行html5游戏的问题。



我希望播放器显示的画布包含1920的canvas.width,或者1080.of canvas.height,以便看不到填充。这意味着如果玩家用其他比例调整屏幕大小,我不想保持(最佳)游戏比例16/9,但我想保持视口比率16/9以避免拉伸(使用canvas.style。 ***)



让我举一个具有可调整大小的屏幕(window.innerWidth = 500和window.innerHeight = 1600)的播放器的示例,如1600/500> 1920/1080,我希望玩家可以看到游戏高度的1920和游戏高度小于1080,防止视口拉伸。



Agar.io是另一个很好的例子。



非常感谢你!

解决方案

要适应但如果方面不匹配,将在侧面或顶部底部留空区域。

  var scale = Math.min(innerWidth / canvas.width,innerHeight / canvas.height); 

或填充但如果方面不匹配则会剪辑画布

  var scale = Math.max(innerWidth / canvas.width,innerHeight / canvas.height); 

显示1600乘500和帆布1920乘1080

  1600/1920 = 0.8333; 
500/1080 = 0.463;

因此适合画布将 0.463 *(1920,1080)=( 889,500)边上是空的



并且填充画布将是 0.8333 *(1920,1080)=(1600, 900)剪裁顶部和底部。



有关比例和拟合的更多信息,请参见下文。



如果要缩放以填充画布,则需要考虑剪裁区域并找到画布左上角的偏移量(这将离开页面)。

  var leftOffset = 0; 
var topOffset = 0;
var canW = scale * canvas.width;
var canH = scale * canvas.height;
if(canW> innerWidth){
leftOffset =((canW - innerWidth)/ canW)* 1920/2;
}否则
如果(canH> innerHeight){
topOffset =((canH - innerHeight)/ canH)* 1080/2;
}

您的画布将填充页面innerWidth和innerHeight,但您需要抵消所有渲染。这可以通过将变换设置为正确的偏移来完成

  ctx.setTransform(1,0,0,1,-leftOffset ,-topOffset); 

画布显示尺寸为

  canvas.style.width = innerWidth +px; 
canvas.style.height = innerHeight +px;

并且画布分辨率将是

  canvas.width = 1920  - (leftOffset * 2); 
canvas.height = 1080 - (topOffset * 2);

以下是代码的实例。非常懒惰的编码,只是为了显示它的工作应该真的不能在调整大小时创建和销毁画布。另外



缩放以填充



表示图像缩放以便所有画布像素将被图像覆盖。如果图像方面与画布不同,则图像的某些部分将被剪裁。该示例显示缩放以填充的图像。请注意图像的顶部和底部是如何不再可见的。





示例缩放以适合



  var image = new Image(); 
image.src =imgURL;
image.onload = function(){
scaleToFit(this);
}

function scaleToFit(img){
//得到比例
var scale = Math.min(canvas.width / img.width,canvas.height / img.height);
//获取图像的左上角位置
var x =(canvas.width / 2) - (img.width / 2)* scale;
var y =(canvas.height / 2) - (img.height / 2)* scale;
ctx.drawImage(img,x,y,img.width * scale,img.height * scale);
}



示例缩放以填充



  var image = new Image(); 
image.src =imgURL;
image.onload = function(){
scaleToFill(this);
}

function scaleToFill(img){
//得到比例
var scale = Math.max(canvas.width / img.width,canvas.height / img.height);
//获取图像的左上角位置
var x =(canvas.width / 2) - (img.width / 2)* scale;
var y =(canvas.height / 2) - (img.height / 2)* scale;
ctx.drawImage(img,x,y,img.width * scale,img.height * scale);
}

这两个函数之间的唯一区别就是得到了比例。拟合使用最小拟合比例将填充使用最大拟合比例。


I have a question for a html5 game using canvas in javascript.

I would like that the canvas showed to the player contains either 1920 of canvas.width, either 1080 of canvas.height in order to not see the padding. That means that I don't want to keep the (optimal) game ratio 16/9 if the player resize his screen with an other ratio, but I want to keep the viewport ratio 16/9 to avoid stretching (using canvas.style.***)

Let me take an example of a player with a resizable screen (window.innerWidth = 500 and window.innerHeight = 1600), as 1600/500 > 1920 / 1080, I would like that the player can see 1920 of the game width and "less than 1080" of the game height, preventing viewport stretching.

Agar.io is an other good example.

Thank you very much !

解决方案

To fit but will leave empty areas on the sides or top bottom if aspects do not match.

var scale = Math.min(innerWidth / canvas.width, innerHeight / canvas.height);

or to fill but will clip canvas if aspects do not match

var scale = Math.max(innerWidth / canvas.width, innerHeight / canvas.height);

for display 1600 by 500 and canvas 1920 by 1080

1600 / 1920 = 0.8333;
500 / 1080 = 0.463;

thus to fit canvas will be 0.463 * (1920,1080) = (889,500) empty on sides

and to fill canvas will be 0.8333 * (1920,1080) = (1600,900) clipped top and bottom.

More info on scale and fit can be found below.

If you are scaling to fill the canvas you will need to account for the clipped area and find the offset to the top left corner of the canvas (this will be off the page).

var leftOffset = 0;
var topOffset = 0;
var canW = scale * canvas.width;
var canH = scale * canvas.height;
if(canW > innerWidth ){
    leftOffset = ((canW - innerWidth) / canW) * 1920 / 2;
}else
if(canH > innerHeight ){
    topOffset = ((canH - innerHeight) / canH) * 1080 / 2;
}

Your canvas will fill the page innerWidth and innerHeight but you will need to offset all rendering. This can be done by setting the transform to the correct offsets

ctx.setTransform(1,0,0,1,-leftOffset, -topOffset);

The canvas display size will be

canvas.style.width = innerWidth + "px"; 
canvas.style.height = innerHeight + "px";

and the canvas resolution will be

canvas.width = 1920 - (leftOffset * 2);
canvas.height = 1080 - (topOffset * 2);

Below is an example of the code in action. Very lazy coding, just to show it working should really not create and destroy canvas on resizes. Also as fiddle because it has resizable panels to test with.

 var canvas;
var createCanvas = function(){
    if(canvas !== undefined){
         document.body.removeChild(canvas);
    
    }
    var canWidth = 1920;
    var canHeight = 1080;

    var scale = Math.max(innerWidth /canWidth, innerHeight / canHeight);
    var leftOffset = 0;
    var topOffset = 0;
    var canW = scale * canWidth;
    var canH = scale * canHeight;
    if(canW > innerWidth ){
        leftOffset = ((canW - innerWidth) / canW) * canWidth / 2;
    }else
    if(canH > innerHeight ){
        topOffset = ((canH - innerHeight) / canH) * canHeight / 2;
    }

    canvas = document.createElement("canvas");
    canvas.style.position = "absolute";
    canvas.style.top = "0px";
    canvas.style.left = "0px";
    canvas.style.width = innerWidth + "px"; 
    canvas.style.height = innerHeight + "px";
    canvas.width = canWidth - (leftOffset * 2);
    canvas.height = canHeight - (topOffset * 2);
    document.body.appendChild(canvas);
    var ctx = canvas.getContext("2d");


    ctx.setTransform(1,0,0,1,-leftOffset, -topOffset);
    ctx.beginPath();
    ctx.arc(canWidth / 2, canHeight/2, 400,0,Math.PI * 2);
    ctx.stroke();
}

window.addEventListener('resize',createCanvas);
createCanvas();


Scaling to fit

Means that the whole image will be visible but there may be some empty space on the sides or top and bottom if the image is not the same aspect as the canvas. The example shows the image scaled to fit. The blue on the sides is due to the fact that the image is not the same aspect as the canvas.

Scaling to fill

Means that the image is scaled so that all the canvas pixels will be covered by the image. If the image aspect is not the same as the canvas then some parts of the image will be clipped. The example shows the image scaled to fill. Note how the top and bottom of the image are no longer visible.

Example Scale to fit

var image = new Image();
image.src = "imgURL";
image.onload = function(){
    scaleToFit(this);
}

function scaleToFit(img){
    // get the scale
    var scale = Math.min(canvas.width / img.width, canvas.height / img.height);
    // get the top left position of the image
    var x = (canvas.width / 2) - (img.width / 2) * scale;
    var y = (canvas.height / 2) - (img.height / 2) * scale;
    ctx.drawImage(img, x, y, img.width * scale, img.height * scale);
}

Example Scale to fill

var image = new Image();
image.src = "imgURL";
image.onload = function(){
    scaleToFill(this);
}

function scaleToFill(img){
    // get the scale
    var scale = Math.max(canvas.width / img.width, canvas.height / img.height);
    // get the top left position of the image
    var x = (canvas.width / 2) - (img.width / 2) * scale;
    var y = (canvas.height / 2) - (img.height / 2) * scale;
    ctx.drawImage(img, x, y, img.width * scale, img.height * scale);
}

The only differance between the two functions is getting the scale. The fit uses the min fitting scale will the fill uses the max fitting scale.

这篇关于调整大小的画布 - 保持最大宽度或高度而不拉伸/填充的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆