Canvas on resize - сохранить максимальную ширину или высоту без растяжения / заполнения
У меня вопрос к html5-игре с использованием canvas в javascript.
Мне бы хотелось, чтобы показанный игроку холст содержал либо 1920 холстов. Ширины, либо 1080 холстов. Высоты, чтобы не видеть отступы. Это означает, что я не хочу сохранять (оптимальное) игровое соотношение 16/9, если игрок изменяет размер своего экрана с другим соотношением, но я хочу сохранить пропорцию окна просмотра 16/9, чтобы избежать растяжения (используя canvas.style.***)
Позвольте мне привести пример игрока с изменяемым размером экрана (window.innerWidth = 500 и window.innerHeight = 1600), при 1600/500 > 1920 / 1080, я хотел бы, чтобы игрок мог видеть 1920 ширины игры и " меньше чем 1080" высоты игры, предотвращая растяжение области просмотра.
Agar.io является еще одним хорошим примером.
Большое спасибо!
1 ответ
Подходит, но оставит пустые области по бокам или сверху внизу, если аспекты не совпадают.
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;
}else
if(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);
Ниже приведен пример кода в действии. Очень ленивое кодирование, просто чтобы показать, что оно работает, на самом деле не нужно создавать и уничтожать canvas при изменении размеров. Также как скрипка, потому что у него есть изменяемые размеры панелей для тестирования.
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();
Масштабирование, чтобы соответствовать
Означает, что все изображение будет видимым, но может быть некоторое пустое пространство по бокам или сверху и снизу, если изображение не совпадает с аспектом холста. В примере показано изображение, масштабированное для соответствия. Синий цвет по бокам связан с тем, что изображение отличается от холста.
Масштабирование для заполнения
Означает, что изображение масштабируется так, что все пиксели холста будут покрыты изображением. Если аспект изображения не совпадает с холстом, то некоторые части изображения будут обрезаны. В примере показано изображение, масштабированное для заполнения. Обратите внимание, что верх и низ изображения больше не видны.
Пример Масштаб, чтобы соответствовать
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);
}
Единственное различие между этими двумя функциями - получение шкалы. Подгонка использует минимальную шкалу подгонки, если заполнение использует максимальную шкалу подгонки.