diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
commit | 074785cea106179cb3305637055ab0a009ca74f2 (patch) | |
tree | e6ae371cccd642aa2b67f39752a2cdf1fd4eb040 /files/ru/web/api/canvas_api/tutorial/transformations | |
parent | da78a9e329e272dedb2400b79a3bdeebff387d47 (diff) | |
download | translated-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.html | 275 |
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&depth=1&hl=ru&ie=UTF8&prev=_t&rurl=translate.google.com&sl=en&sp=nmt4&tl=ru&u=https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes&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"><canvas id="canvas" width="150" height="150"></canvas></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 < 3; i++) { + for (var j = 0; j < 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"><canvas id="canvas" width="150" height="150"></canvas></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"><canvas id="canvas" width="300" height="200"></canvas></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"><canvas id="canvas" width="150" height="150"></canvas></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 & c & e \\ b & d & f \\ 0 & 0 & 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 <= 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"><canvas id="canvas" width="200" height="250"></canvas></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> |