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

Вивчаємо Canvas з нуля: Трансформації та Градієнти

by
Read Time:12 minsLanguages:
This post is part of a series called Canvas From Scratch.
Canvas From Scratch: Advanced Drawing
Canvas From Scratch: Pixel Manipulation

Ukrainian (українська мова) 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 squareA simple squareA simple square

Тепер давайте спробуємо виконати перелічення 2-мірного контексту відображення та намалювати інший квадрат у тій самій позиції:

Як гадаєте, що відбудеться? Отримайте медальку ті, хто відгадав, що буде промальовано новий квадрат у координатах (100, 100). Ніколи гратися з тими, хто не вгадав. Без образ!

Translating a squareTranslating a squareTranslating a square

Так що ж тут відбувається? Одразу після додавання коду, який потрібен для промальовування другого квадрата, ви промалювали його у тому самому місці, що й перший. Це так, оскільки ви по суті зміщуєте всю систему координат полотна таким чином, що її координати (0, 0) тепер розташовуються в координатах (100, 100).

How translation worksHow translation worksHow translation works

Тепер вам стало зрозуміліше? Сподіваюсь, що так. Може знадобитися деякий час на те, щоб ви зрозуміли цю концепцію, проте вона проста, як тільки ви її зрозуміли.

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

Давайте розглянемо наступну трансформацію у нашому списку.


Масштабуємо наші елементи

Як ви вже, скоріш за все, здогадалися, трансформація scale використовується для зміни розмірів об'єктів. Точніше, трансформація scale використовується для зміни масштабів 2-мірного контексту відображення.

Видаліть код, з яким працювали в прикладі з translate, і додайте наступний:

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

A simple squareA simple squareA simple square

Аргументи методу scale є множниками розмірів контексту за осями x та y.

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

У нашому випадку ми хочемо збільшити розмір квадрата у два рази, так що ми застосовуємо масштаб (5, 5).

У результаті цього отримуємо квадрат, що більше попереднього у два рази.

Scaling a squareScaling a squareScaling a square

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

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

В результаті отримуємо квадрат, розміри якого удвічі більше початкового, проте який промальовано у тій самій позиції, як і початковий.

Scaling and translating squareScaling and translating squareScaling and translating square

Саме обізнаність про подібні невеликі примхи, що спостерігаються при використанні трансформацій, реально допомагають при їх застосуванні. Схоже на те, що більшість поширених проблем при використанні трансформацій є результатом недостатнього розуміння принципів їх роботи.


Обертаємо елементи

Поки що всі трансформації, з якими ви мали справу, були доволі нецікавими.  На щастя, трансформація rotate врятує положення, і це безумовно моя улюблена з всього набору.

Впевнений, що rotate не потребує представлення, так що давайте візьмемося одразу до написання коду та обернемо квадрат на 45 градусів (пам'ятаєте, що градуси потібно виражати в радіанах (* центральний кут, довжина дуги якого дорівнює радіусові цієї дуги)).

Завдяки цьому коду квадрат розташовується у координатах (100, 100) та обертається ... воу, зачекайте! Результат виглядає не так, як очікувалося:

Rotating a squareRotating a squareRotating a square

Бачите, що вийшло? Схоже, що квадрат намагається вийти за межи вікна браузера, а не обернутися у точці з координатами (100, 100). Це так, оскільки rotate, як і всі інші трансформації, впливає на весь 2-мірний контекст відображення, а не тільки не окремий об'єкт.

Нижче наводиться ілюстрація того, що відбувається з системою координат при виконанні rotate на 45 градусів:

How rotation worksHow rotation worksHow rotation works

Зверніть увагу, як вся система координат обернулася на 45 градусів відносно точки відліку (0, 0)? Саме через це квадрат виглядає так, неначе він виходить за межі браузера, просто тому, що позицію (100, 100) було обернуто прямо до кута браузера.

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

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

Rotating and translating a squareRotating and translating a squareRotating and translating a square

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

Нижче наведено код для заголовка сторінки:


Крок 5: Додаємо стильове оформлення для каркаса розмітки: заголовок

Тепер нам потрібно додати стильове оформлення для тегів div. Давайте почнемо по черзі.

Для початку на потрібно додати стильове оформлення для тегів header та body:

Додати тіні до об'єктів чарівливо просто. Для цього потрібно всього лише, щоб у якості значення властивості shadowColor 2-мірного контексту відображення було встановлено значення, відмінне від чорного прозорого, і щоб у якості значень властивостей shadowBlur, shadowOffsetX та shadowOffsetY було встановлено значення, відмінне від 0.

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

Буде додано розмиття тіні шириною 15 пікселів та встановлено у якості значення кольору тіні непрозорий чорний колір.

Adding a blurred shadowAdding a blurred shadowAdding a blurred shadow

Поки що виконуємо доволі стандартні маніпуляції.

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

то отримаєте в результаті тінь без розмиття, що з'являється трохи правіше та нижче промальованого об'єкта:

Adding a solid shadowAdding a solid shadowAdding 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 gradientCreating a linear gradientCreating a linear gradient

Проте вам не завжди варто використовувати лінійний градієнт; ви також можете створювати радіальні градієнти!

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

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

Звучить заплутано, вірно? Трохи, так що давайте візьмемо та створимо радіальний градієнт щоб подивитися, що відбудеться:

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

Creating a radial gradientCreating a radial gradientCreating a radial gradient

Якщо ви схожі на мене, то це не те, що ми очікували побачити. Я користався радіальними градієнтами раніше у програмах на зразок Adobe Photoshop, і вони виглядають там зовсім по-іншому! Так чому же він виглядає так? Що ж, ось чому він виглядає так таємничо.

Ознайомтеся зі схемою нижче, на якій ясно пояснюється, як працює радіальний градієнт у Сanvas:

How radial gradients workHow radial gradients workHow radial gradients work

Цікаво, чи не так? По суті, метод для створення градієнта дозволяє вам створювати конусовидну фігуру, але що якщо ви хочете створити стандартний радіальний градієнт, подібний тому, що використовуємо у Photoshop? На щастя, це просто.

Для створення стандартного радіального градієнта вам просто потрібно розмістити два круги градієнта в тих самих координатах x та y, і при цьому впевнитися, що одне з кіл градієнта більше іншого:

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

Creating a radial gradientCreating a radial gradientCreating a radial gradient

Він виглядає зрозуміліше! Правду кажучи, я був вражений, коли побачив, як реалізуються радіальні градієнти. Готовий побитися об заклад, що у багатьох виникли труднощі з розумінням їх роботи, коли вони побачили цю конусовидну фігуру. Що ж, як мінімум тепер ви знаєте, як створювати стандартні градієнти.

Варто зазначити, що створення градієнтів на полотні – також доволі ресурсозатратна операція. Якщо ви хочете покрити все полотно градієнтом, то я би спочатку розглянув варіант із застосуванням до самого елемента canvas фону у вигляді градієнта CSS3.


Підводимо підсумки

У цьому посібнику ми розглянули, як виконувати базові трансформації на полотні, включаючи перелічення, масштабування та обертання. Також ви дізналися, як додавати тіні до об'єктів та як створювати градієнти. Звучить не дуже вражаюче, проте трансформації, особливо, служать основою деяких найкрутіших трюків, які можна виконати у Саnvas.

У наступному посібнику серії "Canvas from Scratch" ми перейдемо від малювання об'єктів до розглядання того, як маніпулювати зображеннями та відео на полотні. Ось де стає по-справжньому цікаво! Слідкуйте за з'явленням нових посібників!

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.