HTML5+JS
Эффекты создаются с использованием чистого JavaScript на элементе canvas HTML5. В этом разделе рассматриваются основы: рисование фигур, рисование с итерациями и добавление движения.
Рисование фигур
Заголовок раздела «Рисование фигур»В этом руководстве используется общий шаблон lightscript:
<head> <meta description="Template"/> <meta publisher="WhirlwindFX" /></head>
<body style="margin: 0; padding: 0;"> <canvas id="exCanvas" width="320" height="200"></canvas></body>
<script> // Get the canvas element from the DOM var c = document.getElementById("exCanvas"); var ctx = c.getContext("2d");
var width = 320; var height = 200; var hue = 0;
function update() { // Code goes here window.requestAnimationFrame(update); }
window.requestAnimationFrame(update);</script>Независимо от количества линий процесс остаётся одинаковым.
- ctx.beginPath() начинает фигуру
- ctx.moveTo(x, y) задаёт первую точку
- ctx.lineTo(x, y) задаёт следующую точку и линию обратно к первой. Используйте несколько lineTo для рисования более крупных фигур.
- Задайте ctx.strokeStyle и/или ctx.fillStyle (если фигура замкнута)
- Используйте ctx.stroke() для отрисовки линий и ctx.fill() для заливки замкнутых фигур. Важно помнить, что до этого момента всё является лишь гипотетическим — ничего не рисуется до выполнения этих команд.
Три примера с использованием линий:
function update() { // One Line ctx.beginPath(); ctx.moveTo(30, 30); ctx.lineTo(30, 170); ctx.strokeStyle = "blue"; ctx.stroke();
// L ctx.beginPath(); ctx.moveTo(80, 30); ctx.lineTo(80, 100); ctx.lineTo(120, 100); ctx.strokeStyle = "blue"; ctx.stroke();
// Filled Triangle ctx.beginPath(); ctx.moveTo(130, 30); ctx.lineTo(130, 100); ctx.lineTo(170, 100); ctx.lineTo(130, 30); ctx.fillStyle = "red"; ctx.strokeStyle = "blue"; ctx.fill(); ctx.stroke();
window.requestAnimationFrame(update);}
Важно отметить порядок отрисовки: закрашенный треугольник рисуется последним, поэтому он перекрыл бы две другие фигуры, если бы находился на той же позиции. Кроме того, обводка треугольника рисуется после заливки. Если поменять эти шаги местами, внутренняя половина обводки будет перекрыта красной заливкой.
Прямоугольники
Заголовок раздела «Прямоугольники»Прямоугольники просты и полезны, особенно для типичного разрешения RGB-клавиатуры. Процесс аналогичен рисованию линий — просто замените команды moveTo и lineTo на rect(x, y, width, height).
function update() { // Basic Square ctx.beginPath(); ctx.rect(30, 30, 75, 75); ctx.strokeStyle = "blue"; ctx.stroke();
// Filled Rectangle ctx.beginPath(); ctx.rect(125, 30, 125, 100); ctx.fillStyle = "red"; ctx.strokeStyle = "blue"; ctx.fill(); ctx.stroke();
window.requestAnimationFrame(update); }
Дуги рисуются путём вращения внешней точки вокруг центральной и могут использоваться для создания окружностей. Команда дуги: ctx.arc(x, y, radius, start angle, end angle), где оба угла задаются в радианах. В отличие от прямоугольников, дуга рисуется с началом координат (x, y) в центре дуги.
function update() { // Half-circle ctx.beginPath(); ctx.arc(70, 100, 30, 0, Math.PI); ctx.strokeStyle = "blue"; ctx.stroke();
// 3/4 circle ctx.beginPath(); ctx.arc(140, 100, 30, 0, Math.PI * (3/2)); ctx.strokeStyle = "blue"; ctx.stroke();
// Full circle ctx.beginPath(); ctx.arc(210, 100, 30, 0, Math.PI * 2); ctx.strokeStyle = "blue"; ctx.stroke(); ctx.fillStyle = "red"; ctx.fill();
window.requestAnimationFrame(update); }
Как видно, дуги рисуются по часовой стрелке по умолчанию. Это можно изменить, задав конечный угол меньше начального или добавив «true» в качестве последнего аргумента метода ctx.arc().
Рисование с итерациями
Заголовок раздела «Рисование с итерациями»Нарисовать три фигуры вручную легко занимает двадцать строк кода, поэтому если нужно нарисовать сто фигур, необходим более эффективный подход. Циклы в JavaScript — простой способ повторять задачи, и они применимы и к рисованию.
Пример с использованием for-цикла для рисования ряда шахматных квадратов:
function update() {
for(let i = 0; i < 8; i++){
// 1. Create rectangle path and draw the stroke for each. ctx.beginPath(); ctx.rect(i * 20, 20, 20, 20); ctx.strokeStyle = "black"; ctx.stroke();
// 2. If 'i' is even, the fillStyle is black. Otherwise it's white. if(i % 2 == 0){ ctx.fillStyle = "black"; } else { ctx.fillStyle = "white"; } // 3. Fill the shape after setting the fillStyle. ctx.fill(); }
window.requestAnimationFrame(update); }
Пример с while-циклом для рисования шахматной сетки. В каждой итерации яркость чёрных квадратов и оттенок белых квадратов будут немного меняться с использованием шаблонных литералов.
function update() {
var i = 0;
while(i < 16){
// 1. X and Y calculations with 'row' and 'column' // This operation rounds the result down to the nearest integer. For i = (0-3) the row will be 0, for i = (4-7) the row will be 1, and so on var iRow = Math.floor(i / 4); // This operation finds the remainder after division, limiting column to the (0-3) range. var iCol = i % 4; // Multiply by the square width to find this square's x-origin var ix = iCol * 20; // Multiply by the square height to find this square's y-origin var iy = iRow * 20;
// 2. Path and stroke ctx.beginPath(); ctx.rect(ix, iy, 20, 20); ctx.strokeStyle = "black"; ctx.stroke();
// 3. If the row is even, every other square is filled black. If odd, switch the black squares. Each iteration adds a small amount of the lightness component to the black, and hue to the white. if(iRow % 2 == 0){ if(i % 2 == 0){ // 'Black' ctx.fillStyle = `hsl(1, 0%, ${5 * i}%)` } else { // 'White' ctx.fillStyle = `hsl(${10 * i}, 100%, 50%)`; } } else { if(i % 2 == 0){ // 'White' ctx.fillStyle = `hsl(${10 * i}, 100%, 50%)`; } else { // 'Black' ctx.fillStyle = `hsl(1, 0%, ${5 * i}%)` } }
ctx.fill(); i++; }
window.requestAnimationFrame(update); }
Добавление движения
Заголовок раздела «Добавление движения»Анимации на canvas ограничены лишь вашим воображением и математическими знаниями. Если вы чувствуете себя неуверенно в тригонометрии или геометрии, рекомендуем немного углубиться в эти темы. В следующих примерах возьмём неподвижный круг и привяжем все возможные переменные к простому осциллирующему движению.
Золотым стандартом осцилляции (регулярного движения туда-обратно) является вычисление sin() или cosine() от таймера. Обе операции вернут значение от -1 до 1 для ЛЮБОГО переданного значения, даже если оно только увеличивается. Единственное различие между ними — небольшой сдвиг фазы: когда cos равен 0, sin равен -1 или 1, и наоборот. Мы можем использовать это в нашей анимации:
function update() {
// Find current time in milliseconds, then divide to slow down the animation speed let time = Date.now() / 100;
// Draw a background so the old shapes don't stick around ctx.fillStyle = "white"; ctx.fillRect(0, 0, 320,200);
ctx.beginPath();
//USE ONE EXAMPLE AT A TIME // 1st example - side to side, y is constant ctx.arc(15 * Math.cos(time) + 160, 100, 30, 0, Math.PI * 2); // 2nd example - up and down, x is constant ctx.arc(160, 15 * Math.sin(time) + 100, 30, 0, Math.PI * 2); // 3rd example - circle, x and y are variable ctx.arc(15 * Math.cos(time) + 160, 15 * Math.sin(time) + 100, 30, 0, Math.PI * 2);
ctx.fillStyle = "black"; ctx.fill();
window.requestAnimationFrame(update); }Движение влево-вправо
Заголовок раздела «Движение влево-вправо»
Движение вверх-вниз
Заголовок раздела «Движение вверх-вниз»
Полный круг
Заголовок раздела «Полный круг»
Осталось изменить ещё несколько атрибутов со временем — радиус круга, заливку и обводку. Углы дуги пока оставим без изменений, чтобы фигура оставалась простой, — остальное будет достаточно эффектным.
function update() {
let time = Date.now() / 100;
ctx.fillStyle = "white"; ctx.fillRect(0, 0, 320,200);
ctx.beginPath(); ctx.arc(15 * Math.cos(time) + 160, 15 * Math.sin(time) + 100, 30 + 15 * Math.sin(time), 0, Math.PI * 2);
ctx.fillStyle = `hsl(${180 + 180 * Math.cos(time)}, 100%, 50%)`; ctx.fill();
ctx.strokeStyle = `hsl(${180 + 180 * Math.sin(time)}, 100%, 50%)`; ctx.stroke();
window.requestAnimationFrame(update); }
Каждый атрибут каждой созданной нами фигуры можно изменять со временем, и любая анимация — это комбинация описанных выше навыков. Для получения подробной информации о создании многократно используемых эффективных анимаций ознакомьтесь со страницей Обратные вызовы!