Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Web Development
Code

Изучаем Canvas с нуля: Трансформации и Градиенты

by
Difficulty:BeginnerLength:LongLanguages:
This post is part of a series called Canvas From Scratch.
Canvas From Scratch: Advanced Drawing
Canvas From Scratch: Pixel Manipulation

Russian (Pусский) translation by AlexBioJS (you can also view the original English article)

В данном руководстве мы рассмотрим трансформации (*  процесс, преобразующий координаты из одной системы в другую посредством пересчета (translation), вращений (rotation) и масштабирования (scaling). Тут и далее примеч. пер.) на холсте, а также тени и градиенты. Трансформации чрезвычайно полезный набор методов, который способствует пробуждению креативности у нас при прорисовывании объектов на холсте. И после этого краткого вступления давайте начнем!


Подготавливаем страницу

Вы будете использовать тот же самый шаблон HTML, что и в предыдущем руководстве, поэтому откройте свой любимый редактор и вставьте туда следующий код:

Это всего лишь базовая HTML-страница с элементом canvas и некоторым кодом JavaScript, который выполняется после загрузки DOM (* Document Object Model – Объектная модель документа). Ничего фантастического тут нет.


Пересчет в действии

При помощи пересчета по сути смещается вся система координат.

Одна из наиболее простых трансформаций на холсте – translate. Она позволяет вам переместить точку отсчета 2-мерного контекста отображения – координаты (0, 0) холста. Давайте проиллюстрирую, что это значит.

Вначале разместите квадрат на холсте в координатах (0, 0):

За счет этого кода будет прорисован квадрат в левом верхнем углу холста. По-прежнему у нас нет тут ничего фантастического.

A simple square

Теперь давайте попробуем выполнить пересчет 2-мерного контекста отображения и нарисовать другой квадрат в той же самой позиции:

Как думаете, что произойдет? Получите медальку те, кто отгадал, что будет прорисован новый квадрат в координатах (100, 100). Некогда играться с теми, кто не угадал. Без обид!

Translating a square

Так что же тут происходит? Сразу после добавления кода, необходимого для прорисовывания второго квадрата, вы прорисовали его в том же месте, как и первый. Это так, поскольку вы по сути смещаете всю систему координат холста таким образом, что ее координаты (0, 0) теперь располагается в координатах (100, 100).

How translation works

Теперь вам стало понятнее? Надеюсь, что да. Может потребоваться некоторое время на то, чтобы вы поняли эту концепцию, однако она проста, как только вы ее поняли.

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

Давайте рассмотрим следующую трансформацию в нашем списке.


Масштабируем наши элементы

Как вы уже, скорее всего, догадались, трансформация scale используется для изменения размеров объектов. Точнее, трансформация scale используется для изменения масштабов 2-мерного контекста отображения.

Уберите код, с которым работали в примере с translate, и добавьте следующий:

За счет него будет прорисован обычный квадрат в координатах (100, 100) с шириной/высотой 100 пикселей.  Итак, как изменить его масштаб?

A simple square

Аргументы метода scale являются множителями размеров контекста по осям x и y.

Трансформация scale используется подобно translate, в том смысле, что она выполняется до того, как вы прорисуете объекты, к которым вы хотели бы ее применить. Важно подчеркнуть, что аргументы метода scale являются множителями размеров контекста по осям x и y. Это означает, что при масштабе (1, 1) размер 2-мерного контекста отображения был бы помножен на 1, оставляя тот же размер контекста. При масштабе (5, 5) размер 2-мерного контекста отображения был бы помножен на 5, в результате чего размер контекста увеличился бы в 5 раз по сравнению с первоначальным. Все просто.

В нашем случае мы хотим увеличить размер квадрата в два раза, так что мы применяем масштаб (5, 5).

В результате чего получаем  квадрат, который больше предыдущего в два раза.

Scaling a square

Однако, обратите внимание на то, что квадрат был теперь прорисован в иной позиции, чем до применения scale. Причина в том, что при использовании scale происходит перемножение размера всего, что находится в 2-мерном контексте отображения, включая координаты. В нашем случае координаты (100, 100) меняются на (200, 200); значения координат теперь увеличились в два раза по сравнению с тем, какими бы они были без применения масштабирования.

