Перейти к содержимому

Canvas как нарисовать квадрат

  • автор:

Прямоугольники и другие фигуры в Canvas

Перед тем, как рисовать фигуры в Canvas, нужно создать холст и установить для него контекст. О том, как это делать, рассказывалось в предыдущей теме. А здесь я просто напишу код:

let canvas = document.querySelector('canvas'); let ctx = canvas.getContext('2d');

Установка цвета

Все фигуры в Canvas делятся на два типа:

  1. Закрашенные фигуры
  2. Линии

Для каждого типа цвет устанавливается отдельно. Когда Вы выбрали цвет для какого-то типа, то все фигуры этого типа будут создаваться с таким цветом. Пока Вы не установите другой цвет. Свойство fillStyle содержит цвет для закрашенных фигур, а strokeStyle для линий. Цвет устанавливается любым из способов, существующих в CSS. Только не забывайте, что значениями этих свойств являются строки. Установим цвет для фигур:

ctx.fillStyle = '#F0F0F0'; //для линий ctx.strokeStyle = 'rgba(255,10,38,0.9)'; //для закрашенных фигур

Прямоугольники в Canvas

Для рисования прямоугольников и всех остальных фигур применяются координаты в пикселях. Точкой отсчёта является левый верхний угол холста.

Метод fillRect() рисует закрашенный прямоугольник.

fillRect(X, Y, ширина, высота)

X — координата X левого края прямоугольника

Y — координата Y верхнего края прямоугольника

ширина — ширина прямоугольника

высота — высота прямоугольника

Метод strokeRect() добавляет в Canvas прямоугольник в виде линий. Параметры такие же. Для примера нарисуем прямоугольник во весь холст, чтобы были видны его размеры. И добавим ещё один прямоугольник. Фигуры будут иметь цвета, которые мы установили ранее.

ctx.fillRect(0, 0, 699, 399); ctx.strokeRect(10, 60, 70, 100);

Должна получиться такая картинка:

canvas прямоугольник

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

Контуры

Остальные фигуры в Canvas рисуются с помощью контуров. Это делается так:

  1. Вызываем метод beginPath() , который создаёт новый контур.
  2. С помощью различных методов контекста рисуем сам контур.
  3. Если нужно замкнуть контур, то есть, соединить начальную и конечную точку, то используем метод closePath() . Это может потребоваться только для линий. А у замкнутых фигур контур всегда замыкается, даже если это не сделать.
  4. Вызываем один из методов — либо stroke() , либо fill() , которые рисуют фигуру по контуру. stroke() рисует линию, а fill() заполняет контур.

Контур не отображается на рисунке. Он становится виден, когда по нему нарисована фигура.

Метод lineTo() рисует прямую линию от текущей точки до указанной точки.

Указанная точка становится текущей. От неё можно нарисовать ещё одну прямую. И таким образом можно создать сложную линию. Если нужно её прервать и начать новую линию, то используется метод moveTo() , который задаёт новую текущую точку. Все линии остаются частью одного контура. При создании нового контура нужно использовать метод moveTo() для указания начальной точки, от которой начинается контур.

Добавим на рисунок линии:

19
20
21
22
23
24
25
26
27

ctx.strokeStyle = '#0000FF'; ctx.beginPath(); ctx.moveTo(20, 10); ctx.lineTo(70, 50); ctx.lineTo(120, 10); ctx.lineTo(170, 50); ctx.moveTo(200, 10); ctx.lineTo(230, 10); ctx.stroke();

Результат получится такой:

canvas прямоугольник

Замыкать контур не требовалось, поэтому метод closePath() не использован.

Теперь нарисуем закрашенный треугольник.

29
30
31
32
33
34

ctx.fillStyle = '#309053'; ctx.beginPath(); ctx.moveTo(285, 5); ctx.lineTo(320, 70); ctx.lineTo(250, 70); ctx.fill();

Должно выглядеть так:

canvas фигуры

Обратите внимание, нарисовано только две линии. Третья появилась при замыкании контура. Мы ничего не делали для этого. Контур замыкается при заливке.

Стиль линий

Есть несколько свойств, определяуюих стиль линий. Значения этих свойств нужно указывать до того, как линия нарисована. То есть, до метода stroke() . Ширину линий устанавливает свойство lineWidth . Значением является число, указывающее ширину в пикселях. Пример:

36
37
38
39
40
41

ctx.lineWidth = 10; ctx.beginPath(); ctx.moveTo(340, 20); ctx.lineTo(430, 40); ctx.lineTo(340, 70); ctx.stroke();

 фигуры canvas

Ширину менее 2 пикселей не всегда возможно сделать. Вместо уменьшения ширины линия может становиться прозрачной. Особенно это проявляется на горизонтальных и вертикальных линиях. Для дуги ширина 1 пиксель выглядит нормально. Можно указывать дробные значения.

Свойство lineCap определяет внешний вид краёв линий. Может иметь значения:

butt — плоские (по умолчанию)

Укажем это свойство при рисовании широкой линии:

ctx.lineCap = 'round';

