aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/api/canvas_api/tutorial/transformations
diff options
context:
space:
mode:
authorPeter Bengtsson <mail@peterbe.com>2020-12-08 14:42:52 -0500
committerPeter Bengtsson <mail@peterbe.com>2020-12-08 14:42:52 -0500
commit074785cea106179cb3305637055ab0a009ca74f2 (patch)
treee6ae371cccd642aa2b67f39752a2cdf1fd4eb040 /files/ru/web/api/canvas_api/tutorial/transformations
parentda78a9e329e272dedb2400b79a3bdeebff387d47 (diff)
downloadtranslated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.gz
translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.bz2
translated-content-074785cea106179cb3305637055ab0a009ca74f2.zip
initial commit
Diffstat (limited to 'files/ru/web/api/canvas_api/tutorial/transformations')
-rw-r--r--files/ru/web/api/canvas_api/tutorial/transformations/index.html275
1 files changed, 275 insertions, 0 deletions
diff --git a/files/ru/web/api/canvas_api/tutorial/transformations/index.html b/files/ru/web/api/canvas_api/tutorial/transformations/index.html
new file mode 100644
index 0000000000..0f871d6909
--- /dev/null
+++ b/files/ru/web/api/canvas_api/tutorial/transformations/index.html
@@ -0,0 +1,275 @@
+---
+title: Transformations
+slug: Web/API/Canvas_API/Tutorial/Transformations
+translation_of: Web/API/Canvas_API/Tutorial/Transformations
+---
+<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Using_images", "Web/API/Canvas_API/Tutorial/Compositing")}}</div>
+
+<div class="summary"><span class="notranslate">Ранее в этом уроке мы узнали о</span> <span class="notranslate" style="background-color: #e6ecf9;"> <a href="https://translate.googleusercontent.com/translate_c?act=url&amp;depth=1&amp;hl=ru&amp;ie=UTF8&amp;prev=_t&amp;rurl=translate.google.com&amp;sl=en&amp;sp=nmt4&amp;tl=ru&amp;u=https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes&amp;usg=ALkJrhiuWce927wE2920fN95Jlcrf1HyUg">сетке холста</a></span> <span class="notranslate">и <strong>координатном пространстве</strong> .</span> <span class="notranslate"> До сих пор мы использовали только сетку по умолчанию и изменили размер всего холста для наших нужд.</span> При преобразованиях существуют более мощные способы изменения исходных координат в различные положение, поворот сетки и даже масштабирование.</div>
+
+<h2 id="Saving_and_restoring_state" name="Saving_and_restoring_state"><span class="notranslate" style="background-color: #e6ecf9;">Сохранение и восстановление состояния</span></h2>
+
+<p><span class="notranslate">Прежде чем перейти к методам преобразования, давайте рассмотрим два других метода, которые необходимы, когда вы начинаете создавать все более сложные рисунки.</span></p>
+
+<dl>
+ <dt>{{domxref("CanvasRenderingContext2D.save", "save()")}}</dt>
+ <dd><span class="notranslate">Сохраняет все состояние холста.</span></dd>
+ <dt>{{domxref("CanvasRenderingContext2D.restore", "restore()")}}</dt>
+ <dd><span class="notranslate">Восстанавливает последнее сохраненное состояние холста.</span></dd>
+</dl>
+
+<p>Состояние холста сохраняется в стеке. Каждый раз, когда вызывается метод <code>save()</code>, текущее состояние отрисовки записывается в стек. Состояние отрисовки содержит:</p>
+
+<ul>
+ <li>Трансформации, которые были применены (например, <code>translate</code>, <code>rotate</code> and <code>scale</code> – см. ниже).</li>
+ <li>Текущее значение следующих атрибутов: {{domxref("CanvasRenderingContext2D.strokeStyle", "strokeStyle")}}, {{domxref("CanvasRenderingContext2D.fillStyle", "fillStyle")}}, {{domxref("CanvasRenderingContext2D.globalAlpha", "globalAlpha")}}, {{domxref("CanvasRenderingContext2D.lineWidth", "lineWidth")}}, {{domxref("CanvasRenderingContext2D.lineCap", "lineCap")}}, {{domxref("CanvasRenderingContext2D.lineJoin", "lineJoin")}}, {{domxref("CanvasRenderingContext2D.miterLimit", "miterLimit")}}, {{domxref("CanvasRenderingContext2D.lineDashOffset", "lineDashOffset")}}, {{domxref("CanvasRenderingContext2D.shadowOffsetX", "shadowOffsetX")}}, {{domxref("CanvasRenderingContext2D.shadowOffsetY", "shadowOffsetY")}}, {{domxref("CanvasRenderingContext2D.shadowBlur", "shadowBlur")}}, {{domxref("CanvasRenderingContext2D.shadowColor", "shadowColor")}}, {{domxref("CanvasRenderingContext2D.globalCompositeOperation", "globalCompositeOperation")}}, {{domxref("CanvasRenderingContext2D.font", "font")}}, {{domxref("CanvasRenderingContext2D.textAlign", "textAlign")}}, {{domxref("CanvasRenderingContext2D.textBaseline", "textBaseline")}}, {{domxref("CanvasRenderingContext2D.direction", "direction")}}, {{domxref("CanvasRenderingContext2D.imageSmoothingEnabled", "imageSmoothingEnabled")}}.</li>
+ <li>Текущее значение границ вырезанного холста (<a href="/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing#Clipping_paths">clipping path</a>), которые будут рассматриваться в следующем разделе.</li>
+</ul>
+
+<p>Вы можете вызывать метод <code>save()</code> столько раз, сколько захотите. В то же время, при вызове метода <code>restore()</code> последнее сохранённое состояние будет считано из стека, и все сохранённые настройки будут восстановлены.</p>
+
+<h3 id="A_save_and_restore_canvas_state_example" name="A_save_and_restore_canvas_state_example">Пример <font face="consolas, Liberation Mono, courier, monospace">сохранения и восстановления</font> состояния холста</h3>
+
+<p>Здесь показано, как функционирует сохранение в стек состояния отрисовки на примере последовательной отрисовки набора прямоугольников.</p>
+
+<pre class="brush: js; highlight:[5,10,15,18] notranslate">function draw() {
+ var ctx = document.getElementById('canvas').getContext('2d');
+
+ ctx.fillRect(0, 0, 150, 150); // рисуем прямоугольник с настройками по умолчанию
+ ctx.save(); // сохраняем состояние
+
+ ctx.fillStyle = '#09F'; // вносим изменения в настройки
+ ctx.fillRect(15, 15, 120, 120); // рисуем прямоугольник с новыми настройками
+ ctx.save(); // сохраняем состояние
+
+ ctx.fillStyle = '#FFF'; // вносим изменения в настройки
+ ctx.globalAlpha = 0.5;
+ ctx.fillRect(30, 30, 90, 90); // рисуем прямоугольник с новыми настройками
+
+ ctx.restore(); // возвращаемся к предыдущим настройкам
+ ctx.fillRect(45, 45, 60, 60); // рисуем прямоугольник с восстановленными настройками
+
+ ctx.restore(); // возвращаемся к начальным настройкам
+ ctx.fillRect(60, 60, 30, 30); // рисуем прямоугольник с изначальными настройками
+}</pre>
+
+<div class="hidden">
+<pre class="brush: html notranslate">&lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;</pre>
+
+<pre class="brush: js notranslate">draw();</pre>
+</div>
+
+<p>Сначала рисуется большой прямоугольник с настройками по умолчанию. Затем мы сохраняем состояние холста, после чего изменяем цвет заливки. Затем рисуем второй синий прямоугольник меньшего размера и опять сохраняем состояние. Снова изменяем какие-то настройки и рисуем третий полупрозрачный белый прямоугольник.</p>
+
+<p>До сих пор наши действия ничем не отличались от тех, что мы делали в предыдущем разделе. Однако, как только мы сделали первый вызов <code>restore(),</code> последнее сохранённое состояние отрисовки было восстановлено из стека, вернув все сохранённые настройки. Если бы мы не сохранили предыдущее состояние, используя <code>save()</code>, нам бы пришлось менять цвет заливки и настройки прозрачности вручную для возврата к предыдущему состоянию. Для каких-нибудь двух простых свойств это, может быть, сделать не так сложно. Но если таких своиств гораздо больше, это чревато очень быстрым разрастанием кода.</p>
+
+<p>Когда второй вызов <code>restore()</code> сделан, изначальное состояние (то самое, которое было сделано перед первым вызовом <code>save</code>) восстанавливается и последний нарисованный прямоугольник внось становится чёрным.</p>
+
+<p>{{EmbedLiveSample("A_save_and_restore_canvas_state_example", "180", "180", "https://mdn.mozillademos.org/files/249/Canvas_savestate.png")}}</p>
+
+<h2 id="Translating" name="Translating">Трансляция (смещение)</h2>
+
+<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/234/Canvas_grid_translate.png" style="float: right;">Первый метод для трасформирования холста <code>translate()</code>. Он используется для перемещения холста в любую точку нашей сетки.</p>
+
+<dl>
+ <dt>{{domxref("CanvasRenderingContext2D.translate", "translate(x, y)")}}</dt>
+ <dd>Перемещение холста на сетке. <code>x</code> и <code>y</code> - смещение по горизонтали и вертикали соответственно.</dd>
+</dl>
+
+<p>Неплохая идея - сохранять <code>canvas state</code> перед использованием любых трансформаций. Обычно удобнее использовать метод <code>restore</code>, чем выполнять обратные преобразования, чтобы вернуться к начальному состоянию. <span class="tlid-translation translation" lang="ru"><span title="">Кроме того, если вы выполняете преобразования внутри цикла не используя </span></span><code>save</code><span class="tlid-translation translation" lang="ru"><span title=""> и </span></span><code>restore</code><span class="tlid-translation translation" lang="ru"><span title="">, вы рискуете потерять часть рисунка, потому что он был нарисован за пределами края холста.</span></span></p>
+
+<h3 id="A_translate_example" name="A_translate_example">Пример использования <code>translate</code></h3>
+
+<p><span class="tlid-translation translation" lang="ru"><span title="">Этот пример демонстрирует некоторые преимущества</span></span> при использовании смещения холста. Без использования метода <code>translate()</code> все прямоугольники будут отрисованы в одинаковой позиции (0,0). Метод <code>translate()</code> дает возможность размещения прямоугольника в любой позиции без изменения параметров функции <code>fillRect()</code>. Это может дать некоторое упрощение для понимания и использования.</p>
+
+<p>Внутри функции <code>draw()</code> мы вызываем <code>fillRect()</code> девять раз, используя два цикла <code>for</code>. Каждый раз мы сохраняем состояние холста, смещаем его, рисуем прямоугольник, а затем восстанавливаем исходное состояние. Заметьте, что <code>fillRect()</code> всегда использует одни и те же параметры, а изменение позиции фигуры осуществляется с помощью <code>translate()</code>.</p>
+
+<pre class="brush: js; highlight:[7] notranslate">function draw() {
+ var ctx = document.getElementById('canvas').getContext('2d');
+ for (var i = 0; i &lt; 3; i++) {
+ for (var j = 0; j &lt; 3; j++) {
+ ctx.save();
+ ctx.fillStyle = 'rgb(' + (51 * i) + ', ' + (255 - 51 * i) + ', 255)';
+ ctx.translate(10 + j * 50, 10 + i * 50);
+ ctx.fillRect(0, 0, 25, 25);
+ ctx.restore();
+ }
+ }
+}
+</pre>
+
+<div class="hidden">
+<pre class="brush: html notranslate">&lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;</pre>
+
+<pre class="brush: js notranslate">draw();</pre>
+</div>
+
+<p>{{EmbedLiveSample("A_translate_example", "160", "160", "https://mdn.mozillademos.org/files/9857/translate.png")}}</p>
+
+<h2 id="Rotating" name="Rotating">Поворот</h2>
+
+<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/233/Canvas_grid_rotate.png" style="float: right;">Второй метод трансформации <code>rotate()</code>. Он используется для поворота нашего холста.</p>
+
+<dl>
+ <dt>{{domxref("CanvasRenderingContext2D.rotate", "rotate(angle)")}}</dt>
+ <dd>Поворачивает наш холст по часовой стрелке вокруг начальной точки на угол <code>anglе</code> в радианах.</dd>
+</dl>
+
+<p>Центр поворота - всегда начало координат. Для изменения координат центра мы должны сместить холст, используя метод <code>translate()</code>.</p>
+
+<h3 id="A_rotate_example" name="A_rotate_example">Пример использования<code>rotate</code></h3>
+
+<p>В этом примере мы сначала используем <code>rotate()</code> для поворота прямоугольника относительно начала координат, а затем, используя <code>translate()</code> совместно с <code>rotate()</code> поворачиваем прямоугольник относительно его центра.</p>
+
+<div class="note">
+<p><strong>Памятка</strong>: Углы измеряются в радианах, а не в градусах. Для преобразования единиц используйте следующую формулу: <code>radians = (Math.PI/180)*degrees</code>.</p>
+</div>
+
+<pre class="brush: js; highlight:[9, 23] notranslate">function draw() {
+ var ctx = document.getElementById('canvas').getContext('2d');
+
+ // left rectangles, rotate from canvas origin
+ ctx.save();
+ // blue rect
+ ctx.fillStyle = '#0095DD';
+ ctx.fillRect(30, 30, 100, 100);
+ ctx.rotate((Math.PI / 180) * 25);
+ // grey rect
+ ctx.fillStyle = '#4D4E53';
+ ctx.fillRect(30, 30, 100, 100);
+ ctx.restore();
+
+ // right rectangles, rotate from rectangle center
+ // draw blue rect
+ ctx.fillStyle = '#0095DD';
+ ctx.fillRect(150, 30, 100, 100);
+
+ ctx.translate(200, 80); // translate to rectangle center
+ // x = x + 0.5 * width
+ // y = y + 0.5 * height
+ ctx.rotate((Math.PI / 180) * 25); // rotate
+ ctx.translate(-200, -80); // translate back
+
+ // draw grey rect
+ ctx.fillStyle = '#4D4E53';
+ ctx.fillRect(150, 30, 100, 100);
+}
+</pre>
+
+<p>Для поворота прямоугольника относительно его центра мы сначала смещаем начало координат, выполняем поворот, а затем выполняем обратное смещение к точке 0,0, и наконец рисуем прямоугольник.</p>
+
+<div class="hidden">
+<pre class="brush: html notranslate">&lt;canvas id="canvas" width="300" height="200"&gt;&lt;/canvas&gt;</pre>
+
+<pre class="brush: js notranslate">draw();</pre>
+</div>
+
+<p>{{EmbedLiveSample("A_rotate_example", "310", "210", "https://mdn.mozillademos.org/files/9859/rotate.png")}}</p>
+
+<h2 id="Scaling" name="Scaling">Масштабирование</h2>
+
+<p>Следующий метод трансформации холста - scaling. Он используется для растяжения, сжатия и отражения координатной сетки. Он может использоваться для отрисовки растянутых или сжатых по осям фигур и изображений.</p>
+
+<dl>
+ <dt>{{domxref("CanvasRenderingContext2D.scale", "scale(x, y)")}}</dt>
+ <dd>Масштабирует координатную сетку холста по горизонтали и вертикали. Оба параметра - вещественные числа. Значения меньше 1.0 уменьшают, а больше 1.0 увеличивают масштаб сетки. Значение 1.0 не изменяет его.</dd>
+</dl>
+
+<p>Используя отрицательные значения вы можете зеркально отразить направление осей. Например, используя <code>translate(0,canvas.height); scale(1,-1);</code> вы получите хорошо известную декартову систему координат с началом в верхнем левом углу.</p>
+
+<p>По умолчанию единица координатной сетки точно соответствует одному пикселю. Если же вы, например, зададите масштабный коэффициент 0.5, то единица сетки будет равна половине пикселя, и нарисованная фигура будет иметь размер в два раза меньше оригинала. Наоборот, если задать масштабный коэффициент 2.0, единица сетки будет соответствовать двум пикселям, а нарисованная фигура станет в два раза больше.</p>
+
+<h3 id="A_scale_example" name="A_scale_example">Пример использования <code>scale</code></h3>
+
+<p>В этом примере мы нарисуем прямоугольники, используя разные масштабные коэффициенты.</p>
+
+<pre class="brush: js; highlight:[6,11] notranslate">function draw() {
+ var ctx = document.getElementById('canvas').getContext('2d');
+
+ // рисуем масштабированный прямоугольник.
+ ctx.save();
+ ctx.scale(10, 3);
+ ctx.fillRect(1, 10, 10, 10);
+ ctx.restore();
+
+ // размещаем текст, отраженный по горизонтали
+ ctx.scale(-1, 1);
+ ctx.font = '48px serif';
+ ctx.fillText('MDN', -135, 120);
+}
+
+</pre>
+
+<div class="hidden">
+<pre class="brush: html notranslate">&lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;</pre>
+
+<pre class="brush: js notranslate">draw();</pre>
+</div>
+
+<p>{{EmbedLiveSample("A_scale_example", "160", "160", "https://mdn.mozillademos.org/files/9861/scale.png")}}</p>
+
+<h2 id="Transforms" name="Transforms">Матричное преобразование</h2>
+
+<p>В заключении рассмотрим метод, который вызывает изменения в соответствии с матрицей преобразования.</p>
+
+<dl>
+ <dt>{{domxref("CanvasRenderingContext2D.transform", "transform(a, b, c, d, e, f)")}}</dt>
+ <dd>Накладывает матрицу преобразования, заданную параметрами, на текущую матрицу. Матрица преобразования задается следующим образом: <math><semantics><mrow><mo>[</mo><mtable columnalign="center center center" rowspacing="0.5ex"><mtr><mtd><mi>a</mi></mtd><mtd><mi>c</mi></mtd><mtd><mi>e</mi></mtd></mtr><mtr><mtd><mi>b</mi></mtd><mtd><mi>d</mi></mtd><mtd><mi>f</mi></mtd></mtr><mtr><mtd><mn>0</mn></mtd><mtd><mn>0</mn></mtd><mtd><mn>1</mn></mtd></mtr></mtable><mo>]</mo></mrow><annotation encoding="TeX">\left[ \begin{array}{ccc} a &amp; c &amp; e \\ b &amp; d &amp; f \\ 0 &amp; 0 &amp; 1 \end{array} \right]</annotation></semantics></math></dd>
+</dl>
+
+<dl>
+ <dd>If any of the arguments are <code><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code> the transformation matrix must be marked as infinite instead of the method throwing an exception.</dd>
+</dl>
+
+<p>Параметры функции:</p>
+
+<dl>
+ <dt><code>a (m11)</code></dt>
+ <dd>Horizontal scaling.</dd>
+ <dt><em><code>b (m12)</code></em></dt>
+ <dd>Horizontal skewing.</dd>
+ <dt><code>c (m21)</code></dt>
+ <dd>Vertical skewing.</dd>
+ <dt><code>d (m22)</code></dt>
+ <dd>Vertical scaling.</dd>
+ <dt><code>e (dx)</code></dt>
+ <dd>Horizontal moving.</dd>
+ <dt><code>f (dy)</code></dt>
+ <dd>Vertical moving.</dd>
+ <dt>{{domxref("CanvasRenderingContext2D.setTransform", "setTransform(a, b, c, d, e, f)")}}</dt>
+ <dd>Сбрасывает текущую матрицу преобразования, а затем вызывает<code>transform()</code> в соответствии с аргументами.</dd>
+ <dt>{{domxref("CanvasRenderingContext2D.resetTransform", "resetTransform()")}}</dt>
+ <dd>Сбрасывает текущую матрицу преобразования к значению по умолчанию. Аналогично вызову <code>ctx.setTransform(1, 0, 0, 1, 0, 0);</code></dd>
+</dl>
+
+<h3 id="Пример_использования_transform_и_setTransform">Пример использования <code>transform</code> и <code>setTransform</code></h3>
+
+<pre class="brush: js; highlight:[12,15] notranslate">function draw() {
+ var ctx = document.getElementById('canvas').getContext('2d');
+
+ var sin = Math.sin(Math.PI / 6);
+ var cos = Math.cos(Math.PI / 6);
+ ctx.translate(100, 100);
+ var c = 0;
+ for (var i = 0; i &lt;= 12; i++) {
+ c = Math.floor(255 / 12 * i);
+ ctx.fillStyle = 'rgb(' + c + ', ' + c + ', ' + c + ')';
+ ctx.fillRect(0, 0, 100, 10);
+ ctx.transform(cos, sin, -sin, cos, 0, 0);
+ }
+
+ ctx.setTransform(-1, 0, 0, 1, 100, 100);
+ ctx.fillStyle = 'rgba(255, 128, 255, 0.5)';
+ ctx.fillRect(0, 50, 100, 100);
+}
+</pre>
+
+<div class="hidden">
+<pre class="brush: html notranslate">&lt;canvas id="canvas" width="200" height="250"&gt;&lt;/canvas&gt;</pre>
+
+<pre class="brush: js notranslate">draw();</pre>
+</div>
+
+<p>{{EmbedLiveSample("Example_for_transform_and_setTransform", "230", "280", "https://mdn.mozillademos.org/files/255/Canvas_transform.png")}}</p>
+
+<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Using_images", "Web/API/Canvas_API/Tutorial/Compositing")}}</p>