Чтобы это поправить, мы можем выполнить трансформацию translate, при которой точка отсчета 2-мерного контекста  отображения перемещается в позицию, в которой мы хотим прорисовать квадрат. Если вы затем примените scale и прорисуете квадрат в координатах (0, 0), то положение квадрата останется тем же, что и у изначального.

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

Scaling and translating square

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


Вращаем элементы

Пока что все трансформации, с которыми вы имели дело, были довольно неинтересными.  К счастью, трансформация rotate спасет положение, и это бесспорно моя любимая из всего набора.

Уверен, что rotate не нуждается в представлении, так что давайте приступим сразу к написанию кода и повернем квадрат на 45 градусов (помните, что градусы должны быть выражены в радианах (* плоский угол, который образуется, если соединить с центром круга концы дуги на его окружности, равной радиусу этого круга. Так как круг содержит 360 градусов, или 2π радиан, то радиан приблизительно равен 57,2958 градусов)).

За счет этого кода квадрат располагается в координатах (100, 100) и поворачивается ... воу, погодите! Результат выглядит не так, как ожидалось:

Rotating a square

Видите, что получилось? Похоже, что квадрат пытается выйти за пределы окна браузера, а не повернуться в точке с координатами (100, 100). Это так, поскольку rotate, как и все остальные трансформации, влияет на весь 2-мерный контекст отображения, а не только на отдельный объект.

Ниже приводится иллюстрация того, что происходит с системой координат при выполнении rotate на 45 градусов:

How rotation works

Обратите внимание на то, как вся система координат повернулась на 45 градусов относительно точки отсчета (0, 0)? Именно из-за этого квадрат выглядит так, как будто бы он выходит за рамки браузера, просто потому, что позиция (100, 100) была повернута прямо к углу браузера.

Эту проблему можно просто разрешить за счет комбинирования трансформации rotate с translate следующим образом:

При выполнении translate точка отсчета 2-мерного контекста отображения (0, 0) перемещается туда, где должна располагаться центральная точка квадрата (150, 150). Это означает, что любое вращение теперь будет происходить вокруг координаты (150, 150). Если вы затем прорисуете квадрат с негативными значениям координат x и y, равными половине ширины и высоты квадрата, то у вас выйдет квадрат, который выглядит так, как будто он был повернут вокруг его центральной точки:

Rotating and translating a square

Трансформация rotate, скорее всего, наиболее сложна для полного понимания из всех. Важно помнить, что трансформации выполняются со всем 2-мерым контекстом отображения, и если вы хотите повернуть фигуру вокруг ее центральной точки, то вам будет необходимо использовать совместно rotate и translate.

Давайте перейдем к нечто визуально более впечатляющему.


Добавляем Тени

Добавить тени к объектам чарующе просто.

В Canvas имеется поддержка небольшого количества свойств для манипулирования видом прорисованных объектов, и один из наборов этих свойств позволяет вам добавлять тени.

Добавить тени к объектам чарующе просто. Для этого необходимо всего лишь, чтобы в качестве значения свойства shadowColor 2-мерного контекста отображения было установлено значение, отличное от черного прозрачного, и чтобы в качестве значений свойств shadowBlur, shadowOffsetX или shadowOffsetY было установлено значение, отличное от 0.

Посмотрим, что получится в результате выполнения следующего кода:

Будет добавлено размытие тени шириной 15 пикселей и установлено в качестве значения цвета тени непрозрачный черный цвет.

Adding a blurred shadow

Пока выполняем довольно стандартные манипуляции.

Если вы установите в качестве значения shadowBlur 0, измените значение shadowColor на светло серый и установите для dowOffsetX и shadowOffsetY позитивные значения:

то получите в результате тень без размытия, которая появляется немного правее и ниже прорисованного объекта:

Adding a solid shadow

Добавление тени к тексту заголовка    Как бы ни были круты тени, они могут быть отчасти пожирателями ресурсов (* программный пакет, аппаратный блок или человек-пользователь, который захватывает неадекватно большую долю системных ресурсов, например памяти).

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

Помните, что производительность может пострадать, если вы добавляете тень ко множеству объектов одновременно. В некоторых случаях может быть уместным использование изображения PNG (* Portable Network Graphics - "переносимая сетевая графика"; растровый формат, используемый для графических файлов в Интернете, аналогичный формату GIF , но с заметно лучшим сжатием) с тенью вместо прорисовки объектов вручную и динамичного добавления тени при помощи кода. Мы обсудим, как использовать изображения на холсте в следующем руководстве этой серии.