Учитывайте, что круглые и квадратные края занимают место на рисунке и увеличивают длину линии.

Свойство lineJoin устанавливает внешний вид угла между двумя линиями. Значения:

miter — острый (по умолчанию)

ctx.lineJoin = 'round';

В этой теме уже рассматривалось рисование прямоугольников. Существует ещё метод rect() , который также добавляет прямоугольник в Canvas. Его отличие в том, что он создаёт контур, по которому далее нужно нарисовать фигуру.

Дуги

Метод arc() рисует дугу определённого радиуса. В том числе, она может нарисовать круг.

arc(X, Y, радиус, начальный угол, конечный угол, направление)

X — координата X центра

Y — координата Y центра

радиус — радиус в пикселях

начальный угол — угол в радианах, от которого начинается дуга Отсчёт производится от самой правой точки окружности.

конечный угол — угол в радианах, до которого доходит дуга

направление — направление дуги. false — по часовой стрелке, true — против часовой. По умолчанию установлено false

Начальный и конечный углы указываются так:

Число пи в JavaScript можно получить с помощью свойства Math.PI .

Чтобы нарисовать полный круг, начальный угол можно указать 0, а конечный 2 пи.

Добавим на рисунок окружность.

45
46
47
48
49

ctx.strokeStyle = '#5F0070'; ctx.lineWidth = 1; ctx.beginPath(); ctx.arc(160, 120, 50, 0, 2*Math.PI); ctx.stroke();

Не обязательно для каждой дуги создавать свой контур. Внутри одного контура можно создать несколько дуг и несколько прямых линий. А потом применить метод arc() и нарисовать по контуру линии. Только цвет и стиль линий будет одинаковый. То же относится и к закрашенным фигурам.

Нарисуем закрашенную фигуру в виде половины круга:

ctx.fillStyle = '#B50F20'; ctx.beginPath(); ctx.arc(300, 150, 50, 0.5*Math.PI, 1.5*Math.PI, true); ctx.fill();

Попробуйте нарисовать дуги другой формы.

Метод arcTo() рисует дугу по двум касательным окружности. Касательные формируются по предыдущей точке контура и двум контрольным точкам.

arcTo(X1, Y1, X2, Y2, радиус)

X1 — координата X первой контрольной точки

Y1 — координата Y первой контрольной точки

X2 — координата X второй контрольной точки

Y2 — координата Y второй контрольной точки

радиус — радиус дуги

Касательные для дуги определяются так:

Первая касательная проводится через предыдущую точку контура и контрольную точку 1. Предыдущая точка контура — это точка, до которой дошло рисование контура перед созданием дуги. Если контур начинается с дуги, то перед этим нужно использовать метод moveTo() и таким образом создать предыдущую точку.

Вторая касательная проводится через контрольную точку 1 и контрольную точку 2.

По этим двум касательным проходит дуга. Пример:

58
59
60
61
62

ctx.beginPath(); ctx.moveTo(400, 200); ctx.arcTo(400, 150, 450, 150, 50); ctx.closePath(); ctx.stroke();

Кривые Безье

Кривая Безье — это линия, созданная по специальным базовым точкам. Она начинается на первой базовой точке и заканчивается на последней базовой точке. То есть, первая и последняя точки находятся на линии. А вот остальные, промежуточные точки часто находятся вне линии. Они «оттягивают» линию на себя, и происходит плавное искривление линии. Кривые Безье рассчитываются по математическим формулам. Но при создании изображений это не имеет значения. Для нас важно, что они позволяют рисовать плавные линии сложной формы.

Метод quadraticCurveTo() рисует квадратичную кривую Безье. «Квадратичная» означает, что она рисуется по трём точкам. Первая — это предыдущая точка контура. И ещё две точки указываются в параметрах. Если предыдущей точки контура нет, её нужно создать с помощью метода MoveTo() .

quadraticCurveTo(X2, Y2, X3, Y3)

X2 — координата X второй базовой точки

Y2 — координата Y второй базовой точки

X3 — координата X третьей базовой точки

Y3 — координата Y третьей базовой точки

ctx.beginPath(); ctx.moveTo(10, 190); ctx.quadraticCurveTo(200, 250, 230, 190); ctx.stroke();

Метод bezierCurveTo() рисует кубическую кривую Безье. Она создаётся по четырём точкам. Первой точкой также является предыдущая точка контура. Соответственно, в параметрах указывается три точки. Пример:

ctx.beginPath(); ctx.moveTo(250, 300); ctx.bezierCurveTo(300, 230, 350, 370, 400, 300); ctx.stroke();

Коприрование материалов сайта возможно только с согласия администрации

2017 — 2024 © basecourse.ru Все права защищены

Рисование фигур с помощью canvas

Теперь, установив наше окружение canvas, мы можем погрузиться в детали того, как рисовать в canvas. К концу этой статьи, вы научитесь рисовать прямоугольники, треугольники, линии, дуги и кривые, при условии что вы хорошо знакомы с основными геометрическими фигурами. Работа с путями весьма важна, когда рисуете объекты на canvas и мы увидим как это может быть сделано.

