Кроме прямоугольников canvas позволяет рисовать и более сложные фигуры. Для оформления сложных фигур используется концепция геометрических путей, которые представляют набор линий, окружностей, прямоугольников и других более мелких деталей, необходимых для построения сложной фигуры.
Для создания нового пути надо вызвать метод beginPath():
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.beginPath(); // начинаем рисование фигуры
После метода beginPath()
вызываются методы, которые непосредственно создают различные участки пути.
Для начала рисования пути нам надо зафиксировать начальную точку этого пути. Это можно сделать с помощью метода moveTo(), который имеет следующее определение:
moveTo(x, y)
Метод перемещает нас на точку с координатами x и y.
Метод lineTo() рисует линию. Он имеет похожее определение:
lineTo(x, y)
Метод рисует линию от текущей позиции до точки с координатами x и y.
Теперь нарисуем ряд линий:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.beginPath(); context.moveTo(20, 100); context.lineTo(140, 10); context.lineTo(260, 100);
Здесь мы устанавливаем начало пути в точку (20, 100), затем от нее рисуем линию до точки (140, 10) (линия вверх) и далее рисуем еще одну линию до точки (260, 100).
Хотя мы нарисовали несколько линий, пока мы их не увидим, потому что их надо отобразить на экране. Для отображения пути надо использовать метод stroke():
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.beginPath(); context.moveTo(20, 100); context.lineTo(140, 10); context.lineTo(260, 100); context.stroke(); // отображаем путь
По умолчанию для отрисовки используется черный цвет, но с помощью свойства strokeStyle можно изменить цвет:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.beginPath(); context.moveTo(20, 100); context.lineTo(140, 10); context.lineTo(260, 100); context.strokeStyle = "red"; // красный цвет context.stroke(); // отображаем путь
Мы нарисовали две линии, и, допустим, мы их хотим соединить, чтобы замкнуть фигуру - в данном случае прямоугольник. В принципе в этом случае мы могли бы нарисовать еще одну линию, и у нас бы получился треугольник. Однако для упрощения Canvas API для этого предоставляет специальный метод - context.closePath(), который позволяет автоматически замкнуть путь, соединив первую и последнюю точки пути, и образовать фигуру:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.beginPath(); context.moveTo(20, 100); context.lineTo(140, 10); context.lineTo(260, 100); context.closePath(); // закрываем путь context.stroke();
При работе со многими путями может возникнуть путаница. В этом случае для разграниченися отдельных путей можно использовать объект Path2D. Этот объект предоставляет методы, аналогичные методам объекта контекста в отношении создания пути. Например:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); const path1 = new Path2D(); // первый путь path1.moveTo(20, 100); path1.lineTo(140, 10); path1.lineTo(260, 100); path1.closePath(); // закрываем путь context.strokeStyle = "blue"; context.stroke(path1); const path2 = new Path2D(); // первый путь path2.moveTo(20, 110); path2.lineTo(140, 200); path2.lineTo(260, 110); path2.closePath(); // закрываем путь context.strokeStyle = "red"; context.stroke(path2);
Здесь создаются два пути, каждый из которых представляет треугольник. Для отрисовки каждого пути вызывается метод context.stroke()
, в который передается путь.
Метод rect() создает прямоугольник. Он имеет следующее определение:
rect(x, y, width, height)
Где x и y - это координаты верхнего левого угла прямоугольника относительно canvas, а width и height - соответственно ширина и высота прямоугольника. Нарисуем, к примеру, следующий прямоугольник:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.beginPath(); context.rect(30, 20, 100, 90); context.closePath(); context.stroke();
Стоит отметить, что такой же прямоугольник мы могли бы создать из линий:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.beginPath(); context.moveTo(30, 20); context.lineTo(130, 20); context.lineTo(130, 110); context.lineTo(30, 110); context.closePath(); context.stroke();
Метод fill() заполняет цветом все внутреннее пространство нарисованного пути:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.beginPath(); context.moveTo(20, 100); context.lineTo(140, 10); context.lineTo(260, 100); context.closePath(); context.strokeStyle = "#2e86de"; context.fillStyle = "#4bcffa"; context.fill(); context.stroke();
С помощью свойства fillStyle
опять же можно задать цвет заполнения фигуры. В данном случае это цвет "#4bcffa".
Метод clip() позволяет вырезать из canvas определенную область, а все, что вне этой области, будет игнорироваться при последующей отрисовке.
Для понимания этого метода сначала нарисуем два прямоугольника:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); // рисуем первый красный прямоугольник context.beginPath(); context.moveTo(10, 20); context.lineTo(130, 20); context.lineTo(130, 110); context.lineTo(10, 110); context.closePath(); context.strokeStyle = "red"; context.stroke(); // рисуем второй зеленый прямоугольник context.beginPath(); context.rect(30, 50, 180, 70); context.closePath(); context.strokeStyle = "green"; context.stroke();
Теперь применим метод clip()
для ограничения области рисования только первым прямоугольником:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); // рисуем первый красный прямоугольник context.beginPath(); context.moveTo(10, 20); context.lineTo(130, 20); context.lineTo(130, 110); context.lineTo(10, 110); context.closePath(); context.strokeStyle = "red"; context.stroke(); context.clip(); // обрезаем область рисования по первому пути // рисуем второй зеленый прямоугольник context.beginPath(); context.rect(30, 50, 180, 70); context.closePath(); context.strokeStyle = "green"; context.stroke();
Поскольку вызов метода clip()
идет после первого прямоугольника, то из второго прямоугольника будет нарисована только та часть, которая
попадает в первый прямоугольник.
Метод arc() добавляет к пути участок окружности или дугу/арку. Он имеет следующее определение:
arc(x, y, radius, startAngle, endAngle, anticlockwise)
Здесь используются следующие параметры:
x
и y
: x- и y-координаты, в которых начинается дуга
radius
: радиус окружности, по которой создается дуга
startAngle
и endAngle
: начальный и конечный угол, которые усекают окружность до дуги.
В качестве единици измерения для углов применяются радианы. Например, полная окружность - это 2π радиан.
Если, к примеру, нам надо нарисовать полный круг, то для параметра endAngle можно указать значение 2π. В JavaScript эту веричину можно получить с
помощью выражения Math.PI * 2
.
anticlockwise
: направление движения по окружности при отсечении ее части, ограниченной начальным и конечным углом. При значении
true
направление против часовой стрелки, а при значении false
- по часовой стрелке.
Пример рисования дуг и окружностей
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.strokeStyle = "red"; context.beginPath(); context.moveTo(20, 90); context.arc(20, 90, 50, 0, Math.PI/2, false); context.closePath(); context.stroke(); context.beginPath(); context.moveTo(130, 90); context.arc(130, 90, 50, 0, Math.PI, false); context.closePath(); context.stroke(); context.beginPath(); context.moveTo(240, 90); context.arc(240, 90, 50, 0, Math.PI * 3 / 2, false); context.closePath(); context.stroke(); context.beginPath(); context.arc(350, 90, 50, 0, Math.PI*2, false); context.closePath(); context.stroke();
Последний параметр anticlockwise играет важную роль, так как определяет движение по окружности, и в случае изменения true на false и наоборот, мы можем получить совершенно разные фигуры:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.strokeStyle = "red"; context.beginPath(); context.moveTo(80, 90); context.arc(80, 90, 50, 0, Math.PI/2, false); context.closePath(); context.stroke(); context.beginPath(); context.moveTo(240, 90); context.arc(240, 90, 50, 0, Math.PI/2, true); context.closePath(); context.stroke();
Метод arcTo() также рисует дугу. Он имеет следующее определение:
arcTo(x1, y1, x2, y2, radius)
Где x1 и y1 - координаты первой контрольной точки, x2 и y2 - координаты второй контрольной точки, а radius - радиус дуги.
Пример рисования дуг с помощью arcTo()
:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.strokeStyle = "red"; context.beginPath(); context.moveTo(0, 150); context.arcTo(0, 0, 150, 0, 140) context.closePath(); context.stroke();
Здесь мы перемещаемся вначале на точку (0, 150), и от этой точки до первой контрольной точки (0, 0) будет проходить первая касательная. Далее от первой контрольной точки (0, 0) до второй (150, 0) будет проходить вторая касательная. Эти две касательные оформляют дугу, а 140 служит радиусом окружности, на которой усекается дуга.
Метод quadraticCurveTo() создает квадратичную кривую. Он имеет следующее определение:
quadraticCurveTo(x1, y1, x2, y2)
Где x1 и y1 - координаты первой опорной точки, а x2 и y2 - координаты второй опорной точки.
Пример квадратичной Безье:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.strokeStyle = "red"; context.beginPath(); context.moveTo(20, 90); context.quadraticCurveTo(130, 0, 280, 90) context.closePath(); context.stroke();
Метод bezierCurveTo() рисует кривую Безье. Он имеет следующее определение:
bezierCurveTo(x1, y1, x2, y2, x3, y3)
Где x1 и y1 - координаты первой опорной точки, x2 и y2 - координаты второй опорной точки, а x3 и y3 - координаты третьей опорной точки.
Пример кривой Безье:
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.strokeStyle = "red"; context.beginPath(); context.moveTo(30, 100); context.bezierCurveTo(110, 0, 190, 200, 270, 100); context.closePath(); context.stroke();
Объединим несколько фигур вместе и нарисуем более сложную двухмерную сцену:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>METANIT.COM</title> </head> <body> <canvas id="canvas" width="400" height="250"></canvas> <script> const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); context.beginPath(); context.fill(); context.fillStyle = "yellow"; context.beginPath(); context.arc(160, 130, 100, 0, 2 * Math.PI); context.fill(); // рот context.beginPath(); context.moveTo(100, 160); context.quadraticCurveTo(160, 250, 220, 160); context.closePath(); context.fillStyle = "red"; context.fill(); context.lineWidth = 2; context.strokeStyle = "black"; context.stroke(); // зубы context.fillStyle = "#FFFFFF"; context.fillRect(140, 160, 15, 15); context.fillRect(170, 160, 15, 15); //глаза context.beginPath(); context.arc(130, 90, 20, 0, 2 * Math.PI); context.fillStyle = "#333333"; context.fill(); context.closePath(); context.beginPath(); context.arc(190, 90, 20, 0, 2 * Math.PI); context.fillStyle = "#333333"; context.fill(); context.closePath(); </script> </body> </html>