Создаем Градиенты

Вы можете создать два типа градиентов на холсте: линейный и радиальный.

Последняя возможность, которую я хочу с вами рассмотреть в этом руководстве, – добавление градиентов. Имеется два типа градиентов в Сanvas, первый из которых – линейный (прямой) градиент. Вы можете создать линейный градиент при помощи метода createLinearGradient (кто бы сомневался), который в псевдокоде (*  язык, напоминающий императивный язык программирования и используемый в качестве нотации для описания алгоритмов и/или структуры программы) выглядит следующим образом:

Первая пара аргументов – x- и у-координаты начала градиента, а вторая пара аргументов – x- и у-координаты конца градиента. Важно подчеркнуть, что градиент в Сanvas является собственно значением цвета, поэтому вы применяете его в качестве значений свойств fillStyle и strokeStyle.

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

Обратите внимание на то, что вы присваиваете значение градиента переменной, затем используете эту переменную для вызова метода addColorStop. Этот метод позволяет вам установить значения цвета в определенных участках вдоль градиента. Например: позиция со значением 0 представляла бы начало градиента (первая пара x- и у-координат), а позиция со значением 1 представляла бы конец градиента (вторая пара x- и у-координат). Также вы можете использовать десятичные значения между 0 и 1 для присвоения значения цвета в различных участках вдоль градиента, например 0.5 представляло бы участок посередине градиента.

За счет применения значения переменной gradient к свойству fillStyle вы получаете замечательный градиент, который начинается с белого цвета (в позиции 0 на верхушке холста) и заканчивается черным (в позиции 1 внизу холста):

Creating a linear gradient

Однако вам не всегда следует использовать линейный градиент; вы также можете создавать радиальные градиенты!

Радиальные градиенты создаются при помощи метода createRadialGradient, который в псевдокоде выглядит следующим образом:

Первые три аргумента – координаты x, y и радиус круга в начале градиента, а остальные три аргумента представляют собой координаты x, y и радиус круга в конце градиента.

Звучит запутанно, верно? Немного, так что давайте возьмем и создадим радиальный градиент, чтобы посмотреть, что произойдет:

Мы создали радиальный градиент, который начинается в точке (350, 350) с радиусом круга, равным 0, и заканчивается в точке (50, 50) с радиусом круга, равным 100. Вы можете догадаться, как этот градиент будет выглядеть? Получите 20 очков, если вы посчитали, что он будет выглядеть следующим образом:

Creating a radial gradient

Если вы похожи на меня, то это не то, что мы ожидали увидеть. Я пользовался радиальными градиентами ранее в программах вроде Adobe Photoshop, и они выглядят там совсем по-другому. Так почему же он выглядит так? Что ж, вот почему он выглядит так таинственно.

Ознакомьтесь со схемой ниже, на которой ясно разъясняется, как работает радиальный градиент в Сanvas:

How radial gradients work

Интересно, не правда ли? По существу, метод для создания градиента позволяет вам создавать конусовидную фигуру, но что если вы хотите создать стандартный радиальный градиент, подобный тому, что используем в Photoshop? К счастью, это просто.

Для создания стандартного радиального градиента вам просто необходимо разместить два круга градиента в одних и тех же координатах x и y, и при этом убедиться, что один из кругов градиента больше другого:

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

Creating a radial gradient

Он выглядит понятнее! Честно говоря, я был поражен, когда увидел, как реализуются радиальные градиенты в Сanvas. Готов поспорить, у многих возникли трудности в пониманием их работы, когда они увидели эту конусообразную фигуру. Что же, как минимум теперь вы знаете, как создавать стандартные градиенты.

Стоит отметить, что создание градиентов на холсте – также довольно ресурсозатратная операция. Если вы хотите покрыть весь холст градиентом, то я бы сначала рассмотрел вариант с применением к самому элементу canvas фона в виде градиента CSS3.


Подводим итоги

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

В следующем руководстве серии "Canvas from Scratch" мы перейдем от рисования объектов к рассмотрению того, как манипулировать изображениями и видео на холсте. Вот где ставится по-настоящему интересно. Следите за появлением новых руководств!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.