Сетка

Перед тем, как мы начнём рисовать, нам нужно поговорить о сетке canvas или координатной плоскости. Наш HTML каркас из предыдущей страницы включал в себя элемент canvas 150 пикселей в ширину и 150 пикселей в высоту. Справа можно увидеть этот canvas с сеткой, накладываемой по умолчанию. Обычно 1 единица на сетке соответствует 1 пикселю на canvas. Начало координат этой сетки расположено в верхнем левом углу в координате (0,0 ) . Все элементы размещены относительно этого начала. Таким образом, положение верхнего левого угла синего квадрата составляет х пикселей слева и у пикселей сверху, на координате (х, у) . Позже в этом уроке мы увидим, как можно перевести начало координат в другое место, вращать сетку и даже масштабировать её, но сейчас мы будем придерживаться настроек сетки по умолчанию.

Рисование прямоугольников

Сначала рассмотрим прямоугольник. Ниже представлены три функции рисования прямоугольников в canvas:

Рисование заполненного прямоугольника.

Рисование прямоугольного контура.

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

Каждая из приведённых функций принимает несколько параметров:

  • x, y устанавливают положение верхнего левого угла прямоугольника в canvas (относительно начала координат);
  • width (ширина) и height (высота) определяют размеры прямоугольника.

Ниже приведена функция draw(), использующая эти три функции.

Пример создания прямоугольных фигур

html> body onload="draw();"> canvas id="canvas" width="150" height="150">canvas> body> html> 
function draw()  var canvas = document.getElementById("canvas"); if (canvas.getContext)  var ctx = canvas.getContext("2d"); ctx.fillRect(25, 25, 100, 100); ctx.clearRect(45, 45, 60, 60); ctx.strokeRect(50, 50, 50, 50); > > 

Этот пример изображён ниже.

Функция fillRect() рисует большой чёрный квадрат со стороной 100 px. Функция clearRect() вырезает квадрат 60х60 из центра, а функция strokeRect() создаёт прямоугольный контур 50х50 пикселей внутри очищенного квадрата.

На следующей странице мы рассмотрим две альтернативы методу clearRect(), и также увидим, как можно изменять цвет и стиль контура отображаемых фигур.

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

Рисование контуров (path)

Остальные примитивные фигуры создаются контурами. Контур — это набор точек, которые, соединяясь в отрезки линий, могут образовывать различные фигуры, изогнутые или нет, разной ширины и разного цвета. Контур (или субконтур) может быть закрытым.

Создание фигур используя контуры происходит в несколько важных шагов:

  1. Сначала вы создаёте контур.
  2. Затем, используя команды рисования, рисуете контур.
  3. Потом закрываете контур.
  4. Созданный контур вы можете обвести или залить для его отображения.

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

Создаёт новый контур. После создания используется в дальнейшем командами рисования при построении контуров.

Методы для установки различных контуров объекта.

Закрывает контур, так что будущие команды рисования вновь направлены контекст.

Рисует фигуру с внешней обводкой.

Рисует фигуру с заливкой внутренней области.

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

Примечание: если текущий контур пуст (например, как после вызова beginPath() или на вновь созданном canvas), первой командой построения контура всегда является функция moveTo() . Поэтому мы всегда можем установить начальную позицию рисования контура после перезагрузки.

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

Третий и необязательный шаг — это вызов closePath() . Этот метод пытается закрыть фигуру, рисуя прямую линию из текущей точки в начальную. Если фигура была уже закрыта или является просто точкой, то функция ничего не делает.

Примечание: Когда вы вызываете fill() , то каждая открытая фигура закрывается автоматически, так что вы можете не использовать closePath() . Это обстоятельство не имеет место в случае вызова stroke() .

Рисование треугольника

Например, код для рисования треугольника будет выглядеть как-то так:

html> body onload="draw();"> canvas id="canvas" width="100" height="100">canvas> body> html> 
function draw()  var canvas = document.getElementById("canvas"); if (canvas.getContext)  var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.moveTo(75, 50); ctx.lineTo(100, 75); ctx.lineTo(100, 25); ctx.fill(); > > 

Результат выглядит так:

Передвижение пера

Одна очень полезная функция, которая ничего не рисует, но связана по смыслу с вышеописанными функциями — это moveTo() . Вы можете представить это как отрыв (подъем) пера от бумаги и его перемещение в другое место.

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

При инициализации canvas или при вызове beginPath() , вы захотите использовать функцию moveTo() для перемещения в точку начала рисования. Можно использовать moveTo() и для рисования несвязанного(незакрытого) контура. Посмотрите на смайлик ниже.

Вы можете проверить это сами, используя участок кода ниже. Просто вставьте в функцию draw() , рассмотренную ранее.

