В мире шейдеров, сеток и фильтров Canvas2D может вас не заинтересовать. Но так и должно быть! 30–40 % веб-страниц содержат элемент <canvas>
, а 98 % всех холстов используют контекст рендеринга Canvas2D. Canvas2D есть в машинах, холодильниках и в космосе (правда).
Следует признать, что API немного отстает от времени, когда дело доходит до современного 2D-рисования. К счастью, мы усердно работали над реализацией новых функций в Canvas2D, чтобы догнать CSS, оптимизировать эргономику и повысить производительность.
Часть 1: знакомство с CSS
В CSS есть несколько команд рисования, которых катастрофически не хватает в Canvas2D. В новом API мы добавили несколько наиболее востребованных функций:
Круглый прямоугольник
Скругленные прямоугольники: краеугольный камень Интернета, компьютеров и цивилизации.
А если серьезно, прямоугольники с закругленными углами чрезвычайно полезны: в качестве кнопок, облачков чата, миниатюр, речевых облачков и т. д. В Canvas2D всегда можно было сделать закругленный прямоугольник, но это было немного запутанно:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'magenta';
const top = 10;
const left = 10;
const width = 200;
const height = 100;
const radius = 20;
ctx.beginPath();
ctx.moveTo(left + radius, top);
ctx.lineTo(left + width - radius, top);
ctx.arcTo(left + width, top, left + width, top + radius, radius);
ctx.lineTo(left + width, top + height - radius);
ctx.arcTo(left + width, top + height, left + width - radius, top + height, radius);
ctx.lineTo(left + radius, top + height);
ctx.arcTo(left, top + height, left, top + height - radius, radius);
ctx.lineTo(left, top + radius);
ctx.arcTo(left, top, left + radius, top, radius);
ctx.stroke();
Все это было необходимо для скромного простого скругленного прямоугольника:
В новом API появился метод roundRect()
.
ctx.roundRect(upper, left, width, height, borderRadius);
Таким образом, вышеизложенное можно полностью заменить следующим:
ctx.roundRect(10, 10, 200, 100, 20);
Метод ctx.roundRect()
также принимает массив для аргумента borderRadius
, содержащий до четырех чисел. Эти радиусы управляют четырьмя углами скругленного прямоугольника так же , как и в CSS . Например:
ctx.roundRect(10, 10, 200, 100, [15, 50, 30]);
Посмотрите демо-версию, чтобы поиграть !
Конический градиент
Вы видели линейные градиенты:
const gradient = ctx.createLinearGradient(0, 0, 200, 100);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(0.5, 'magenta');
gradient.addColorStop(1, 'white');
ctx.fillStyle = gradient;
ctx.fillRect(10, 10, 200, 100);
Радиальные градиенты:
const radialGradient = ctx.createRadialGradient(150, 75, 10, 150, 75, 70);
radialGradient.addColorStop(0, 'white');
radialGradient.addColorStop(0.5, 'magenta');
radialGradient.addColorStop(1, 'lightblue');
ctx.fillStyle = radialGradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
А как насчет красивого конического градиента?
const grad = ctx.createConicGradient(0, 100, 100);
grad.addColorStop(0, 'red');
grad.addColorStop(0.25, 'orange');
grad.addColorStop(0.5, 'yellow');
grad.addColorStop(0.75, 'green');
grad.addColorStop(1, 'blue');
ctx.fillStyle = grad;
ctx.fillRect(0, 0, 200, 200);
Модификаторы текста
Возможности рендеринга текста Canvas2D сильно отстают. Chrome добавил несколько новых атрибутов в рендеринг текста Canvas2D:
- ctx. письмоИнтервал
- ctx. wordSpacing
- ctx. шрифтВариант
- ctx. Шрифт Кернинг
- ctx. шрифтРастянуть
- ctx. текстУкрашение
- ctx. текстПодчеркиваниеПозиция
- ctx. textРендеринг
Все эти атрибуты соответствуют своим аналогам CSS с такими же именами.
Часть 2: эргономические настройки
Раньше некоторые вещи с Canvas2D были возможны, но их реализация была неоправданно сложной. Вот некоторые улучшения качества жизни для разработчиков JavaScript, которые хотят использовать Canvas2D:
Сброс контекста
Чтобы объяснить очистку холста, я написал небольшую глупую функцию для рисования ретро-узора :
draw90sPattern();
Большой! Теперь, когда я закончил с этим узором, я хочу очистить холст и нарисовать что-нибудь еще. Подождите, а как нам снова очистить холст? Ах, да! ctx.clearRect()
, конечно.
ctx.clearRect(0, 0, canvas.width, canvas.height);
Ха… это не сработало. Ах, да! Сначала мне нужно сбросить преобразование:
ctx.resetTransform();
ctx.clearRect(0, 0, canvas.width, canvas.height);
Идеальный! Красивый чистый холст. Теперь давайте начнем рисовать красивую горизонтальную линию:
ctx.moveTo(10, 10);
ctx.lineTo(canvas.width, 10);
ctx.stroke();
Грррр! Это неправильно! 😡 Что здесь делает эта дополнительная строка? И еще, почему он розовый? Хорошо, давайте просто проверим StackOverflow.
canvas.width = canvas.width;
Почему это так глупо? Почему это так сложно?
Ну, это уже не так. С новым API мы получили простое, элегантное и красивое новаторское решение:
ctx.reset();
Извините, что это заняло так много времени.
Фильтры
SVG-фильтры — это отдельный мир. Если они для вас новы, я настоятельно рекомендую прочитать «Искусство фильтров SVG и почему это круто» , где показан их удивительный потенциал.
Фильтры в стиле SVG уже доступны для Canvas2D! Вам просто нужно быть готовым передать фильтр как URL-адрес, указывающий на другой элемент фильтра SVG на странице:
<svg>
<defs>
<filter id="svgFilter">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" />
<feConvolveMatrix kernelMatrix="-3 0 0 0 0.5 0 0 0 3" />
<feColorMatrix type="hueRotate" values="90" />
</filter>
</defs>
</svg>
const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 400;
const ctx = canvas.getContext('2d');
document.body.appendChild(canvas);
ctx.filter = "url('#svgFilter')";
draw90sPattern(ctx);
Это довольно сильно портит наш шаблон:
Но что, если вы хотите сделать все вышеперечисленное, но оставаться в рамках JavaScript и не возиться со строками? С новым API это вполне возможно.
ctx.filter = new CanvasFilter([
{ filter: 'gaussianBlur', stdDeviation: 5 },
{
filter: 'convolveMatrix',
kernelMatrix: [
[-3, 0, 0],
[0, 0.5, 0],
[0, 0, 3],
],
},
{ filter: 'colorMatrix', type: 'hueRotate', values: 90 },
]);
Легко как пирог! Попробуйте и поиграйте с параметрами в демо-версии здесь .
Часть 3: улучшение производительности
С помощью нового API Canvas2D мы также хотели повысить производительность, где это возможно. Мы добавили пару функций, чтобы дать разработчикам более детальный контроль над своими веб-сайтами и обеспечить максимально низкую частоту кадров:
Буду часто читать
Используйте getImageData()
для чтения данных пикселей обратно с холста. Это может быть очень медленно. Новый API дает вам возможность явно пометить холст для обратного чтения (например, для генеративных эффектов). Это позволяет вам оптимизировать внутренние процессы и поддерживать скорость холста для более широкого спектра вариантов использования. Эта функция уже давно присутствует в Firefox, и мы наконец-то сделали ее частью спецификации Canvas.
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
Потеря контекста
Давайте снова сделаем грустные вкладки счастливыми! В случае, если у клиента закончится память графического процессора или с вашим холстом произойдет какая-то другая катастрофа, теперь вы можете получить обратный вызов и перерисовать по мере необходимости:
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.addEventListener('contextlost', onContextLost);
canvas.addEventListener('contextrestored', redraw);
Если вы хотите узнать больше о контексте и потерях холста, у WHATWG есть хорошее объяснение в их вики.
Заключение
Независимо от того, являетесь ли вы новичком в Canvas2D, используете его уже много лет или избегаете его использования в течение многих лет, я здесь, чтобы посоветовать вам взглянуть на Canvas по-новому. Это соседний API, который существовал всегда.