diff options
author | Florian Merz <me@fiji-flo.de> | 2021-02-11 14:51:05 +0100 |
---|---|---|
committer | Florian Merz <me@fiji-flo.de> | 2021-02-11 14:51:05 +0100 |
commit | c058fa0fb22dc40ef0225b21a97578cddd0aaffa (patch) | |
tree | df20f8b4c724b61cb9c34cdb450a7ac77d690bd0 /files/ru/web/api/canvas_api/tutorial/drawing_shapes | |
parent | 8260a606c143e6b55a467edf017a56bdcd6cba7e (diff) | |
download | translated-content-c058fa0fb22dc40ef0225b21a97578cddd0aaffa.tar.gz translated-content-c058fa0fb22dc40ef0225b21a97578cddd0aaffa.tar.bz2 translated-content-c058fa0fb22dc40ef0225b21a97578cddd0aaffa.zip |
unslug ru: move
Diffstat (limited to 'files/ru/web/api/canvas_api/tutorial/drawing_shapes')
-rw-r--r-- | files/ru/web/api/canvas_api/tutorial/drawing_shapes/index.html | 582 |
1 files changed, 582 insertions, 0 deletions
diff --git a/files/ru/web/api/canvas_api/tutorial/drawing_shapes/index.html b/files/ru/web/api/canvas_api/tutorial/drawing_shapes/index.html new file mode 100644 index 0000000000..f6ca6c23ef --- /dev/null +++ b/files/ru/web/api/canvas_api/tutorial/drawing_shapes/index.html @@ -0,0 +1,582 @@ +--- +title: Рисование фигур с помощью canvas +slug: Web/API/Canvas_API/Tutorial/Рисование_фигур +translation_of: Web/API/Canvas_API/Tutorial/Drawing_shapes +--- +<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_usage", "Web/API/Canvas_API/Tutorial/Applying_styles_and_colors")}}</div> + +<div class="summary"> +<p>Теперь, установив наше <a href="/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_usage">окружение canvas</a>, мы можем погрузиться в детали того, как рисовать в canvas. К концу этой статьи, Вы научитесь рисовать прямоугольники, треугольники, линии, дуги и кривые, при условии что Вы хорошо знакомы с основными геометрическими фигурами. Работа с путями весьма важна, когда рисуете объекты на canvas и мы увидим как это может быть сделано.</p> +</div> + +<h2 id="Сетка">Сетка</h2> + +<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/224/Canvas_default_grid.png" style="float: right; height: 220px; width: 220px;">Перед тем, как мы начнем рисовать, нам нужно поговорить о сетке canvas или <strong>координатной плоскости</strong>. Наш HTML каркас из предыдущей страницы включал в себя элемент canvas 150 пикселей в ширину и 150 пикселей в высоту. Справа можно увидеть этот canvas <span class="short_text" id="result_box" lang="ru"><span class="hps">с сеткой</span><span>, накладываемой по умолчанию</span></span>. <span id="result_box" lang="ru"><span class="hps">Обычно 1 единица</span> <span class="hps">на сетке соответствует</span> <span class="hps">1 пикселю на</span></span> canvas. <span id="result_box" lang="ru"><span>Начало координат этой сетки</span> <span class="hps">расположено</span> <em><span class="hps">в верхнем левом</span> <span class="hps">углу</span></em> <span class="hps">в</span> <span class="atn hps">координате <code><em>(</em></code></span><span><code><em>0,0 )</em></code>.</span></span> <span id="result_box" lang="ru"><span class="hps">Все</span> <span class="hps">элементы размещены</span> <span class="hps">относительно</span> <span class="hps">этого</span> <span class="hps">начала</span><span>. </span><span class="hps">Так</span>им образом, <span class="hps">положение верхнего</span> <span class="hps">левого угла</span> <span class="hps">синего квадрата составляет</span> <code><em><span class="hps">х</span></em></code> <span class="hps">пикселей слева</span><span class="hps"> и</span> <code><em><span class="hps">у</span></em></code> <span class="hps">пикселей</span> <span class="hps">сверху,</span> <span class="hps">на</span> <span class="hps">координате <code><em>(х</em></code></span><span><code><em>, у)</em></code>.</span></span> <span id="result_box" lang="ru"><span class="hps">Позже в</span> <span class="hps">этом уроке мы</span> <span class="hps">увидим, как</span> <span class="hps">можно</span> <span class="hps">перевести</span> <span class="hps">начало координат</span> <span class="hps">в другое место</span><span>,</span> <span class="hps">вращать сетку</span> <span class="hps">и даже</span> <span class="hps">масштабировать ее</span><span>, но сейчас</span> <span class="hps">мы будем придерживаться</span> <span class="hps">настроек сетки по умолчанию.</span></span></p> + +<h2 id="Рисование_прямоугольников">Рисование прямоугольников</h2> + +<p>В отличие от {{Glossary("SVG")}}, {{HTMLElement("canvas")}} поддерживает только одну примитивную фигуру: прямоугольник. Все другие фигуры должны быть созданы комбинацией одного или большего количества контуров (paths), набором точек, соединенных в линии. К счастью в ассортименте рисования контуров у нас есть функции, которые делают возможным составление очень сложных фигур.</p> + +<p>Сначала рассмотрим прямоугольник. Ниже представлены три функции рисования прямоугольников в canvas:</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.fillRect", "fillRect(x, y, width, height)")}}</dt> + <dd>Рисование заполненного прямоугольника.</dd> + <dt>{{domxref("CanvasRenderingContext2D.strokeRect", "strokeRect(x, y, width, height)")}}</dt> + <dd>Рисование прямоугольного контура.</dd> + <dt>{{domxref("CanvasRenderingContext2D.clearRect", "clearRect(x, y, width, height)")}}</dt> + <dd>Очистка прямоугольной области, делая содержимое совершенно прозрачным.</dd> +</dl> + +<p>Каждая из приведенных функций принимает несколько параметров: </p> + +<ul> + <li><em>x</em>, <font face="Consolas, Liberation Mono, Courier, monospace"><em>y</em></font> устанавливают положение верхнего левого угла прямоугольника в canvas (относительно начала координат);</li> + <li><code><em>width</em></code>(ширина) и <code><em><em>height</em></em></code>(высота) определяют размеры прямоугольника.</li> +</ul> + +<p>Ниже приведена функция draw(), использующая эти три функции.</p> + +<h3 id="Пример_создания_прямоугольных_фигур">Пример создания прямоугольных фигур</h3> + +<div class="hidden"> +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js notranslate">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); + } +}</pre> + +<p>Этот пример изображен ниже.</p> + +<p>{{EmbedLiveSample("Пример_создания_прямоугольных_фигур", 160, 160, "https://mdn.mozillademos.org/files/245/Canvas_rect.png")}}</p> + +<p>Функция fillRect() рисует большой чёрный квадрат со стороной 100 px. Функция clearRect() вырезает квадрат 60х60 из центра, а функция strokeRect() создает прямоугольный контур 50х50 пикселей внутри очищенного квадрата.</p> + +<p>На следующей странице мы рассмотрим две альтернативы методу clearRect(), и также увидим, как можно изменять цвет и стиль контура отображаемых фигур.</p> + +<p>В отличие от функций создания контуров, которые будут рассмотрены в следующем разделе, все три функции создания прямоугольника сразу же отображаются на canvas.</p> + +<h2 id="Рисование_контуров_path">Рисование контуров (path)</h2> + +<p>Остальные примитивные фигуры создаются <em>контурами</em>. Контур - это набор точек, которые, соединяясь в отрезки линий, могут образовывать различные фигуры, изогнутые или нет, разной ширины и разного цвета. Контур (или субконтур) может быть закрытым.</p> + +<p>Создание фигур используя контуры происходит в несколько важных шагов:</p> + +<ol> + <li>Сначала вы создаете контур.</li> + <li>Затем, используя <a href="/en-US/docs/Web/API/CanvasRenderingContext2D#Paths">команды рисования</a>, рисуете контур.</li> + <li>Потом закрываете контур.</li> + <li>Созданный контур вы можете обвести или залить для его отображения.</li> +</ol> + +<p>Здесь приведены функции, которые можно использовать в описанных шагах:</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.beginPath", "beginPath()")}}</dt> + <dd>Создает новый контур. После создания используется в дальнейшем командами рисования при построении контуров.</dd> + <dt><a href="/en-US/docs/Web/API/CanvasRenderingContext2D#Paths">Path методы</a></dt> + <dd>Методы для установки различных контуров объекта.</dd> + <dt>{{domxref("CanvasRenderingContext2D.closePath", "closePath()")}}</dt> + <dd><span id="result_box" lang="ru"><span class="hps">Закрывает контур</span><span>, так что</span> <span class="hps">будущие</span> <span class="hps">команды рисования</span> <span class="hps">вновь</span> <span class="hps">направлены</span> <span class="hps">контекст</span><span>.</span></span></dd> + <dt>{{domxref("CanvasRenderingContext2D.stroke", "stroke()")}}</dt> + <dd>Рисует фигуру с внешней обводкой.</dd> + <dt>{{domxref("CanvasRenderingContext2D.fill", "fill()")}}</dt> + <dd>Рисует фигуру с заливкой внутренней области.</dd> +</dl> + +<p>Первый шаг создания контура заключается в вызове функции <strong><code>beginPath()</code></strong>. Внутри содержатся контуры в виде набора суб-контуров (линии, дуги и др.), которые вместе образуют форму фигуры. Каждый вызов этого метода очищает набор, и мы можем начинать рисовать новые фигуры.</p> + +<div class="note"><strong>Note:</strong> если текущий контур пуст (например, как после вызова <code>beginPath() </code>или на вновь созданном canvas), первой командой построения контура всегда является функция <strong><code>moveTo()</code></strong>. Поэтому мы всегда можем установить начальную позицию рисования контура после перезагрузки.</div> + +<p>Вторым шагом является вызов методов, определяемых видом контура, который нужно нарисовать. Их мы рассмотрим позднее.</p> + +<p>Третий и необязательный шаг - это вызов <strong><code>closePath()</code></strong>. Этот метод пытается закрыть фигуру, рисуя прямую линию из текущей точки в начальную. Если фигура была уже закрыта или является просто точкой, то функция ничего не делает.</p> + +<div class="note"><strong>Note:</strong> Когда вы вызываете <strong><code>fill()</code></strong>, то каждая открытая фигура закрывается автоматически, так что вы можете не использовать <code>closePath()</code>. Это обстоятельство не имеет место в случае вызова <code>stroke()</code>.</div> + +<h3 id="Рисование_треугольника">Рисование треугольника</h3> + +<p>Например, код для рисования треугольника будет выглядеть как-то так:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="100" height="100"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js notranslate">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(); + } +} +</pre> + +<p>Результат выглядит так:</p> + +<p>{{EmbedLiveSample("Рисование_треугольника", 110, 110, "https://mdn.mozillademos.org/files/9847/triangle.png")}}</p> + +<h3 id="Передвижение_пера">Передвижение пера</h3> + +<p>Одна очень полезная функция, которая ничего не рисует, но связана по смыслу с вышеописанными функциями - это <strong><code>moveTo()</code></strong>. Вы можете представить это как отрыв (подъем) пера от бумаги и его перемещение в другое место.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.moveTo", "moveTo(x, y)")}}</dt> + <dd>Перемещает перо в точку с координатами x и y.</dd> +</dl> + +<p>При инициализации canvas или при вызове <code>beginPath()</code>, вы захотите использовать функцию <code>moveTo()</code> для перемещения в точку начала рисования. Можно использовать <code>moveTo()</code> и для рисования несвязанного(незакрытого) контура. Посмотрите на смайлик ниже.</p> + +<p>Вы можете проверить это сами, используя участок кода ниже. Просто вставьте в функцию <code>draw()</code>, рассмотренную ранее.</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight:[8,10,12] notranslate">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(); + } +} +</pre> + +<p>Результат этого ниже:</p> + +<p>{{EmbedLiveSample("Передвижение_пера", 160, 160, "https://mdn.mozillademos.org/files/252/Canvas_smiley.png")}}</p> + +<p>Если вы захотите увидеть соединные линии, то можете удалить вызов <code>moveTo()</code>.</p> + +<div class="note"> +<p><strong>Note:</strong> Подробнее о функции <code>arc()</code>,посмотрите {{anch("Дуги")}} .</p> +</div> + +<h3 id="Линии">Линии</h3> + +<p>Для рисования прямых линий используйте метод <code>lineTo()</code>.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.lineTo", "lineTo(x, y)")}}</dt> + <dd>Рисует линию с текущей позиции до позиции, определенной <code>x и y</code>.</dd> +</dl> + +<p><span id="result_box" lang="ru"><span class="hps">Этот метод принимает</span> <span class="hps">два аргумента</span> </span><code><em>x</em><span lang="ru"><span class="hps"> и </span></span><em>y</em></code><span lang="ru"><span>, которые являются</span> <span class="hps">координатами конечной</span> <span class="hps">точки линии</span><span>.</span></span> <span id="result_box" lang="ru"><span>Начальная точка зависит</span> <span class="hps">от</span> <span class="hps">ранее</span> <span class="hps">нарисованных путей, причём</span> <span class="hps">конечная точка</span> <span class="hps">предыдущего пути является</span> начальной <span class="hps">точкой следующего</span> <span class="hps">и т. д.</span> <span class="hps">Начальная точка также</span> <span class="hps">может быть изменена</span> <span class="hps">с помощью метода</span></span> <code>moveTo()</code>.</p> + +<p>Пример ниже рисует два треугольника, один закрашенный и другой обведен контуром.</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight[9,10,16,17] notranslate">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(); + } +} +</pre> + +<p><span id="result_box" lang="ru"><span class="hps">Отрисовка начинается с вызова</span> </span><code>beginPath()</code><span lang="ru"><span>, чтобы начать</span> <span class="hps">рисовать путь новой фигуры</span><span>.</span></span> <span id="result_box" lang="ru"><span class="hps">Затем мы используем</span> <span class="hps">метод</span> </span><code>moveTo()</code><span lang="ru"><span>, чтобы переместить</span> <span class="hps">начальную точку</span> <span class="hps">в нужное положение</span><span>.</span> <span class="hps">Ниже</span> <span class="hps">рисуются две линии</span><span>, которые образуют две</span> <span class="hps">стороны треугольника</span><span>.</span></span></p> + +<p>{{EmbedLiveSample("Линии", 160, 160, "https://mdn.mozillademos.org/files/238/Canvas_lineTo.png")}}</p> + +<p><span id="result_box" lang="ru"><span class="hps">Вы заметите</span> <span class="hps">разницу между</span> <span class="hps">закрашенным</span> <span class="hps">и обведенным контуром</span> <span class="hps">треугольниками.</span> <span class="hps">Это, </span><span class="hps">как упоминалось выше</span><span>,</span> <span class="hps">из-за</span> того, что <span class="hps">фигуры</span> <span class="hps">автоматически закрываются</span><span>, когда</span> <span class="hps">путь</span> <span class="hps">заполнен (т. е. закрашен)</span><span>, но</span> <span class="hps">не тогда, когда</span> <span class="hps">он очерчен (т. е. обведен контуром)</span><span>.</span></span> <span id="result_box" lang="ru"><span class="hps">Если бы мы</span> <span class="hps">не учли</span> </span><code>closePath()</code><span lang="ru"> <span class="hps">для</span> очерченного <span class="hps">треугольника</span><span>,</span> тогда <span class="hps">только две линии</span> <span class="hps">были бы</span> <span class="hps">нарисованы,</span> <span class="hps">а не</span> <span class="hps">весь треугольник</span><span>.</span></span></p> + +<h3 id="Дуги">Дуги</h3> + +<p>Для рисования дуг и окружностей, используем методы arc() и arcTo().</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.arc", "arc(x, y, radius, startAngle, endAngle, anticlockwise)")}}</dt> + <dd>Рисуем дугу с центром в точке <code><em>(x,y)</em></code> радиусом <code><em>radius</em></code>, начиная с угла <em><code>startAngle </code>и заканчивая в </em><em><code>endAngle </code>в направлении против часовой стрелки <code>anticlockwise</code></em><code> </code>(по умолчанию по ходу движения часовой стрелки).</dd> + <dt>{{domxref("CanvasRenderingContext2D.arcTo", "arcTo(x1, y1, x2, y2, radius)")}}</dt> + <dd>Рисуем дугу с заданными контрольными точками и радиусом, соединяя эти точки прямой линией.</dd> +</dl> + +<p>Рассмотрим детальнее метод <em>arc()</em>, который имеет пять параметров: <em><code>x</code></em> и <em><code>y</code></em> — это координаты центра окружности, в которой должна быть нарисована дуга. <em><code>radius</code></em> — не требует пояснений. Углы <code>startAngle</code> и <code>endAngle</code> определяют начальную и конечную точки дуги в радианах вдоль кривой окружности. Отсчет происходит от оси x. Параметр <code>anticlockwise</code> — логическое значение, которое, если <code>true</code>, то рисование дуги совершается против хода часовой стрелки; иначе рисование происходит по ходу часовой стрелки.</p> + +<div class="note"> +<p><strong>Note</strong>: Углы в функции arc() измеряют в радианах, не в градусах. Для перевода градусов в радианы вы можете использовать JavaScript-выражение: <code>radians = (Math.PI/180)*degrees</code>.</p> +</div> + +<p>Следующий пример немного сложнее, чем мы рассматривали ранее. Здесь нарисованы 12 различных дуг с разными углами и заливками.</p> + +<p>Два <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for"><code>for</code> цикла</a> размещают дуги по столбцам и строкам. Для каждой дуги, мы начинаем новый контур, вызывая <em><code>beginPath()</code></em>. В этом коде каждый параметр дуги для большей ясности задан в виде переменной, но вам не обязательно делать так в реальных проектах.</p> + +<p>Координаты <code>x</code> и <code>y</code> должны быть достаточно ясны. <code>radius</code> and <code>startAngle</code> — фиксированы. <code>endAngle</code> начинается со 180 градусов (полуокружность) в первой колонке и, увеличиваясь с шагом 90 градусов, достигает кульминации полноценной окружностью в последнем столбце.</p> + +<p>Установка параметра <code>clockwise</code> определяет результат; в первой и третьей строках рисование дуг происходит по часовой стрелке, а во второй и четвертой - против часовой стрелки. Благодаря if-условию верхняя половина дуг образуется с контуром, (обводкой), а нижняя половина дуг - с заливкой.</p> + +<div class="note"> +<p><strong>Note:</strong> Этот пример требует немного большего холста (canvas), чем другие на этой странице: 150 x 200 pixels.</p> +</div> + +<div class="hidden"> +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="200"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight[16] notranslate">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(); + } + } + } + } +} +</pre> + +<p>{{EmbedLiveSample("Дуги", 160, 210, "https://mdn.mozillademos.org/files/204/Canvas_arc.png")}}</p> + +<h3 id="Безье_и_квадратичные_кривые">Безье и квадратичные кривые</h3> + +<p>Следующим типом доступных контуров являются <a class="external" href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve" rel="external" title="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">кривые Безье</a>, и к тому же доступны в кубическом и квадратичном вариантах. Обычно они используются при рисовании сложных составных фигур.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.quadraticCurveTo", "quadraticCurveTo(cp1x, cp1y, x, y)")}}</dt> + <dd>Рисуется квадратичная кривая Безье с текущей позиции пера в конечную точку с координатами <code>x</code> и <code>y</code>, используя контрольную точку с координатами <code>cp1x</code> и <code>cp1y</code>.</dd> + <dt>{{domxref("CanvasRenderingContext2D.bezierCurveTo", "bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)")}}</dt> + <dd>Рисуется кубическая кривая Безье с текущей позиции пера в конечную точку с координатами <code>x</code> и <code>y</code>, используя две контрольные точки с координатами (<code>cp1x</code>, <code>cp1y</code>) и (cp2x, cp2y).</dd> +</dl> + +<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/223/Canvas_curves.png" style="float: right; height: 190px; width: 190px;">Различие между ними можно увидеть на рисунке, изображенном справа. Квадратичная кривая Безье имеет стартовую и конечную точки (синие точки) и всего одну контрольную точку (красная точка), в то время как кубическая кривая Безье использует две контрольные точки.</p> + +<p>Параметры <code>x</code> и <code>y</code> в этих двух методах являются координатами конечной точки. <code>cp1x</code> и <code>cp1y</code> — координаты первой контрольной точки, а <code>cp2x</code> и <code>cp2y</code> — координаты второй контрольной точки.</p> + +<p>Использование квадратичных или кубических кривых Безье может быть спорным выходом, так как в отличие от приложений векторной графики типа Adobe Illustrator, мы не имеем полной видимой обратной связи с тем, что мы делаем. Этот факт делает довольно сложным процесс рисования сложных фигур. В следующем примере мы нарисуем совсем простую составную фигуру, но, если у вас есть время и ещё больше терпения, можно создать более сложные составные фигуры.</p> + +<p>В этом примере нет ничего слишком тяжелого. В обоих случаях мы видим последовательность кривых, рисуя которые, в результате получим составную фигуру.</p> + +<h4 id="Квадратичные_кривые_Безье">Квадратичные кривые Безье</h4> + +<p>В этом примере многократно используются квадратичные кривые Безье для рисования речевой выноски.</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight[9,10,11,12,13,14] notranslate">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(); + } +} +</pre> + +<p>{{EmbedLiveSample("Квадратичные_кривые_Безье", 160, 160, "https://mdn.mozillademos.org/files/243/Canvas_quadratic.png")}}</p> + +<h4 id="Кубические_кривые_Безье">Кубические кривые Безье</h4> + +<p>В этом примере нарисовано сердце с использованием кубических кривых Безье.</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight[9,10,11,12,13,14] notranslate">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(); + } +} +</pre> + +<p>{{EmbedLiveSample("Cubic_Bezier_curves", 160, 160, "https://mdn.mozillademos.org/files/207/Canvas_bezier.png")}}</p> + +<h3 id="Прямоугольники">Прямоугольники</h3> + +<p>Все эти методы мы видели в {{anch("Рисование прямоугольников")}}, которые рисуют прямоугольники сразу в canvas, так же есть метод <code>rect()</code>, который не отображает, а только добавляет контур рисования (path) заданного прямоугольника к последнему открытому контуру.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.rect", "rect(x, y, width, height)")}}</dt> + <dd><br> + Добавляет в path прямоугольник, верхний левый угол которого указан с помощью (x, y) с вашими width и height</dd> + <dt></dt> +</dl> + +<p>Когда этот метод вызван, автоматически вызывается метод moveTo() с параметрами (x, y). Другими словами, позиция курсора устанавливается в начало добавленного прямоугольника.</p> + +<h3 id="Создание_комбинаций">Создание комбинаций</h3> + +<p>До сих пор, в каждом примере использовался только один тип функции контуров для каждой фигуры.<br> + Однако, нет никаких ограничений на количество или типы контуров, которые вы можете использовать для создания фигур. Давайте в этом примере объединим все вышеперечисленные функции контуров, чтобы создать набор очень известных игровых персонажей.</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js notranslate">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.lineTo(x,y+height-radius); + ctx.quadraticCurveTo(x,y+height,x+radius,y+height); + ctx.lineTo(x+width-radius,y+height); + ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius); + ctx.lineTo(x+width,y+radius); + ctx.quadraticCurveTo(x+width,y,x+width-radius,y); + ctx.lineTo(x+radius,y); + ctx.quadraticCurveTo(x,y,x,y+radius); + ctx.stroke(); +} +</pre> + +<p>Конечное изображение выглядит так:</p> + +<p>{{EmbedLiveSample("Создание_комбинаций", 160, 160, "https://mdn.mozillademos.org/files/9849/combinations.png")}}</p> + +<p>Мы не будем подробно останавливаться на том, так как это на самом деле удивительно просто. Наиболее важные вещи, которые следует отметить, это использование свойства <code>fillStyle</code> в контексте рисования и использование функции утилиты (в данном случае <code>roundedRect()</code>). Использование функций утилиты для битов чертежа часто может быть очень полезным и сократить количество необходимого кода, а также его сложность.</p> + +<p>Позже, в этом уроке, мы еще раз рассмотрим <code>fillStyle</code>, но более подробно. Здесь же мы используем его для изменения цвета заливки путей вместо цвета по умолчанию от черного до белого, а затем обратно.</p> + +<h2 id="Path2D_объекты">Path2D объекты</h2> + +<p>Как мы видели в последнем примере, есть серия путей и команд для рисования объектов на вашем холсте. Чтобы упростить код и повысить производительность, объект {{domxref("Path2D")}}, доступный в последних версиях браузеров, позволяет вам кэшировать или записывать эти команды рисования. Вы можете быстро запускать свои пути.<br> + Давайте посмотрим, как мы можем построить объект <code>Path2D</code> :</p> + +<dl> + <dt>{{domxref("Path2D.Path2D", "Path2D()")}}</dt> + <dd>Конструктор <code><strong>Path2D()</strong></code> возвращает вновь созданный объект <code>Path2D</code> необязательно с другим путем в качестве аргумента (создает копию) или необязательно со строкой, состоящей из данных пути <a href="/en-US/docs/Web/SVG/Tutorial/Paths">SVG path</a> .</dd> +</dl> + +<pre class="brush: js notranslate">new Path2D(); // пустой path объект +new Path2D(path); // копирование из другого path +new Path2D(d); // path из SVG</pre> + +<p>Все <a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D#Paths">методы path</a> , такие как <code>moveTo</code>, <code>rect</code>, <code>arc</code>, или <code>quadraticCurveTo</code>, итп, которые мы уже знаем, доступны для объектов <code>Path2D</code></p> + +<p>API <code>Path2D</code> также добавляет способ комбинирования путей с использованием метода <code>addPath</code>. Это может быть полезно, если вы хотите, например, создавать объекты из нескольких компонентов.</p> + +<dl> + <dt>{{domxref("Path2D.addPath", "Path2D.addPath(path [, transform])")}}</dt> + <dd>Добавляет путь к текущему пути с необязательной матрицей преобразования.</dd> +</dl> + +<h3 id="Path2D_пример">Path2D пример</h3> + +<p>В этом примере мы создаем прямоугольник и круг. Оба они сохраняются как объект <code>Path2D</code>, поэтому они доступны для последующего использования. С новым API <code>Path2D</code> несколько методов были обновлены, чтобы при необходимости принять объект <code>Path2D</code> для использования вместо текущего пути. Здесь <code>stroke</code> и <code>fill</code> используются с аргументом пути, например, для рисования обоих объектов на холст.</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="130" height="100"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight[6,9] notranslate">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); + } +} +</pre> + +<p>{{EmbedLiveSample("Path2D_example", 130, 110, "https://mdn.mozillademos.org/files/9851/path2d.png")}}</p> + +<h3 id="Использование_SVG_путей">Использование SVG путей</h3> + +<p>Еще одна мощная функция нового Canvas <code>Path2D</code> API использует данные пути SVG, <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths">SVG path data</a>, для инициализации путей на вашем холсте. Это может позволить вам передавать данные пути и повторно использовать их как в SVG, так и в холсте.</p> + +<p>Путь перемещается в точку (<code>M10 10</code>), а затем горизонтально перемещается на 80 пунктов вправо (<code>h 80</code>), затем на 80 пунктов вниз (<code>v 80</code>), затем на 80 пунктов влево (<code>h -80</code>), а затем обратно на start (<code>z</code>). <br> + Этот пример можно увидеть на странице <a href="/en-US/docs/Web/API/Path2D.Path2D#Using_SVG_paths"><code>Path2D</code> constructor</a>.</p> + +<pre class="brush: js; notranslate">var p = new Path2D("M10 10 h 80 v 80 h -80 Z");</pre> + +<div>{{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_usage", "Web/API/Canvas_API/Tutorial/Applying_styles_and_colors")}}</div> |