html> body onload="draw();"> canvas id="canvas" width="150" height="150">canvas> body> html> 
function draw()  var canvas = document.getElementById("canvas"); if (canvas.getContext)  var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.arc(75, 75, 50, 0, Math.PI * 2, true); // Внешняя окружность ctx.moveTo(110, 75); ctx.arc(75, 75, 35, 0, Math.PI, false); // рот (по часовой стрелке) ctx.moveTo(65, 65); ctx.arc(60, 65, 5, 0, Math.PI * 2, true); // Левый глаз ctx.moveTo(95, 65); ctx.arc(90, 65, 5, 0, Math.PI * 2, true); // Правый глаз ctx.stroke(); > > 

Результат этого ниже:

Если вы захотите увидеть соединение линии, то можете удалить вызов moveTo() .

Примечание: Подробнее о функции arc() ,посмотрите Дуги .

Линии

Для рисования прямых линий используйте метод lineTo() .

Рисует линию с текущей позиции до позиции, определённой x и y .

Этот метод принимает два аргумента x и y , которые являются координатами конечной точки линии. Начальная точка зависит от ранее нарисованных путей, причём конечная точка предыдущего пути является начальной точкой следующего и т. д. Начальная точка также может быть изменена с помощью метода moveTo() .

Пример ниже рисует два треугольника, один закрашенный и другой обведён контуром.

html> body onload="draw();"> canvas id="canvas" width="150" height="150">canvas> body> html> 
function draw()  var canvas = document.getElementById("canvas"); if (canvas.getContext)  var ctx = canvas.getContext("2d"); // Filled triangle ctx.beginPath(); ctx.moveTo(25, 25); ctx.lineTo(105, 25); ctx.lineTo(25, 105); ctx.fill(); // Stroked triangle ctx.beginPath(); ctx.moveTo(125, 125); ctx.lineTo(125, 45); ctx.lineTo(45, 125); ctx.closePath(); ctx.stroke(); > > 

Отрисовка начинается с вызова beginPath() , чтобы начать рисовать путь новой фигуры. Затем мы используем метод moveTo() , чтобы переместить начальную точку в нужное положение. Ниже рисуются две линии, которые образуют две стороны треугольника.

Вы заметите разницу между закрашенным и обведённым контуром треугольниками. Это, как упоминалось выше, из-за того, что фигуры автоматически закрываются, когда путь заполнен (т. е. закрашен), но не тогда, когда он очерчен (т. е. обведён контуром). Если бы мы не учли closePath() для очерченного треугольника, тогда только две линии были бы нарисованы, а не весь треугольник.

Дуги

Для рисования дуг и окружностей, используем методы arc() и arcTo().

Рисуем дугу с центром в точке (x,y) радиусом radius , начиная с угла startAngle и заканчивая в endAngle в направлении против часовой стрелки anticlockwise (по умолчанию по ходу движения часовой стрелки).

Рисуем дугу с заданными контрольными точками и радиусом, соединяя эти точки прямой линией.

Рассмотрим детальнее метод arc(), который имеет пять параметров: x и y — это координаты центра окружности, в которой должна быть нарисована дуга. radius — не требует пояснений. Углы startAngle и endAngle определяют начальную и конечную точки дуги в радианах вдоль кривой окружности. Отсчёт происходит от оси x. Параметр anticlockwise — логическое значение, которое, если true , то рисование дуги совершается против хода часовой стрелки; иначе рисование происходит по ходу часовой стрелки.

Примечание: Углы в функции arc() измеряют в радианах, не в градусах. Для перевода градусов в радианы вы можете использовать JavaScript-выражение: radians = (Math.PI/180)*degrees .

Следующий пример немного сложнее, чем мы рассматривали ранее. Здесь нарисованы 12 различных дуг с разными углами и заливками.

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

Координаты x и y должны быть достаточно ясны. radius and startAngle — фиксированы. endAngle начинается со 180 градусов (полуокружность) в первой колонке и, увеличиваясь с шагом 90 градусов, достигает кульминации полноценной окружностью в последнем столбце.

Установка параметра clockwise определяет результат; в первой и третьей строках рисование дуг происходит по часовой стрелке, а во второй и четвёртой — против часовой стрелки. Благодаря if-условию верхняя половина дуг образуется с контуром, (обводкой), а нижняя половина дуг — с заливкой.

Примечание: Этот пример требует немного большего холста (canvas), чем другие на этой странице: 150 x 200 pixels.

html> body onload="draw();"> canvas id="canvas" width="150" height="200">canvas> body> html> 
function draw()  var canvas = document.getElementById("canvas"); if (canvas.getContext)  var ctx = canvas.getContext("2d"); for (var i = 0; i  4; i++)  for (var j = 0; j  3; j++)  ctx.beginPath(); var x = 25 + j * 50; // x coordinate var y = 25 + i * 50; // y coordinate var radius = 20; // Arc radius var startAngle = 0; // Starting point on circle var endAngle = Math.PI + (Math.PI * j) / 2; // End point on circle var anticlockwise = i % 2 == 0 ? false : true; // clockwise or anticlockwise ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise); if (i > 1)  ctx.fill(); > else  ctx.stroke(); > > > > > 

Безье и квадратичные кривые

