HTML5 Canvas - тени и градиентная заливка

183

До сих пор для рисования и заливки элементов на холсте мы использовали сплошные цвета. И хотя в этом определенно нет ничего предосудительного, артистические натуры будут рады узнать, что возможности холста не ограничиваются только сплошными цветами.

Одним из примеров такого оформления будет возможность любого элемента на холсте отбрасывать артистически оформленную тень. Другим примером будет заполнение фигуры узором повторяющихся изображений. Но почти наверняка самой изысканной возможностью рисования являются градиенты, посредством которых можно смешивать два или несколько цветов, создавая калейдоскопические узоры.

В последующих разделах мы научимся использовать эти возможности, просто устанавливая разные свойства контекста рисования холста.

Создание теней

Одной из полезных возможностей холста является добавление теней позади любого нарисованного изображения. Тени можно применять с одинаковым успехом с фигурами, изображениями и текстом. Одной из интересных особенностей является взаимодействие теней с изображениями с прозрачным фоном. Тени также хорошо сочетаются с текстом, позволяя создавать разнообразные эффекты, управляемые установкой соответствующих параметров.

По сути, тень — это размытая версия исходного изображения — линии, фигуры, изображения или текста. Внешний вид тени управляется установкой свойств контекста рисования (перечислены в таблице):

Свойства для управления внешним видом теней в элементе Canvas
Свойство Описание
shadowColor Устанавливает цвет тени. Можно установить черную или цветную тень, но обычно лучше всего делать ее полусерой. Другой хороший подход - использовать полупрозрачные тени, чтобы можно было видеть содержимое под ними. Отключить тени можно, присвоив атрибуту альфа свойства shadowColor нулевое значение
shadowBlur Устанавливает степень размытия теней. Нулевое значение этого свойства определяет четкую, резкую тень, выглядящую как силуэт исходного изображения. А значение 20 дает тень в виде размытой дымки, и можно установить еще большее значение. Большинство людей считает, что лучше всего выглядит слегка размытая тень (значение shadowBlur около 3)
shadowOffsetX и shadowOffsetY Определяют положение тени относительно содержимого, которому она принадлежит. Например, если присвоить каждому свойству значение 5, тень будет расположена на 5 пикселов вправо и 5 пикселов вниз от исходного содержимого. Отрицательные значения сдвигают тень в противоположном направлении — влево и вверх

Ниже показан пример использования теней:

// Определение контекста рисования
canvas = document.getElementById("drawingCanvas");
context = canvas.getContext("2d");
   
// Рисуем прямоугольник с тенью
context.rect(20, 20, 200, 100);
context.fillStyle = "#8ED6FF";
context.shadowColor = "#bbbbbb";
context.shadowBlur = 20;
context.shadowOffsetX = 15;
context.shadowOffsetY = 15;
context.fill();

// Рисуем три строчки текста с тенью
context.textBaseline = "top";
context.font = "bold 20px Arial";

context.shadowBlur = 3;
context.shadowOffsetX = 2;
context.shadowOffsetY = 2;
context.fillStyle = "steelblue";
context.fillText("Едва различимая, слегка старомодная тень.", 10, 175);

context.shadowBlur = 5;
context.shadowOffsetX = 20;
context.shadowOffsetY = 20;
context.fillStyle = "green";
context.fillText("Здесь используется \"далекая\" тень...", 10, 225);

context.shadowBlur = 15;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.shadowColor = "black";
context.fillStyle = "white";
context.fillText("Эта тень не смещена от исходного изображения и создает эффект ореола.", 10, 300);

// Рисуем звезду с тенью (загрузка из изображения)
context.shadowOffsetX = 10;
context.shadowOffsetY = 10;
context.shadowColor = "#bbbbbb";
context.shadowBlur = 4;

var img = new Image();
img.onload = function() {
	context.drawImage(img, 250, 30);
};
img.src = "http://professorweb.ru/downloads/star.png";
Разные виды теней в элементе Canvas

Заполнение фигур изображениями

Нарисованные на холсте фигуры можно заполнять не только сплошными или полупрозрачными цветами, но также градиентными цветами или узорами. Такие вычурные стили, несомненно, сделают простые фигуры более привлекательными. Такого рода оформление выполняется в два этапа: сначала создается заполнение, которое потом связывается со свойством fillStyle (или иногда со свойством strokeStyle).

Заполнение узором осуществляется путем множественной вставки копий одного исходного изображения вплотную друг к другу. Изображение, используемое в качестве исходной плитки, нужно загрузить в объект изображения. Имея объект изображения, можно создать объект шаблона, используя метод контекста createPattern(). На этом этапе указывается направление копирования плитки - горизонтально (repeat-x), вертикально (repeat-y) или в обоих направлениях (repeat). Последний шаг — присвоить созданный объект шаблона свойству контекста fillStyle или strokeStyle.

Ниже показан пример:

var img = new Image();
img.onload = function() {
    context.drawImage(img, 250, 30);
    var pattern = context.createPattern(img, "repeat");
    context.fillStyle = pattern; 
    context.rect(0, 0, canvas.width, canvas.height);
    context.fill();
};
img.src = "http://professorweb.ru/downloads/brick_tile.gif";

Этот код создает прямоугольник, который заполняет холст исходным изображением:

Узоры на Canvas

Градиентная заливка в Canvas

