调整画布大小-保持最大宽度或高度而不进行拉伸/填充

3

我有一个关于使用JavaScript中canvas的HTML5游戏的问题。

我希望玩家看到的canvas的宽度为1920或高度为1080,以避免出现padding。这意味着如果玩家调整屏幕的比例,则不想保持(最佳)游戏比例16/9,而是要保持视口比例16/9以避免拉伸(使用canvas.style. ***)。

让我举个例子,如果一个玩家有一个可调整大小的屏幕(window.innerWidth = 500和window.innerHeight = 1600),由于1600/500> 1920/1080,我希望玩家能看到1920的游戏宽度和“小于1080”的游戏高度,从而避免视口拉伸。

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

非常感谢!


所以如果我理解正确,您想要 此函数 的 "xMidYMid meet"? - Kaiido
你不能只使用CSS来填充空间,然后使用JS重新分配宽度和高度吗?https://jsfiddle.net/4rhdef0w/ - Domino
1个回答

3
适应大小但如果比例不匹配则会在侧面或顶部底部留下空白区域。
var scale = Math.min(innerWidth / canvas.width, innerHeight / canvas.height);

或者填充但如果宽高比不匹配则会剪切画布。
var scale = Math.max(innerWidth / canvas.width, innerHeight / canvas.height);

用于显示1600 x 500和画布1920 x 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;
}else
if(canH > innerHeight ){
    topOffset = ((canH - innerHeight) / canH) * 1080 / 2;
}

您的画布将填满页面的innerWidth和innerHeight,但您需要对所有渲染进行偏移。这可以通过设置变换来实现正确的偏移量。

ctx.setTransform(1,0,0,1,-leftOffset, -topOffset);
< p >画布显示尺寸将会是

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

画布的分辨率将会是

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

下面是代码示例。这是非常懒惰的编码,只是为了展示它的工作原理而创建和销毁画布。另外,还可以使用Fiddle进行测试,因为它具有可调整大小的面板。

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

缩放以适应

指整个图像将可见,但如果图像与画布的宽高比不同,则可能会在两侧或顶部和底部留有一些空白。下面的示例显示了缩放到适合画布的图像。两侧的蓝色是因为图像与画布的宽高比不同。

enter image description here

缩放以填充

意味着图像被缩放,以覆盖所有画布像素。如果图像宽高比与画布不同,则图像的某些部分将被裁剪。下面的示例显示了缩放以填充的图像。请注意,图像的顶部和底部现在不再可见。

enter image description here

示例:缩放以适应

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

缩放填充示例

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

这两个函数之间唯一的区别在于获取比例的方式。fit函数使用最小适配比例,而fill函数则使用最大适配比例。


谢谢!我已经成功地进行了“缩放以填充”,但现在我无法将图像居中(x,y)...你能帮助我吗? 以下是调整大小的实际代码:canvas.height = 1080;canvas.width = 1920;var scale = Math.max(window.innerWidth / canvas.width; window.innerHeight / canvas.height);canvas.style.width = 1920 * scale + "px";canvas.style.height = 1080 * scale + "px"; - zbeyens
@Miyud 好的,那是我脑海中想到的,我得测试一下。发现问题后会更新。 - Blindman67
你的答案适用于以下代码: canvas.style.width = 1920 * scale + "px"; canvas.style.height = 1080 * scale + "px"; 并保持 canvas.width = 1920; canvas.height = 1080;。非常感谢您的快速回复 :) - zbeyens
@Miyud 一切都好了..无法弄清楚问题出在哪里,因为fiddle是可以工作的..愉快编码。 - Blindman67
1
@androiddeveloper,你所说的“fit-center”被称为scaleToFit。这意味着图像尽可能大,并且可以看到所有像素。 - Blindman67
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接