Следующим типом доступных контуров являются кривые Безье, и к тому же доступны в кубическом и квадратичном вариантах. Обычно они используются при рисовании сложных составных фигур.

Рисуется квадратичная кривая Безье с текущей позиции пера в конечную точку с координатами x и y , используя контрольную точку с координатами cp1x и cp1y .

Рисуется кубическая кривая Безье с текущей позиции пера в конечную точку с координатами x и y , используя две контрольные точки с координатами ( cp1x , cp1y ) и (cp2x, cp2y).

Различие между ними можно увидеть на рисунке, изображённом справа. Квадратичная кривая Безье имеет стартовую и конечную точки (синие точки) и всего одну контрольную точку (красная точка), в то время как кубическая кривая Безье использует две контрольные точки.

Параметры x и y в этих двух методах являются координатами конечной точки. cp1x и cp1y — координаты первой контрольной точки, а cp2x и cp2y — координаты второй контрольной точки.

Использование квадратичных или кубических кривых Безье может быть спорным выходом, так как в отличие от приложений векторной графики типа Adobe Illustrator, мы не имеем полной видимой обратной связи с тем, что мы делаем. Этот факт делает довольно сложным процесс рисования сложных фигур. В следующем примере мы нарисуем совсем простую составную фигуру, но, если у вас есть время и ещё больше терпения, можно создать более сложные составные фигуры.

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

Квадратичные кривые Безье

В этом примере многократно используются квадратичные кривые Безье для рисования речевой выноски.

html> body onload="draw();"> canvas id="canvas" width="150" height="150">canvas> body> html> 
function draw()  var canvas = document.getElementById("canvas"); if (canvas.getContext)  var ctx = canvas.getContext("2d"); // Quadratric curves example ctx.beginPath(); ctx.moveTo(75, 25); ctx.quadraticCurveTo(25, 25, 25, 62.5); ctx.quadraticCurveTo(25, 100, 50, 100); ctx.quadraticCurveTo(50, 120, 30, 125); ctx.quadraticCurveTo(60, 120, 65, 100); ctx.quadraticCurveTo(125, 100, 125, 62.5); ctx.quadraticCurveTo(125, 25, 75, 25); ctx.stroke(); > > 
Кубические кривые Безье

В этом примере нарисовано сердце с использованием кубических кривых Безье.

html> body onload="draw();"> canvas id="canvas" width="150" height="150">canvas> body> html> 
function draw()  var canvas = document.getElementById("canvas"); if (canvas.getContext)  var ctx = canvas.getContext("2d"); // Cubic curves example ctx.beginPath(); ctx.moveTo(75, 40); ctx.bezierCurveTo(75, 37, 70, 25, 50, 25); ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5); ctx.bezierCurveTo(20, 80, 40, 102, 75, 120); ctx.bezierCurveTo(110, 102, 130, 80, 130, 62.5); ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25); ctx.bezierCurveTo(85, 25, 75, 37, 75, 40); ctx.fill(); > > 

Прямоугольники

Все эти методы мы видели в Рисование прямоугольников, которые рисуют прямоугольники сразу в canvas, так же есть метод rect() , который не отображает, а только добавляет контур рисования (path) заданного прямоугольника к последнему открытому контуру.

Добавляет в path прямоугольник, верхний левый угол которого указан с помощью (x, y) с вашими width и height

Когда этот метод вызван, автоматически вызывается метод moveTo() с параметрами (x, y). Другими словами, позиция курсора устанавливается в начало добавленного прямоугольника.

Создание комбинаций

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

html> body onload="draw();"> canvas id="canvas" width="150" height="150">canvas> body> html> 
function draw()  var canvas = document.getElementById("canvas"); if (canvas.getContext)  var ctx = canvas.getContext("2d"); roundedRect(ctx, 12, 12, 150, 150, 15); roundedRect(ctx, 19, 19, 150, 150, 9); roundedRect(ctx, 53, 53, 49, 33, 10); roundedRect(ctx, 53, 119, 49, 16, 6); roundedRect(ctx, 135, 53, 49, 33, 10); roundedRect(ctx, 135, 119, 25, 49, 10); ctx.beginPath(); ctx.arc(37, 37, 13, Math.PI / 7, -Math.PI / 7, false); ctx.lineTo(31, 37); ctx.fill(); for (var i = 0; i  8; i++)  ctx.fillRect(51 + i * 16, 35, 4, 4); > for (i = 0; i  6; i++)  ctx.fillRect(115, 51 + i * 16, 4, 4); > for (i = 0; i  8; i++)  ctx.fillRect(51 + i * 16, 99, 4, 4); > ctx.beginPath(); ctx.moveTo(83, 116); ctx.lineTo(83, 102); ctx.bezierCurveTo(83, 94, 89, 88, 97, 88); ctx.bezierCurveTo(105, 88, 111, 94, 111, 102); ctx.lineTo(111, 116); ctx.lineTo(106.333, 111.333); ctx.lineTo(101.666, 116); ctx.lineTo(97, 111.333); ctx.lineTo(92.333, 116); ctx.lineTo(87.666, 111.333); ctx.lineTo(83, 116); ctx.fill(); ctx.fillStyle = "white"; ctx.beginPath(); ctx.moveTo(91, 96); ctx.bezierCurveTo(88, 96, 87, 99, 87, 101); ctx.bezierCurveTo(87, 103, 88, 106, 91, 106); ctx.bezierCurveTo(94, 106, 95, 103, 95, 101); ctx.bezierCurveTo(95, 99, 94, 96, 91, 96); ctx.moveTo(103, 96); ctx.bezierCurveTo(100, 96, 99, 99, 99, 101); ctx.bezierCurveTo(99, 103, 100, 106, 103, 106); ctx.bezierCurveTo(106, 106, 107, 103, 107, 101); ctx.bezierCurveTo(107, 99, 106, 96, 103, 96); ctx.fill(); ctx.fillStyle = "black"; ctx.beginPath(); ctx.arc(101, 102, 2, 0, Math.PI * 2, true); ctx.fill(); ctx.beginPath(); ctx.arc(89, 102, 2, 0, Math.PI * 2, true); ctx.fill(); > > // A utility function to draw a rectangle with rounded corners. function roundedRect(ctx, x, y, width, height, radius)  ctx.beginPath(); ctx.moveTo(x, y + radius); ctx.arcTo(x, y + height, x + radius, y + height, radius); ctx.arcTo(x + width, y + height, x + width, y + height - radius, radius); ctx.arcTo(x + width, y, x + width - radius, y, radius); ctx.arcTo(x, y, x, y + radius, radius); ctx.stroke(); > 

