Оптимизация canvas
Элемент <canvas> является одним из самых широко используемых инструментов для рендеринга 2D-графики в веб-приложениях. Однако, когда веб-сайты и приложения перегружают API Canvas, производительность начинает снижаться. Эта статья предоставляет рекомендации по оптимизации использования элемента canvas для обеспечения хорошей производительности графики.
Рекомендации по производительности
Ниже приведены рекомендации по улучшению производительности canvas.
Предварительный рендеринг похожих примитивов или повторяющихся объектов на оффскрин-canvas
Если вы обнаружили, что повторяете некоторые операции рисования в каждом кадре анимации, рассмотрите возможность использования оффскрин-canvas. Затем вы можете отобразить изображение оффскрин-canvas на главном canvas, сколько угодно раз, без необходимости повторять шаги, необходимые для его первоначального создания.
myCanvas.offscreenCanvas = document.createElement("canvas");
myCanvas.offscreenCanvas.width = myCanvas.width;
myCanvas.offscreenCanvas.height = myCanvas.height;
myCanvas.getContext("2d").drawImage(myCanvas.offScreenCanvas, 0, 0);
Избегайте координат с плавающей запятой и используйте целые числа
Субпиксельное рендеринг происходит, когда вы отображаете объекты на canvas без целых значений.
ctx.drawImage(myImage, 0.3, 0.5);
Это заставляет браузер выполнять дополнительные вычисления для создания эффекта сглаживания. Чтобы этого избежать, убедитесь, что все координаты, используемые в вызовах drawImage(), округляются с помощью Math.floor(), например.
Не масштабируйте изображения в drawImage
Кэшируйте различные размеры ваших изображений на оффскрин-canvas при загрузке, вместо постоянного масштабирования в drawImage().
Используйте несколько слоистых canvas для сложных сцен
В вашем приложении вы можете обнаружить, что некоторые объекты часто перемещаются или изменяются, в то время как другие остаются относительно статичными. Возможная оптимизация в этом случае — слоить элементы, используя несколько элементов <canvas>.
Например, предположим, что у вас игра с пользовательским интерфейсом сверху, игровым действием посередине и статичным фоном снизу. В этом случае вы можете разделить свою игру на три <canvas> слоя. Пользовательский интерфейс будет изменяться только при взаимодействии пользователя, слой игрового действия будет изменяться с каждым новым кадром, а фон останется в основном неизменным.
<div id="stage">
<canvas id="ui-layer" width="480" height="320"></canvas>
<canvas id="game-layer" width="480" height="320"></canvas>
<canvas id="background-layer" width="480" height="320"></canvas>
</div>
<style>
#stage {
width: 480px;
height: 320px;
position: relative;
border: 2px solid black;
}
canvas {
position: absolute;
}
#ui-layer {
z-index: 3;
}
#game-layer {
z-index: 2;
}
#background-layer {
z-index: 1;
}
</style>
Используйте обычный CSS для больших фоновых изображений
Если у вас есть статическое фоновое изображение, вы можете нарисовать его на обычный элемент <div> с помощью свойства CSS background и расположить его под canvas. Это исключит необходимость рендеринга фона на canvas на каждом такте.
Масштабирование canvas с помощью преобразований CSS
Преобразования CSS быстрее, так как используют GPU. Лучший вариант — не масштабировать canvas или использовать меньший canvas и масштабировать его, а не больший canvas и уменьшать его.
const scaleX = window.innerWidth / canvas.width;
const scaleY = window.innerHeight / canvas.height;
const scaleToFit = Math.min(scaleX, scaleY);
const scaleToCover = Math.max(scaleX, scaleY);
stage.style.transformOrigin = "0 0"; //scale from top left
stage.style.transform = `scale(${scaleToFit})`;
Отключить прозрачность
Если ваше приложение использует canvas и не требует прозрачного фона, установите параметр alpha в значение false при создании контекста рисования с помощью HTMLCanvasElement.getContext(). Эта информация может быть использована браузером для оптимизации рендеринга.
const ctx = canvas.getContext("2d", { alpha: false });
Масштабирование для дисплеев высокой разрешения
Вы можете заметить, что элементы canvas могут казаться размытыми на дисплеях с высоким разрешением. Хотя может быть много решений, простым первым шагом является одновременное увеличение и уменьшение размера canvas с использованием его атрибутов, стилей и масштабирования контекста.
// Get the DPR and size of the canvas
const dpr = window.devicePixelRatio;
const rect = canvas.getBoundingClientRect();
// Set the "actual" size of the canvas
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
// Scale the context to ensure correct drawing operations
ctx.scale(dpr, dpr);
// Set the "drawn" size of the canvas
canvas.style.width = `${rect.width}px`;
canvas.style.height = `${rect.height}px`;
Дополнительные рекомендации
- Объедините вызовы к канве в пакет. Например, нарисуйте полилинию вместо нескольких отдельных линий.
- Избегайте ненужных изменений состояния канвы.
- Отображайте только различия на экране, а не всё новое состояние.
- По возможности избегайте свойства
shadowBlur. - Избегайте отрисовки текста, когда это возможно.
- Попробуйте разные способы очистки канвы (
clearRect()противfillRect()или изменение размеров канвы). - При анимации используйте
Window.requestAnimationFrame()вместоsetInterval(). - Будьте осторожны с громоздкими библиотеками физики.
См. также
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas