Canvas (англійською canvas — «полотно») — елемент HTML5, який застосовують для подання графіки, використовуючи скрипти (переважно JavaScript).
Публікація є переказом посібника з canvas англійською мовою. Текст упорядкував Олександр Рудик з метою пристосувати до використання при навчанні у школі. В усіх завданнях, починаючи з другого, аналіз коду передбачає зміну значень властивостей, передбачення результатів цих змін і порівняння передбачення з отриманим. Кожне таке завдання можна доповнити завданням зміни коду з певною метою.
Зміст
<canvas id="name" width="400" height="300"> Текст і/або зображення, які: * буде відображено старими версіями браузерів, що не підтримують canvas; * не буде відображено новими версіями браузерів, що підтримують canvas. </canvas>
— з назвою "name" (необов'язковий атрибут), шириною 400 i висотою 300 пікселів. Такий опис потрібно розташувати у відповідній частині коду HTML. Контейнер canvas може не містити нічого. Якщо атрибути висоти й ширини не задано, їм як усталенено буде надано значення 300 й 150 відповідно. Розміри також можна задати в CSS.
Вказівки виведення зображення подають окремим кодом Javascript у контейнері <script>…</script>.
Полотно спочатку порожнє і прозоре. Для отримання контексту унаочнення існує метод getContext, який використовують наприклад, таким чином:
var a = document.getElementById('name'); var b = a.getContext('2d');
Завдання 1. Проаналізувати код сторінки, яку можна використати як заготовку для подальших вправ, і порівняти з очікуваним.
2. Прямокутники й контури
На відміну від SVG, canvas підтримує лише одну примітивну фігуру: прямокутник, сторони якого вертикальні або горизонтальні. Всі інші фігур створюють поєднанням контурів.
Прямокутник з властивостями:
малюють за допомогою таких методів (записувати через крапку після назви контексту, отриманого методом getContext):
Контур малюють за допомогою таких методів:
arc(x, y, r, φ1, φ2, anticlockwise) — малювання дуги кола з центром у точці (x, y), радіусом r і кутом у межах від φ0 до φ1 у напрямку проти руху годинникової стрілки при значенні true параметра anticlockwise, інакше — у напрямку руху годинникової стрілки;
quadraticCurveTo(x1, y1, x, y) — малювання квадратичної кривої Безьє з поточної позиції у точку (x, y) з використанням контрольної точки (x1, y1), позначеної червоним квадратом на малюнку нижче:
bezierCurveTo(x1, y1, x2, y2y, x, y) — малювання кубічної кривої Безьє з поточної позиції у точку (x, y) з використанням контрольних точок (x1, y1), (x2, y2), позначених червоними квадратами на малюнку нижче:
rect(x, y, width, height) — додавання в контур контура прямокутника з такими властивостями:
Після виклику rect поточною позицією стає лівий верхній кут доданого прямокутника.
Завдання 2. Проаналізувати код функції draw сторінки, на якій зображено заповнений трикутник і контур іншого трикутника.
Завдання 3. Проаналізувати код функції draw сторінки, на якій зображено дуги і сегменти.
Завдання 4. Проаналізувати код функції draw сторінок a, b, на якій зображено криві Безьє.
3. Колір
Колір визначають значенням властивостей:
Значення цих властивостей можна задати одним з 4 способів — див. приклад для помаранчевого:
b.fillStyle = "orange"; // color CSS b.fillStyle = "#FFA500"; b.fillStyle = "rgb(255,165,0)"; b.fillStyle = "rgba(255,165,0,1)";
— див. перелік назв і кодів. Як усталено колір заповнення й контуру — чорний (#000000).
Примітка. Тут і далі під властивістю розуміють властивість контексту зображення, отриманого методом getContext. В усіх поданих прикладах він має назву b. При зміні значення властивості нове значення стосується лише тих фігур, які буде намальовано надалі до наступної зміни цих значення властивості.
Завдання 5. Проаналізувати код функції draw сторінок, на якій зображено квадрати і кола різного кольору.
Прозорість визначають значенням властивості globalAlpha (дійсне число):
Завдання 6. Проаналізувати код функції draw сторінки, на якій зображено концентричні напівпророзі круги на тлі квадратів різного кольору.
4. Властивості лінії
Ширина лінії визначається значенням властивості lineWidth (ціле число — кількість пікселів).
Завдання 7. Проаналізувати код функції draw сторінки, на якій зображено вертикальні лінії різної товщини.
Зображення кінців визначається значенням властивості lineCap:
Завдання 8. Проаналізувати код функції draw сторінки, на якій зображено вертикальні лінії з різним закінченням.
Спосіб поєднання ланок ліній, дуг або кривих з ненульовий довжиною задають значенням властивості lineJoin:
Останнє налаштування виконують за допомогою властивості miterLimit, про яку мова йтиме далі.
Для властивості lineJoin значенням як усталено є miter. Налаштування lineJoin не діє, якщо дві ланки мають один і той самий напрямок: у цьому випадку не буде додано область сполучення.
Завдання 9. Проаналізувати код функції draw сторінки, на якій зображено ламані з різним сполученням ланок.
Властивість miterLimit (як усталено значення 10) визначає верхню межу відстані між зовнішньою точкою сполучення і внутрішньою точкою сполучення.
Завдання 10. Проаналізувати код функції draw сторінки для різних значень b.miterLimit, що не перевищують 20.
Пунктирна лінія. Метод setLineDash задає шаблон штрихів для пунктирних ліній на основі отриманого списку цілих чисел, який визначає відстані для почергового рисування лінії і розриву.
Завдання 11. Проаналізувати код функції draw сторінки з різними пунктирними лініями.
5. Градієнти
Градієнти створюють за допомогою методів:
createLinearGradient (x1, y1, x2, y2) — cтворення об'єкту лінійного градієнту з початковою точкою (x1, y1) і кінцевою точкою (x2, y2);
createRadialGradient (x1, y1, r1, x2, y2, r2) — cтворення об'єкту радіального градієнту за колами: одне з центром у (x1, y1) і радіусом r1, а інше — з центром у (x2, y2) з радіусом r2.
Після створення об’єкта градієнту потрібно вказати кольори за допомогою методу:
addColorStop(позиція, колір):
Вказати кольори можна у довільній кількості позицій додатково до початкової 0 і кінцевої 1.
Завдання 12. Проаналізувати код функції draw сторінок лінійними і радіальними градієнтами.
6. Шаблон
Шаблон повторення зображень створюють методом createPattern (image, type), що створює і повертає новий об'єкт — шаблон (pattern):
Після створення шаблону можна призначити йому властивості fillStyle або strokeStyle.
Завдання 13. Проаналізувати код функції draw сторінки з декоративним орнаментом, у створенні якого використано таке зображення.
Індекс точки відносно замкненого контура — це кількість обертів вектора з початком у даній точці при однократному русі кінця вектора вздовж цього контура.
Завдання 14. Проаналізувати код функції draw сторінки, що містить два однакові контури з різними правилами заповнення.
8. Текст
Виведення тексту в точку (x, y) — при бажанні можна вказати максимальну ширину:
Cтиль тексту задають значенням таких властивостей:
font — рядок, що має такий самий синтаксис як однойменна властивість CSS. Усталене значення '10px sans-serif'. На початку такого рядка можна задати написання:
textAlign — налаштування вирівнювання тексту по горизонталі з такими можливими значеннями: start, end, left, right, center. Як усталено дорівнює start;
textBaseline — налаштування вирівнювання тексту по вертикалі. Можливі значення: top, hanging, middle, alphabetic, ideographic, bottom. Як усталено дорівнює alphabetic.
Ці властивості мають бути знайомі тим, хто має досвід роботи з CSS.
Тінь формують наданням значень таким властивостям:
Джерело зображення Canvas (тип CanvasImageSource) може мати один з таких типів даних:
Cпособи отримання зображень для використання на полотні
Використання зображень з інших доменів. Використавши атрибут crossОrigin елемента <img>, можна запросити дозвіл на завантаження з іншого домену для використання в drawImage.
Використання інших елементів canvas. Як і для звичайних зображень, можна отримати доступ до інших елементів canvas, використовуючи або метод document.getElementsByTagName, або метод document.getElementById.
Створення зображень з нуля з використанням конструктора Image. При спробі викликати функцію drawImage перед тим як зображення завантажиться, скрипт нічого не зробить (у давніх браузерах, може навіть видати виняток). Тому необхідно використовувати подію load, наприклад, таким чином:
var img = new Image (); // Створює нове зображення img.addEventListener ( "load", function () {// тут використати функцію drawImage }, False ); img.src = 'myImage.png'; // Встановити джерело файлу
Якщо використано лише одне стороннє зображення, то такий підхід прийнятний. Але якщо потрібно стежити за кількома зображеннями, то необхідно придумати щось краще.
Вкладення зображення за допомогою даних URL дозволяє повністю визначити зображення як Base64 кодований рядок символів прямо у код.
var img = new Image (); // Створення нового елемента img img.src = 'data: image / gif; base64, R0lGODlhCwALAIAAAAAA3pn / ZiH5BAEAAAEALAAAAAALAAsAAAIUhA + hkcuO4lmNVindo7qyrIXiGBYAOw ==';
Перевагою такого вкладення є отримання зображення відразу без інших запитів на сервер. Інша потенційна перевага полягає у тому, що так можна інкапсулювати в одному файлі все щодо CSS, JavaScript, HTML і зображень. Але зображення у цьому випадку не кешовано. Для зображень з великим розміром кодування url може стати дуже довгим процесом.
Використання кадрів з відео.
Метод drawImage можна використати таким чином: drawImage(image,x,y);
Завдання 17. Проаналізувати код функції draw сторінки, на якій фото вибуху ядерної бомби перекреслено двома намальованими лініями червоного кольору.
Зміна розмірів. Інший варіант застосування методу drawImage має два додаткові параметри розміри — ширина й висота прямокутника, який буде заповнено зображенням:
drawImage (image, x, y, width, height):
Завдання 18. Проаналізувати код функції draw сторінки, на якій фото дрофи розміру 236×214 пікселів,
зменшене у 4 рази до розміру 50×38 пікселів, використано для створення шпалер.
Примітка При істотному збільшенні або зменшенні зображень растрової графіки якість відображення може стати неприйнятною. Краще за все взагалі не змінювати розміри зображення, якщо на ньому є текст, який потрібно залишити читаним.
10. Опрацювання пікселів
Метод getImageData повертає дані зображення у вигляді, придатному для опрацювання окремих пікселів. Властивість data повернутого об'єкта містить лінійний масив інтенсивностей кольорів моделі RGBα — по 4 числа на піксель. Ці інтенсивності можна аналізувати і навіть змінювати.
Метод putImageData — обернений до getImageData. Інакше кажучи, він виводить дані на полотно.
Завдання 19. Проаналізувати код функції draw сторінки, на якій подано фото дрофи і (на полотні canvas) його "негатив".
"Негатив" утворено переходом до таких інтенсивнестей кольорів, які в сумі з початковими складають 255.
Примітка. Для спрацювання методу getImageData необхідно розташувати код і джерело зображення на сайті. Хоча б на localhost при використанні XAMPP.
Інакше (наприклад, при розташуванні вказаних файлів у звичайній теці на ПК) буде отримано помилку виконання коду, метод getImageData і всі наступні вказівки коду не спрацюють. Для сторінки з прикладу 19 у цьому випадку буде виведено два однакових зображення.
11. Нарізання зображень
У третього і найповнішого за переліком можливостей варіанту методу drawImage крім джерела зображення є ще 8 параметрів, що описують вирізання шматка зображення, зміну його розміру й малюння:
drawImage(image, sx, sy, sW, sH, dx, dy, dW, dH);
Ця функція бере частину зображення у вигляді прямокутника, лівий верхній кут якого має координати (sx, sy), ширина і висота — sW і sH і малює в полотно canvas, розташовуючи верхній лівий його кут у точці (dx, dy) і змінюючи його розмір на значення dW і dH.
Таким чином, перші 4 параметри визначають місце розташування і розмір фрагмента вихідного зображення. Останні 4 параметри визначають прямокутник, в який буде вписано зображення на малюнку canvas.
Можна зібрати всі елементи в одному файлі зображення і використовувати нарізання для створення композиції. При цьому немає потреби завантажувати кожне зображення окремо, що може збільшити швидкість завантаження. сторінки.
Завдання 19. Проаналізувати код функції draw сторінки, у якому частину фото дрофи подано у рамці.
В останньому коді застосовано інший спосіб завантаження зображення: замість створення нових об'єктів HTMLImageElement зображення включено як теги img безпосередньо у сторінку HTML. Зображення приховано за допомогою CSS властивості display зі значенням "none".
Завдання 20. Проаналізувати код функції draw сторінки, який подає невелику галерею, втілену таблицею з 4 зображень:
Після завантаження сторінки, елемент canvas буде вставлено перед кожним зображенням, відмінним від рамки, а навколо буде намальовано рамку.
При переборі елементів document.images додають нові елементи canvas. Для цього використано метод insertBefore батьківського вузла елемента таблиці (зображення).
12. Збереження й відновлення налаштувань
Збереження налаштувань полотна методом save і відновлення збережених налаштувань методом restore — корисні інструменти створення складних зображень.
Налаштування полотна зберігає стек: першим буде відновлено те, що було збережено останнім. До цих збережуваних і відновлюваних налаштувань належать такі:
Метод transform(a, b, c, d, e, f) задає лінійне перетворення координат і має таке тлумачення параметрів:
Він множить поточну матрицю перетворення на таку матрицю:
a | c | e |
b | d | f |
0 | 0 | 1 |
Як усталено матриця перетворення дорівнює одиничній: 1 — на головній діагоналі, решта елементів дорівнюють 0:
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 1 |
Метод setTransform (a, b, c, d, e, f) (з тими самими аргументами) задає поточне перетворення одиничною матрицею, а потім викликає метод transform з тими самими аргументами. Інакше кажучи, скасовує поточне перетворення, після чого встановлює задане перетворення — все однією вказівкою.
Завдання 25. Проаналізувати код функції draw сторінки з урахуванням того, що матриця лінійного перетворення координат при повороті на кут φ має такий вигляд.
cos φ | sin φ |
− sin φ | cos φ |
Метод resetTransform() задає поточне перетворення одиничною матрицею, тобто еквівалентний дії методу setTransform(1,0,0,1,0,0).
14. Відсічний контур
Відсічний контур діє як маска для приховування небажаних частин фігур. Все, що лежить зовні цього контуру, не буде намальовано на полотні. Такий контур створюють за допомогою методу clip, що працює зі шляхами так само, як розглянуті вище методи stroke і fill. Але з такою відмінністю: clip використовують замість closePath, щоб закрити шлях і перетворити його на відсічний контур замість того, щоб обвести контур або заповнити внутрішню область. Як усталено елемент canvas має відсічний контур такого самого розміру, як і саме полотно.
Завдання 26. Проаналізувати код функції draw сторінки з відсічним контуром у вигляді кола, всередині якого зображено випадково розташовані зірки.
15. Поєднання фігур
Поєднання (компонування, змішування) фігур задають значенням властивості globalCompositeOperation.
Завдання 27. Проаналізувати код функції draw сторінки, що показує поєднання квадратів червоного і зеленого кольорів при різних значеннях globalCompositeOperation при умові, що першим буде зображено квадрат червоного кольору. Дати словесний опис результату поєднання для кожного значення властивості globalCompositeOperation.
16. Анімація
Створення анімації на полотні canvas має істотне обмеження: коли фігура намальована, її не можна рухати. Щоб зобразити рух, потрібно перемалювати фігуру. Перемальовування складних кадрів займає багато часу, тому результат відтворення істотно залежить від швидкодії комп'ютера.
Необхідні кроки створення нового кадру
Очистити canvas. Якщо анімована фігура не займає все полотно (як, наприклад, тло), то все намальоване раніше необхідно стерти. Частот це найпростіше зробити за допомогою методу clearRect.
Зберегти початковий стан canvas. Якщо змінюють будь-які налаштування canvas (стилі, трансформації тощо), а при перемалюванні починати потрібно з деякого початкового налаштування, то потрібно зробити і зберегти це початкове налаштування.
Намалювати анімовані фігури.
Відновити стан canvas до того, як малювати наступний кадр.
Для створення анімації необхідним є спосіб виконання функцій відтворення через певні інтервали часу.
Заплановані оновлення передбачають використання таких вказівок:
window.setInterval(f,t) — періодичне виконання функції f кожні t мілісекунд;
window.setTimeout(f,t) — виконання функції f через t мілісекунд;
window.requestAnimationFrame(f) — повідомлення браузеру про перехід до анімації і виклик функції f для поновлення анімації перед наступним перемальовуванням.
Якщо не заплановано жодної взаємодії з користувачем, можна використати setInterval. Якщо контроль анімації здійснюють мишею або клавіатурою (наприклад, у грі), то необхідно використовувати setTimeout. Встановивши EventListener, можна перехопити будь-які дії користувача і відповідним чином змінити анімацію.
У прикладах буде використано вказівку window.requestAnimationFrame для контролю анімації. Вона здійснює нову ітерацію, коли система готова до малювання нового кадру. Кількість викликів на секунду приблизно дорівнює 60 і зменшується, коли вкладення неактивне. Для детальнішого вивчення циклу анімації, особливо для ігор, радимо прочитати статтю «Анатомія відеоігор» (англійською).
Завдання 28. Проаналізувати код сторінки, що моделює рух Землі й Місяця навколо Сонця (без збереження масштабу), використовуючи такі зображення:
b.mozImageSmoothingEnabled = false; b.webkitImageSmoothingEnabled = false; b.msImageSmoothingEnabled = false; b.imageSmoothingEnabled = false;
За допомогою методу drawImage, другого полотна і властивості imageSmoothingEnabled можна збільшити зображення й роздивитися його детальніше.
Завдання 32. Проаналізувати код сторінки, на якій розташування вказівника миші на полотні із зображенням птаха дрофи взято за лівий верхній кут квадрату розміру 40×40, який буде відображено на іншому полотні розміру 200×200 із збільшенням у 5 разів. Як усталено включено згладжування. Можна зняти прапорець, щоб побачити ефект властивості imageSmoothingEnabled, якому потрібні префікси для різних браузерів.
20. Правила роботи для підвищення продуктивності
Попередньо намалювати повторювані об'єкти на offscreenCanvas. Потім можна вивести закадрове зображення на основне полотно без потреби повторювати кроки, необхідні для його породження.
myCanvas.offscreenCanvas = document.createElement ('canvas'); myCanvas.offscreenCanvas.width = myCanvas.width; myCanvas.offscreenCanvas.height = myCanvas.height; myCanvas.getContext('2d').drawImage (myCanvas.offScreenCanvas, 0, 0);
Уникати використання координат з рухомою точкою, використовувати лише цілі числа з метою уникнення створення ефекту згладжування. Округлення здійснювати, наприклад, за допомогою Math.floor().
Не масштабувати зображення при використанні drawImage, а зберігати зображення різних розмірів на <>offscreen 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 background для великих статичних зображень тла з розташуванням під canvas.
Масштабування полотна з використанням CSS-перетворень, які працюють швидше, бо вони використовують графічний процесор. В ідеалі не варто масштабувати зображення на полотні або можна використовувати менше полотно і збільшувати його при необхідності, але не навпаки.
Вимкнути прозорість, якщо немає потреби у прозорості тла, встановивши для параметра alpha значенння false при створенні контексту малювання за допомогою getContext:
var b = canvas.getContext('2d', {alpha: false});
Об'єднувати запити. Наприклад, малювати одну ламану лінію замість декількох окремих.
Уникати непотрібних змін стану canvas.
Відображати лише зміни екрану, а не заново перемальовувати все.
Уникати використання властивості shadowBlur та малювання тексту.
Випробувати різні способи очищення полотна: clearRect , fillRect або зміну розміру олотна.
Для анімації використовувати window.requestAnimationFrame замість window.setInterval.
Бути обережнм з важкими фізичними бібліотеками.
21. Додаткові ресурси глобальної мережі