Конечное изображение выглядит так:

Мы не будем подробно останавливаться на том, так как это на самом деле удивительно просто. Наиболее важные вещи, которые следует отметить, это использование свойства fillStyle в контексте рисования и использование функции утилиты (в данном случае roundedRect() ). Использование функций утилиты для битов чертежа часто может быть очень полезным и сократить количество необходимого кода, а также его сложность.

Позже, в этом уроке, мы ещё раз рассмотрим fillStyle , но более подробно. Здесь же мы используем его для изменения цвета заливки путей вместо цвета по умолчанию от чёрного до белого, а затем обратно.

Path2D объекты

Как мы видели в последнем примере, есть серия путей и команд для рисования объектов на вашем холсте. Чтобы упростить код и повысить производительность, объект Path2D (en-US), доступный в последних версиях браузеров, позволяет вам кешировать или записывать эти команды рисования. Вы можете быстро запускать свои пути. Давайте посмотрим, как мы можем построить объект Path2D :

Конструктор Path2D() возвращает вновь созданный объект Path2D необязательно с другим путём в качестве аргумента (создаёт копию) или необязательно со строкой, состоящей из данных пути SVG path .

new Path2D(); // пустой path объект new Path2D(path); // копирование из другого path new Path2D(d); // path из SVG 

Все методы path , такие как moveTo , rect , arc , или quadraticCurveTo , и т.п, которые мы уже знаем, доступны для объектов Path2D

API Path2D также добавляет способ комбинирования путей с использованием метода addPath . Это может быть полезно, если вы хотите, например, создавать объекты из нескольких компонентов.

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

Path2D пример

В этом примере мы создаём прямоугольник и круг. Оба они сохраняются как объект Path2D , поэтому они доступны для последующего использования. С новым API Path2D несколько методов были обновлены, чтобы при необходимости принять объект Path2D для использования вместо текущего пути. Здесь stroke и fill используются с аргументом пути, например, для рисования обоих объектов на холст.

html> body onload="draw();"> canvas id="canvas" width="130" height="100">canvas> body> html> 
function draw()  var canvas = document.getElementById("canvas"); if (canvas.getContext)  var ctx = canvas.getContext("2d"); var rectangle = new Path2D(); rectangle.rect(10, 10, 50, 50); var circle = new Path2D(); circle.moveTo(125, 35); circle.arc(100, 35, 25, 0, 2 * Math.PI); ctx.stroke(rectangle); ctx.fill(circle); > > 

Использование SVG путей

Ещё одна мощная функция нового Canvas Path2D API использует данные пути SVG, SVG path data, для инициализации путей на вашем холсте. Это может позволить вам передавать данные пути и повторно использовать их как в SVG, так и в холсте.

Путь перемещается в точку ( M10 10 ), а затем горизонтально перемещается на 80 пунктов вправо ( h 80 ), затем на 80 пунктов вниз ( v 80 ), затем на 80 пунктов влево ( h -80 ), а затем обратно на start ( z ). Этот пример можно увидеть на странице Path2D constructor (en-US) .

var p = new Path2D("M10 10 h 80 v 80 h -80 Z"); 
  • « Предыдущая статья
  • Следующая статья »

Found a content problem with this page?

  • Edit the page on GitHub.
  • Report the content issue.
  • View the source on GitHub.

This page was last modified on 3 авг. 2023 г. by MDN contributors.

Your blueprint for a better internet.

Канва для всех: прямоугольники и пути

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