Другим типом заполнения является градиентное, в котором смешиваются два или более цветов. Холст поддерживает линейные и радиальные градиенты. Первым шагом в создании градиентной заливки будет создание правильного типа объекта градиента. Для решения этой задачи контекст рисования предоставляет два метода: createLinearGradient() и createRadialGradient(). Оба метода работают более-менее похоже: они содержат список цветов, которые задействуются в разных точках.

Самый легкий способ разобраться с градиентами — это изучить простой пример. В качестве такого примера рассмотрим код для создания градиента в сердцеобразной фигуре:

// Создаем градиент от точки (10,0) до точки (100,0)
var gradient = context.createLinearGradient(10, 0, 100, 0);

// Добавляем два цвета
gradient.addColorStop(0, "magenta");
gradient.addColorStop(1, "yellow");

// Вызываем функцию для рисования
drawHeart(60, 50);

// Рисуем фигуру
context.fillStyle = gradient;
context.fill();
context.stroke();
		
...
	 
// Вспомогательная функция для рисования фигуры в виде сердца
function drawHeart(x, y) {
		context.beginPath();
		context.moveTo(x, y);
		context.bezierCurveTo(x, y - 40, x - 45, y - 40, x - 48, y);
		context.bezierCurveTo(x - 45, y + 30, x, y + 40, x, y + 80);
		context.bezierCurveTo(x, y + 90, x + 45, y + 40, x + 45, y);
		context.bezierCurveTo(x + 45, y - 30, x, y - 30, x, y);
		context.closePath();
}
Линейный градиент Canvas

При создании линейного градиента указываются две точки, представляющие начало и конец пути, вдоль которого происходит изменение цвета. Важность линии градиента состоит в том, что она определяет внешний вид градиента.

Рассмотрим, например, линейный градиент, переходящий из светло-розового цвета в желтый. Этот переход можно выполнить в полосе шириной в несколько пикселов или же по всей ширине холста. Кроме этого, направление перехода может быть слева направо, сверху вниз или же с любым наклоном между этими двумя линиями. Все эти аспекты определяются линией градиента.

В данном примере линия градиента берет начало в точке (10, 0) и оканчивав в точке (100, 0). Эти точки предоставляют нам следующую важную информацию о данном градиенте:

Часто размер градиента будет лишь слегка больше заполняемой им фигуры, как в этом примере. Но возможны и другие варианты. Например, чтобы заполнить несколько фигур разными частями градиента, можно создать градиент, покрывающий весь холст.

Остановка цветов градиента осуществляется вызовами метода градиента addColorStop(). При каждом вызове метода ему передается значение смещения от 0 до 1, которое определяет местонахождение цвета в переходе. Значение 0 означает, что цвет находится в самом начале градиента, а значение 1 размещает цвет в конце. Изменив эти числа (например, на 0.2 и 0.8), мы можем сжать градиент, показывая большую область сплошного цвета на каждом конце.

Для двухцветного градиента наиболее логичными значениями смещения являются 0 и 1. Но для градиентов с большим количеством цветов можно устанавливать разные смещения, чтобы сжать одни цветовые полосы и растянуть другие.

Процесс создания радиального градиента такой же, как и линейного, только вместо определения двух точек нужно определить два круга. Это потому, что переход градиентов в радиальном градиенте распространяется с меньшего круга к большему. Эти круги определяются указанием их центра и радиуса.

Ниже показан пример, расширяющий предыдущий. В нем добавлен линейный градиент с несколькими цветами, а так же двухцветные и многоцветные радиальные градиенты:

// Двухцветный линейный градиент
var gradient = context.createLinearGradient(10, 0, 100, 0);
gradient.addColorStop(0, "magenta");
gradient.addColorStop(1, "yellow");

drawHeart(60, 50);
context.fillStyle = gradient;
context.fill();
context.stroke();

// Двухцветный радиальный градиент
gradient = context.createRadialGradient(180, 100, 10, 180, 100, 50);
gradient.addColorStop(0, "magenta");
gradient.addColorStop(1, "yellow"); 

drawHeart(180, 100);
context.fillStyle = gradient;
context.fill();
context.stroke();

// Многоцветный линейный градиент
gradient = context.createLinearGradient(10, 0, 100, 0);
gradient.addColorStop("0","magenta");
gradient.addColorStop(".25","blue");
gradient.addColorStop(".50","green");
gradient.addColorStop(".75","yellow");
gradient.addColorStop("1.0","red");

drawHeart(80, 180);
context.fillStyle = gradient;
context.fill();
context.stroke();

// Многоцветный радиальный градиент
gradient = context.createRadialGradient(180, 250, 10, 180, 250, 50);
gradient.addColorStop("0","magenta");
gradient.addColorStop(".25","blue");
gradient.addColorStop(".50","green");
gradient.addColorStop(".75","yellow");
gradient.addColorStop("1.0","red");

drawHeart(180, 230);
context.fillStyle = gradient;
context.fill();
context.stroke();
Линейные и радиальные градиенты Canvas

В правой верхней фигуре примера радиального градиента цветовой переход распространяется от центральной точки фигуры с координатами (180, 100). Внутренний цвет ограничен кругом радиусом 10 пикселов, а внешний — кругом радиусом 50 пикселов. Опять же, если выйти за эти пределы, мы получим сплошные цвета — светло-розовый в центре и желтый по внешней окружности.

Пройди тесты
Лучший чат для C# программистов