Canvas 调整大小 - 在没有 stretching/padding 的情况下保持最大宽度或高度
Canvas on resize - keep a maximal width or height without stretching/padding
我有一个 html5 游戏在 javascript 中使用 canvas 的问题。
我希望显示给玩家的 canvas 包含 canvas.width 的 1920,或 canvas.height 的 1080,以便看不到填充。这意味着如果玩家以其他比例调整屏幕大小,我不想保持(最佳)游戏比例 16/9,但我想保持视口比例 16/9 以避免拉伸(使用 canvas.style.***)
让我举一个可调整屏幕大小的播放器的例子(window.innerWidth = 500 和 window.innerHeight = 1600),因为 1600/500 > 1920 / 1080,我希望播放器可以看到 1920 的游戏宽度和 "less than 1080" 的游戏高度,防止视口拉伸。
Agar.io 是另一个很好的例子。
非常感谢!
适合,但如果方面不匹配,将在两侧或顶部底部留下空白区域。
var scale = Math.min(innerWidth / canvas.width, innerHeight / canvas.height);
或填充,但如果方面不匹配
,将剪辑 canvas
var scale = Math.max(innerWidth / canvas.width, innerHeight / canvas.height);
显示 1600 x 500 和 canvas 1920 x 1080
1600 / 1920 = 0.8333;
500 / 1080 = 0.463;
因此 canvas 将 0.463 * (1920,1080) = (889,500)
两边空着
并填充 canvas 将 0.8333 * (1920,1080) = (1600,900)
剪裁顶部和底部。
可以在下面找到有关比例和适合度的更多信息。
如果要缩放以填充 canvas,则需要考虑裁剪区域并找到 canvas 左上角的偏移量(这将在页面之外) .
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;
}
您的 canvas 将填充页面的 innerWidth 和 innerHeight,但您需要偏移所有渲染。这可以通过将转换设置为正确的偏移量来完成
ctx.setTransform(1,0,0,1,-leftOffset, -topOffset);
canvas 显示大小将为
canvas.style.width = innerWidth + "px";
canvas.style.height = innerHeight + "px";
并且 canvas 分辨率将为
canvas.width = 1920 - (leftOffset * 2);
canvas.height = 1080 - (topOffset * 2);
下面是代码的一个例子。非常懒惰的编码,只是为了表明它的工作真的不应该在调整大小时创建和销毁 canvas。也 as 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();
缩放以适应
意味着整个图像将可见,但如果图像与 canvas 的纵横比不同,则两侧或顶部和底部可能会有一些空白 space。该示例显示了缩放以适合的图像。侧面的蓝色是因为图像与 canvas.
的纵横比不同
缩放以填充
表示图像被缩放,因此所有 canvas 像素都将被图像覆盖。如果图像方面与 canvas 不同,则图像的某些部分将被剪裁。该示例显示了缩放以填充的图像。请注意图像的顶部和底部不再可见。
示例比例适合
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);
}
这两个函数之间的唯一区别是获取比例。拟合使用最小拟合比例,填充使用最大拟合比例。
我有一个 html5 游戏在 javascript 中使用 canvas 的问题。
我希望显示给玩家的 canvas 包含 canvas.width 的 1920,或 canvas.height 的 1080,以便看不到填充。这意味着如果玩家以其他比例调整屏幕大小,我不想保持(最佳)游戏比例 16/9,但我想保持视口比例 16/9 以避免拉伸(使用 canvas.style.***)
让我举一个可调整屏幕大小的播放器的例子(window.innerWidth = 500 和 window.innerHeight = 1600),因为 1600/500 > 1920 / 1080,我希望播放器可以看到 1920 的游戏宽度和 "less than 1080" 的游戏高度,防止视口拉伸。
Agar.io 是另一个很好的例子。
非常感谢!
适合,但如果方面不匹配,将在两侧或顶部底部留下空白区域。
var scale = Math.min(innerWidth / canvas.width, innerHeight / canvas.height);
或填充,但如果方面不匹配
,将剪辑 canvasvar scale = Math.max(innerWidth / canvas.width, innerHeight / canvas.height);
显示 1600 x 500 和 canvas 1920 x 1080
1600 / 1920 = 0.8333;
500 / 1080 = 0.463;
因此 canvas 将 0.463 * (1920,1080) = (889,500)
两边空着
并填充 canvas 将 0.8333 * (1920,1080) = (1600,900)
剪裁顶部和底部。
可以在下面找到有关比例和适合度的更多信息。
如果要缩放以填充 canvas,则需要考虑裁剪区域并找到 canvas 左上角的偏移量(这将在页面之外) .
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;
}
您的 canvas 将填充页面的 innerWidth 和 innerHeight,但您需要偏移所有渲染。这可以通过将转换设置为正确的偏移量来完成
ctx.setTransform(1,0,0,1,-leftOffset, -topOffset);
canvas 显示大小将为
canvas.style.width = innerWidth + "px";
canvas.style.height = innerHeight + "px";
并且 canvas 分辨率将为
canvas.width = 1920 - (leftOffset * 2);
canvas.height = 1080 - (topOffset * 2);
下面是代码的一个例子。非常懒惰的编码,只是为了表明它的工作真的不应该在调整大小时创建和销毁 canvas。也 as 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();
缩放以适应
意味着整个图像将可见,但如果图像与 canvas 的纵横比不同,则两侧或顶部和底部可能会有一些空白 space。该示例显示了缩放以适合的图像。侧面的蓝色是因为图像与 canvas.
的纵横比不同缩放以填充
表示图像被缩放,因此所有 canvas 像素都将被图像覆盖。如果图像方面与 canvas 不同,则图像的某些部分将被剪裁。该示例显示了缩放以填充的图像。请注意图像的顶部和底部不再可见。
示例比例适合
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);
}
这两个函数之间的唯一区别是获取比例。拟合使用最小拟合比例,填充使用最大拟合比例。