Одним из базовых методов, применяемых для рисования является fillRect, который рисует прямоугольник, залитый указанным цветом (по умолчанию — черным).

ctx.fillRect(50,50,100,100);

Этот код нарисует черный квадрат на канве:

fillRect нарисовал черный квадрат

fillRect нарисовал черный квадрат

С помощью этого метода можно рисовать не только квадраты, но и обычные прямоугольник. Достаточно лишь указать в параметрах х и у координату левой верхней вершины, ширину и высоту (ctx.fillRect(x0, y0, width, height); ).

Чтобы нарисовать прямоугольник не залитый каким-либо цветом, а лишь с прочерченными границами, следует использовать метод ctx.strokeRect:

ctx.strokeRect(50,50,100,100);

Этот метод принимает те же параметры, что и предыдущий. На канве будет изображен следующий рисунок:

Квадрат на canvas

Квадрат на canvas

Быстро, просто и удобно. Переходим дальше.

Уметь рисовать квадраты, конечно же, хорошо, но как быть, если нужно нарисовать треугольник? Или пятиугольник? Или еще более сложную фигуру? Тут на помощь нам приходят методы рисования «путей».

Вот они:
beginPath — начинает новый путь
moveTo — размещает точку для начала рисования пути
lineTo — рисует путь от точки, заданной с помощью moveTo до указанной в параметрах точки
closePath — закрывает путь, соединяя последнюю точку с первой
fill — заливает путь цветом
stroke — прочерчивает путь

Например, такой код:

ctx.beginPath(); ctx.moveTo(50,50); ctx.lineTo(50,250); ctx.lineTo(250,250); ctx.closePath(); ctx.fill();

Нарисует вот такой вот треугольник, залитый черным цветом:

Треугольник на canvas

Треугольник на canvas

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

Статья вам помогла?

HTML5 Canvas — интерактивные фигуры

Холст является незапоминаемой (non-retained) поверхностью рисования. Это означает, что холст не отслеживает выполняемые на нем операции рисования, он фиксирует лишь конечный результат этих операций — набор разноцветных пикселей, составляющих его содержимое.

Например, если нарисовать красный квадрат в центре холста методом stroke() или fill(), как только завершится выполнение этого метода, квадрат станет ничем иным, как блоком красных пикселов. Он может казаться вам квадратом, но холст не обладает информацией об этом.

Такой подход позволяет сделать процесс рисования быстрым, но он также усложняет задачу создания интерактивной графики. Допустим, что нам нужно разработать более интеллектуальную версию программы рисования, которую мы рассмотрели в статье «Создание простой программы рисования». В частности, мы хотим, чтобы кроме линий в ней также можно было бы рисовать прямоугольники. (Но это еще легко!)

Более того, мы хотим не только рисовать прямоугольники, но также и выбирать нарисованные прямоугольники, перетаскивать их на новое место, изменять их размеры, цвет и т.п. Но для того чтобы реализовать все эти возможности, нам нужно решить несколько проблем. Прежде всего, как нам узнать, что пользователь щелкнул на прямоугольнике? Потом, как нам узнать все подробности о данном прямоугольнике — его координаты, размер, цвет контура и заполнения? Наконец, как нам выяснить подробности обо всех прочих фигурах на холсте? Что нам необходимо знать, если мы хотим изменить прямоугольник и обновить холст?

Чтобы решить все эти проблемы и сделать холст интерактивным, нам нужно отслеживать все рисуемые на нем объекты. Потом, когда пользователь щелкнет в какой-либо точке холста, нужно определить, не попал ли он по одной из фигур. Этот процесс называется проверкой попадания (hit testing). Если мы можем решить эти две задачи, решение остальных — модифицирование фигуры и обновление холста соответствующим образом — будет легким.

Отслеживание нарисованного содержимого

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

Для простоты, программа рисует только отдельные круги разного размера и цвета. Чтобы отслеживать отдельный круг, нам нужно знать его позицию на холсте (т.е. координаты центра), радиус и цвет заливки. Вместо того чтобы создавать несколько десятков переменных для хранения всей этой информации, нужно хранить четыре типа данных в одном компактном пакете. Таким пакетом будет пользовательский объект (custom object).

Рассмотрим создание пользовательского объекта на случай, если вам никогда раньше не приходилось выполнять эту стандартную процедуру. Сначала создается функция с названием, отображающим тип нашего объекта. Например, функцию для создания пользовательского объекта для рисования круга можно назвать Circle():

function Circle()

Мы хотим, чтобы наш объект мог хранить данные. Это делается посредством создания свойств с помощью ключевого слова this. Например, чтобы определить свойство radius объекта круга, присваивается значение выражению this.radius.

Можно пойти далее и передавать параметры функции Circle(). Таким образом создание объекта круга и установка его свойств осуществляется в одном шаге. В следующем коде приводится пример функции Circle(), позволяющей устанавливать параметры:

// Пользовательский объект Circle function Circle(x, y, radius, color)

Свойство isSelected принимает значения true или false. Когда пользователь щелкает на круге, свойству isSelected присваивается значение true, вследствие чего код рисования знает, что у данного круга нужно нарисовать другой контур.

