Canvas — популярный способ рисования всевозможной графики на экране и точка входа в мир WebGL. Его можно использовать для рисования фигур, изображений, запуска анимации или даже отображения и обработки видеоконтента. Его часто используют для создания красивого пользовательского опыта в мультимедийных веб-приложениях и онлайн-играх.
Он доступен для сценариев, что означает, что контент, нарисованный на холсте, может быть создан программно, например, на JavaScript. Это дает холсту большую гибкость.
В то же время на современных веб-сайтах выполнение скриптов является одним из наиболее частых источников проблем с реагированием пользователей . Поскольку логика холста и рендеринг происходят в том же потоке, что и взаимодействие с пользователем, (иногда тяжелые) вычисления, связанные с анимацией, могут нанести ущерб реальной и воспринимаемой производительности приложения.
К счастью, OffscreenCanvas является ответом на эту угрозу.
Раньше возможности рисования на холсте были привязаны к элементу <canvas>
, а это означало, что он напрямую зависел от DOM. OffscreenCanvas, как следует из названия, отделяет DOM и Canvas API, перемещая его за пределы экрана.
Благодаря этому отделению рендеринг OffscreenCanvas полностью отделен от DOM и, следовательно, обеспечивает некоторое повышение скорости по сравнению с обычным холстом, поскольку между ними нет синхронизации.
Более того, его можно использовать в Web Worker даже при отсутствии доступного DOM. Это позволяет реализовать всевозможные интересные варианты использования.
Используйте OffscreenCanvas в рабочем
Воркеры — это веб-версия потоков, позволяющая запускать задачи в фоновом режиме.
Перемещение части ваших сценариев в рабочий процесс дает вашему приложению больше возможностей для выполнения критически важных для пользователя задач в основном потоке. Без OffscreenCanvas не было возможности использовать Canvas API в воркере, так как не было доступного DOM.
OffscreenCanvas не зависит от DOM, поэтому его можно использовать. В следующем примере OffscreenCanvas используется для расчета цвета градиента в рабочем потоке:
// file: worker.js
function getGradientColor(percent) {
const canvas = new OffscreenCanvas(100, 1);
const ctx = canvas.getContext('2d');
const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1, 'blue');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, ctx.canvas.width, 1);
const imgd = ctx.getImageData(0, 0, ctx.canvas.width, 1);
const colors = imgd.data.slice(percent * 4, percent * 4 + 4);
return `rgba(${colors[0]}, ${colors[1]}, ${colors[2]}, ${colors[3]})`;
}
getGradientColor(40); // rgba(152, 0, 104, 255 )
Разблокировать основной поток
Перенос тяжелых вычислений в рабочий процесс позволяет освободить значительные ресурсы в основном потоке. Используйте метод TransferControlToOffscreen для зеркального отражения обычного холста в экземпляре OffscreenCanvas. Операции, примененные к OffscreenCanvas, будут автоматически отображаться на исходном холсте.
const offscreen = document.querySelector('canvas').transferControlToOffscreen();
const worker = new Worker('myworkerurl.js');
worker.postMessage({canvas: offscreen}, [offscreen]);
В следующем примере тяжелые вычисления происходят при изменении цветовой темы — это должно занять несколько миллисекунд даже на быстром рабочем столе. Вы можете запускать анимацию в основном потоке или в рабочем потоке. В случае с основным потоком вы не можете взаимодействовать с кнопкой во время выполнения тяжелой задачи — поток блокируется. В случае работника это не влияет на скорость реагирования пользовательского интерфейса.
Это работает и в обратную сторону: занятой основной поток не влияет на анимацию, выполняемую воркером. Вы можете использовать эту функцию, чтобы избежать визуальных зависаний и гарантировать плавную анимацию, несмотря на трафик основного потока, как показано в следующей демонстрации.
В случае обычного холста анимация останавливается, когда основной поток искусственно перегружается, в то время как OffscreenCanvas на основе воркера воспроизводится плавно.
Использование с популярными библиотеками
Поскольку API OffscreenCanvas обычно совместим с обычным элементом Canvas, вы можете использовать его в качестве прогрессивного улучшения, а также с некоторыми ведущими графическими библиотеками на рынке.
Например, вы можете обнаружить его и, если доступно, использовать с Three.js, указав параметр холста в конструкторе средства рендеринга:
const canvasEl = document.querySelector('canvas');
const canvas =
'OffscreenCanvas' in window
? canvasEl.transferControlToOffscreen()
: canvasEl;
canvas.style = {width: 0, height: 0};
const renderer = new THREE.WebGLRenderer({canvas: canvas});
Единственная ошибка здесь в том, что Three.js ожидает, что у холста будут свойства style.width
и style.height
. OffscreenCanvas, полностью отделенный от DOM, не имеет его, поэтому вам необходимо предоставить его самостоятельно, либо отключив его, либо предоставив логику, которая связывает эти значения с исходными размерами холста.
Ниже показано, как запустить базовую анимацию Three.js в воркере:
Имейте в виду, что некоторые API-интерфейсы, связанные с DOM, недоступны в воркере, поэтому, если вы хотите использовать более продвинутые функции Three.js, такие как текстуры, вам могут потребоваться дополнительные обходные пути. Некоторые идеи о том, как начать с ними экспериментировать, можно найти в видео с Google I/O 2017 .
Если вы активно используете графические возможности Canvas, OffscreenCanvas может положительно повлиять на производительность вашего приложения. Доступность контекстов рендеринга холста для работников увеличивает параллелизм в веб-приложениях и позволяет лучше использовать многоядерные системы.