Полноэкранный режим и изменение размера
В предыдущем уроке мы разобрались с тем, как можно настроить пользовательские элементы управление, а так же разобрались со встроенными элементами управления three.js
. Если ты это пропустил, то советую вернуться!
Сейчас наш canvas
имеет фиксированный размер 600x600
. В этом уроке мы разберем с вами как настраивать его размер под экран пользователя, научимся делать так, чтобы он занимал все пространство и перестраивался при изменении размера окна, а так же узнаем как работает полноэкранный режим!
Код на начало урока вы можете найти ->тут<-
Запустив приложение вы должны увидеть следующее:
Подстраиваемся под viewport
Чтобы canvas
идеально помещался во viewport, вместо использования фиксированных чисел в переменной размеров используйте window.innerWidth
и window.innerHeight
:
// ... // Размеры const sizes = { width: window.innerWidth, height: window.innerHeight, }; // ...
Вы можете видеть, что canvas
теперь имеет ширину и высоту экрана. К сожалению, есть белое поле и полоса прокрутки (попробуйте прокрутить, если вы не видите никакой полосы прокрутки).
Проблема в том, что все браузеры имеют стили по умолчанию.
Наш script.js
уже связан с CSS-файлом в src/style.css.
Это может показаться странным, если вы не привыкли к Webpack
, но файл CSS импортируется непосредственно из script.js
:
import './style.css'
Хорошей вещью, которую нужно сделать в первую очередь, было бы удалить любой тип отступов для всех элементов, используя селектор *
:
* { margin: 0; padding: 0; }
Затем мы можем зафиксировать canvas
в левом верхнем углу, используя его класс canvas-js
:
.canvas-js { position: fixed; top: 0; left: 0; }
Вам не нужно указывать ширину или высоту canvas
, потому что Three.js
уже заботится об этом, когда вы вызываете метод renderer.setSize(...)
.
Можно еще исправить небольшую проблему нашего canvas
. Возможно, вы заметили синий контур на нем при перетаскивании. В основном это происходит в последних версиях Chrome. Чтобы исправить это, мы можем просто добавить outline: none;
на .canvas-js
:
.canvas-js { position: fixed; top: 0; left: 0; outline: none; }
А еще, если вы хотите удалить любой тип прокрутки даже на сенсорных экранах, вы можете добавить overflow: hidden
как в html
, так и в body
:
html, body { overflow: hidden; }
Теперь вы можете наслаждаться своим WebGL во всей его красе. К сожалению, если вы измените размер окна, canvas
не будет менять размер, и нам нужно с этим разобраться.
Обрабатываем изменение размера
Чтобы изменить размер canvas
, нам сначала нужно знать, когда изменяется размер окна. Для этого вы можете навесить на событие изменения размера окна колбек:
window.addEventListener('resize', () => { console.log('window has been resized'); });
Теперь, когда мы запускаем функцию при изменении размера окна, нам нужно кое-что обновить в нашем коде.
Во-первых, мы должны обновить переменную размеров:
window.addEventListener('resize', () => { // Обновляем размеры sizes.width = window.innerWidth; sizes.height = window.innerHeight; });
Во-вторых, мы должны обновить соотношение сторон камеры, изменив ее свойство aspect
:
window.addEventListener('resize', () => { // ... // Обновляем соотношение сторон камеры camera.aspect = sizes.width / sizes.height; });
Когда вы меняете свойства камеры, такие как aspect
, вам также необходимо обновить матрицу проекции с помощью camera.updateProjectionMatrix()
. Мы поговорим о матрицах позже:
window.addEventListener('resize', () => { // ... camera.updateProjectionMatrix(); });
Наконец, мы должны обновить renderer
. Обновление renderer
автоматически обновит ширину и высоту холста:
window.addEventListener('resize', () => { // ... // Обновляем renderer renderer.setSize(sizes.width, sizes.height); });
window.addEventListener('resize', () => { // Обновляем размеры sizes.width = window.innerWidth; sizes.height = window.innerHeight; // Обновляем соотношение сторон камеры camera.aspect = sizes.width / sizes.height; camera.updateProjectionMatrix(); // Обновляем renderer renderer.setSize(sizes.width, sizes.height); });
Теперь вы можете изменить размер окна по своему усмотрению, canvas
должен закрывать область просмотра без какой-либо полосы прокрутки или переполнения.
Соотношение пикселей
Некоторые из вас могут увидеть своего рода размытый рендеринг и артефакты в форме лестниц по краям (называемые сглаживанием. Если вы это видите, то это потому, что вы тестируете на экране с соотношением пикселей больше 1.
Соотношение пикселей соответствует тому, сколько физических пикселей у вас есть на экране на одну единицу пикселя в программной части.
Немного истории
Несколько лет назад все экраны имели соотношение пикселей 1, и все было просто отлично. Но когда вы внимательно смотрели на свой экран, вы могли видеть эти пиксели, и это было ограничением для того, насколько точными могли быть изображения и насколько тонкими могли быть шрифты.
Компания, которая сделала для этого больше всего, была Apple. Apple увидела возможность и начала создавать экраны с соотношением пикселей 2, называемые retina. Сейчас это делают многие конструкторы, и вы можете видеть экраны с еще более высоким соотношением пикселей.
Хотя это хорошо сказывается на качестве изображения, соотношение пикселей 2 означает, что для рендеринга требуется в 4 раза больше пикселей. А соотношение пикселей 3 означает, что для рендеринга требуется в 9 раз больше пикселей.
И знаешь что? Самое высокое соотношение пикселей обычно наблюдается на самых слабых устройствах — мобильных телефонах.
Обрабатывать соотношение пикселей
Чтобы получить соотношение пикселей экрана, вы можете использовать window.devicePixelRatio
, а чтобы обновить соотношение пикселей renderer
, вам просто нужно вызвать renderer.setPixelRatio(...)
У вас может возникнуть соблазн просто отправить соотношение пикселей устройства этому методу, но в конечном итоге у вас возникнут проблемы с производительностью на устройствах с высоким соотношением пикселей.
Иметь соотношение пикселей больше 2 - это в основном маркетинг. Ваши глаза почти не увидят разницы между 2 и 3, но это создаст проблемы с производительностью и быстрее разрядит аккумулятор. Что вы можете сделать, так это ограничить соотношение пикселей до 2. Чтобы сделать это, вы можете использовать Math.min()
:
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
Существуют методы получения уведомлений об изменении соотношения пикселей, но это касается только пользователей, имеющих несколько экранов с разным соотношением пикселей, и они обычно изменяют размер своего окна при переходе с одного экрана на другой. Вот почему мы просто добавим этот метод и в обратный вызов resize
:
window.addEventListener('resize', () => { // Обновляем размеры sizes.width = window.innerWidth; sizes.height = window.innerHeight; // Обновляем соотношение сторон камеры camera.aspect = sizes.width / sizes.height; camera.updateProjectionMatrix(); // Обновляем renderer renderer.setSize(sizes.width, sizes.height); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); });
Обрабатывать полноэкранный режим
Теперь, когда у нас есть canvas
, занимающий все доступное пространство с правильным соотношением пикселей, пришло время добавить поддержку полноэкранного режима.
Во-первых, нам нужно решить, какое действие вызовет полноэкранный режим. Это может быть кнопка HTML, но вместо этого мы собираемся использовать двойной щелчок.
Когда произойдет двойной щелчок, мы переключим полноэкранный режим — это означает, что если окно не находится в полноэкранном режиме, двойной щелчок включит полноэкранный режим, а если окно уже находится в полноэкранном режиме, двойной щелчок приведет к выходу из полноэкранного режима.
Для начала нам нужно обрабатывать событие двойного щелчка, и мы можем сделать это с помощью события dblclick
:
window.addEventListener('dblclick', () => { console.log('double click'); });
Это событие будет работать в большинстве современных браузеров, за исключением Chrome Android:
Теперь, когда у нас есть наш обработчик, нам нужно 3 вещи:
- Способ узнать, находится ли он уже в полноэкранном режиме
- Способ перехода в полноэкранный режим
- Способ выхода из полноэкранного режима
Чтобы узнать, находимся ли мы уже в полноэкранном режиме или нет, мы можем использовать document.fullscreenElement
:
window.addEventListener('dblclick', () => { if(!document.fullscreenElement) { console.log('открыть fullscreen'); } else { console.log('закрыть fullscreen'); } });
Метод запроса полноэкранного режима связан с элементом. Это потому, что вы можете выбрать, что будет отображаться в полноэкранном режиме. Это может быть целая страница, любой элемент DOM или canvas
.
Мы будем использовать canvas
и вызывать для него метод requestFullscreen()
:
window.addEventListener('dblclick', () => { if(!document.fullscreenElement) { canvas.requestFullscreen(); } else { console.log('закрыть fullscreen'); } });
Способ выхода из полноэкранного режима доступен непосредственно в документе:
window.addEventListener('dblclick', () => { if(!document.fullscreenElement) { canvas.requestFullscreen(); } else { document.exitFullscreen() } });
Вы можете проверить результат, дважды щелкнув в любом месте, чтобы переключить полноэкранный режим. К сожалению, это не будет работать в Safari этот браузер не торопится официально поддерживать простые функции, такие как полноэкранный режим, и нам нужно использовать версии с префиксами, чтобы заставить его работать для document.fullscreenElement
, canvas.requestFullscreen
и document.exitFullscreen
:
window.addEventListener('dblclick', () => { const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement; if(!fullscreenElement) { if(canvas.requestFullscreen) { canvas.requestFullscreen(); } else if(canvas.webkitRequestFullscreen) { canvas.webkitRequestFullscreen(); } } else { if(document.exitFullscreen) { document.exitFullscreen(); } else if(document.webkitExitFullscreen) { document.webkitExitFullscreen(); } } });
Все должно работать нормально во всех современных браузерах.
На этом сегодня все, надеюсь вам это было полезно!
🤖 Чтобы не пропустить новые уроки подпишись на телеграм канал!
🚀 Код для данного урока вы можете найти тут.