Объект круга с помощью этой версии функции Circle() можно создать посредством такого кода:

var myCircle = new Circle(0, 0, 20, "red");

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

// Этот массив хранит все окружности на холсте var circles = [];

Оставшийся код не представляет ничего сложного. Когда пользователь наживает кнопку «Добавить круг», чтобы создать новый круг, вызывается функция addRandomCircle(), которая создает новый круг произвольного размера и цвета в произвольном месте холста:

function addRandomCircle() < // Устанавливаем произвольный размер и позицию круга var radius = randomFromTo(10, 60); var x = randomFromTo(0, canvas.width); var y = randomFromTo(0, canvas.height); // Окрашиваем круг произвольным цветом var colors = ["green", "blue", "red", "yellow", "magenta", "orange", "brown", "purple", "pink"]; var color = colors[randomFromTo(0, 8)]; // Создаем новый круг var circle = new Circle(x, y, radius, color); // Сохраняем его в массиве circles.push(circle); // Обновляем отображение круга drawCircles(); >

В коде применяется пользовательская функция randomFromTo(), которая генерирует произвольные числа в заданном диапазоне:

function randomFromTo(from, to)

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

function drawCircles() < // Очистить холст context.clearRect(0, 0, canvas.width, canvas.height); // Перебираем все круги for(var i=0; ielse < context.lineWidth = 1; >context.fill(); context.stroke(); > >

Функция clearCanvas() очищает холст и использует для этого вызов drawCircles() с обнуленным массивом circles[]:

function clearCanvas() < // Очистить массив circles = []; // Очистить холст drawCircles(); >

Чтобы использовать функции addRandomCircle() и clearCanvas() добавьте в разметку две кнопки, обрабатывающие событие onclick:

  

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

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

Проверка попадания посредством сравнения координат

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

Сложные системы анимации (такие как предоставляемые Flash и Silverlight) облегчают работу разработчика и сами выполняют проверку попадания. Также существуют библиотеки расширения JavaScript для холста (например, Kinetic JS), направленные на предоставление таких удобств, но пока ни одна из них не является достаточно развитой, чтобы ее можно было порекомендовать для применения. Поэтому на данное время фанатам холста нужно разрабатывать собственную логику проверки попадания.

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

Первое, что нам требуется — это цикл для перебора всех фигур. Этот цикл должен перебирать объекты в массиве в обратном порядке — от конца к началу. Проверка начинается с конечного элемента массива (индекс которого равен общему числу объектов в массиве минус единица) и ведет отсчет в обратном направлении к первому элементу (индекс которого равен 0).

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

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

В данном примере веб-страница обрабатывает событие холста onclick, чтобы проверить попадание точки, в которой щелкнули, с кругом. Щелчок по холсту активизирует функцию canvasClick(), которая вычисляет координаты точки, в которой щелкнули, а потом проверяет, не находятся ли они внутри какого-либо круга:

window.onload = function() < // Определение контекста рисования canvas = document.getElementById("drawingCanvas"); context = canvas.getContext("2d"); canvas.onclick = canvasClick; >. var previousSelectedCircle; function canvasClick(e) < // Получаем координаты точки холста, в которой щелкнули var clickX = e.pageX - canvas.offsetLeft; var clickY = e.pageY - canvas.offsetTop; // Проверяем, щелкнули ли no кругу for(var i=circles.length-1; i>=0; i--) < var circle = circles[i]; // С помощью теоремы Пифагора вычисляем расстояние от // точки, в которой щелкнули, до центра текущего круга var distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2)) // Определяем, находится ли точка, в которой щелкнули, в данном круге if (distanceFromCenter > > 

Этот пример можно улучшить множеством разнообразных способов и сделать его более интеллектуальным. Например, можно добавить панель инструментов с командами для редактирования выбранного круга, чтобы изменить его цвет или удалить с холста. Или же можно добавить возможность перетаскивания выбранного круга с одного места холста в другое. Для этого нужно просто отслеживать холст на событие onMouseMove, изменить соответствующим образом координаты круга, а потом вызвать функцию drawCircles(), чтобы обновить холст с кругом в новом месте:

window.onload = function() < // Определение контекста рисования canvas = document.getElementById("drawingCanvas"); context = canvas.getContext("2d"); canvas.onmousedown = canvasClick; canvas.onmouseup = stopDragging; canvas.onmouseout = stopDragging; canvas.onmousemove = dragCircle; >. function canvasClick(e) < . if (distanceFromCenter > > var isDragging = false; function stopDragging() < isDragging = false; >function dragCircle(e) < // Проверка возможности перетаскивания if (isDragging == true) < // Проверка попадания if (previousSelectedCircle != null) < // Сохраняем позицию мыши var x = e.pageX - canvas.offsetLeft; var y = e.pageY - canvas.offsetTop; // Перемещаем круг в новую позицию previousSelectedCircle.x = x; previousSelectedCircle.y = y; // Обновляем холст drawCircles(); >> >

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *