aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/api/canvasrenderingcontext2d/arcto/index.html
blob: 3e74f3015b8e6850cd57355f8120e7d8257b6c4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
---
title: CanvasRenderingContext2D.arcTo()
slug: Web/API/CanvasRenderingContext2D/arcTo
tags:
  - API
  - Canvas
  - Method
translation_of: Web/API/CanvasRenderingContext2D/arcTo
---
<div>{{APIRef}}</div>

<p>В Canvas 2D API есть метод <code><strong>CanvasRenderingContext2D</strong></code><strong><code>.arcTo()</code></strong>. Он добавляет дугу к контуру (path) с заданными контрольными точками и радиусом, соединяя их прямой линией с предыдущей точкой контура.</p>

<p>Обычно метод используется для скругления углов.</p>

<div class="blockIndicator note">
<p><strong>Примечание:</strong> Помните, что вы можете получить неожиданный результат при использовании большого радиуса: соединительная линия дуги будет идти в любом направлении, в котором она должна соответствовать указанному радиусу.</p>
</div>

<h2 id="Синтаксис">Синтаксис</h2>

<pre class="syntaxbox">void <var><em>ctx</em>.arcTo(x1, y1, x2, y2, radius);</var>
</pre>

<h3 id="Параметры">Параметры</h3>

<dl>
 <dt><code>x1</code></dt>
 <dd>Координата <u>x</u> первой контрольной точки.</dd>
 <dt><code>y1</code></dt>
 <dd>Координата <u>y</u> первой контрольной точки.</dd>
 <dt><code>x2</code></dt>
 <dd>Координата <u>x</u> второй контрольной точки.</dd>
 <dt><code>y2</code></dt>
 <dd>Координата <u>y</u> второй контрольной точки.</dd>
 <dt><code>radius</code></dt>
 <dd>Радиус дуги. Не может быть отрицательным.</dd>
</dl>

<h2 id="Примеры">Примеры</h2>

<h3 id="Как_работает_arcTo">Как работает arcTo</h3>

<p>Один из способов понять как работает <code>arcTo()</code> - представить две прямые линии: одна идёт от начальной точки к первой контрольной точке, а вторая от этой точки до второй контрольной точки. Без <code>arcTo()</code> эти два сегмента образовали бы острый угол: <code>arcTo()</code> создает дугу между этими двумя точками и сглаживает его. Другими словами, дуга является касательной для обеих линий.</p>

<h4 id="HTML">HTML</h4>

<pre class="brush: html">&lt;canvas id="canvas"&gt;&lt;/canvas&gt;</pre>

<h4 id="JavaScript">JavaScript</h4>

<pre class="brush: js">const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// Касательная линия
ctx.beginPath();
ctx.strokeStyle = 'gray';
ctx.moveTo(200, 20);
ctx.lineTo(200, 130);
ctx.lineTo(50, 20);
ctx.stroke();

// Дуга
ctx.beginPath();
ctx.strokeStyle = 'black';
ctx.lineWidth = 5;
ctx.moveTo(200, 20);
ctx.arcTo(200,130, 50,20, 40);
ctx.stroke();

// Начальная точка
ctx.beginPath();
ctx.fillStyle = 'blue';
ctx.arc(200, 20, 5, 0, 2 * Math.PI);
ctx.fill();

// Контрольные точки
ctx.beginPath();
ctx.fillStyle = 'red';
ctx.arc(200, 130, 5, 0, 2 * Math.PI); // Первая контрольная точка
ctx.arc(50, 20, 5, 0, 2 * Math.PI);   // Вторая контрольная точка
ctx.fill();</pre>

<h4 id="Результат">Результат</h4>

<p>В этом примере контур, созданный с помощью <code>arcTo()</code> <strong>жирный и чёрный</strong><span style="color: gray;">Касательная линия серия</span>, <span style="color: red;">контрольные точки красные</span>, а <span style="color: blue;">начальная точка синяя</span></p>

<p>{{ EmbedLiveSample('Как_работает_arcTo', 315, 165) }}</p>

<h3 id="Создание_скругленного_угла">Создание скругленного угла</h3>

<p>В этом примере создаётся скруглённый угол с использованием <code>arcTo()</code>. Это ещё один метод, который часто используется.</p>

<h4 id="HTML_2">HTML</h4>

<pre class="brush: html">&lt;canvas id="canvas"&gt;&lt;/canvas&gt;</pre>

<h4 id="JavaScript_2">JavaScript</h4>

<p>Дуга начинается в точке, заданной в <code>moveTo()</code>: (230, 20). Она сформирована так, чтобы соответствовать точкам на (90, 130) и (20, 20) с радиусом 50. Метод <code>lineTo()</code> соединяет дугу с (20, 20) прямой линией. Заметьте, что вторая контрольная точка дуги и точка, заданная в <code>lineTo()</code> одинаковые, что создаёт абсолютно гладкий угол.</p>

<pre class="brush: js">const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const p0 = { x: 230, y: 20  }
const p1 = { x: 90,  y: 130 }
const p2 = { x: 20,  y: 20  }

const labelPoint = function (p) {
  const offset = 15;
  ctx.fillText('(' + p.x + ',' + p.y + ')', p.x + offset, p.y + offset);
}

ctx.beginPath();
ctx.moveTo(p0.x, p0.y);
ctx.arcTo(p1.x, p1.y, p2.x, p2.y, 50);
ctx.lineTo(p2.x, p2.y);

labelPoint(p0);
labelPoint(p1);
labelPoint(p2);

ctx.stroke();</pre>

<h4 id="Результат_2">Результат</h4>

<p>{{ EmbedLiveSample('Создание_скругленного_угла', 315, 165) }}</p>

<h3 id="Результат_с_большим_радиусом">Результат с большим радиусом</h3>

<p>Если вы используете относительно большой радиус, дуга может появиться в том месте, где вы её не ожидаете. В данном примере соединительная линия дуги идёт вверху, а не внизу. Это происходит потому что радиус слишком большой, чтобы уместить дугу между точками.</p>

<h4 id="HTML_3">HTML</h4>

<pre class="brush: html">&lt;canvas id="canvas"&gt;&lt;/canvas&gt;</pre>

<h4 id="JavaScript_3">JavaScript</h4>

<pre class="brush: js">const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

ctx.beginPath();
ctx.moveTo(180, 90);
ctx.arcTo(180,130, 110,130, 130);
ctx.lineTo(110, 130);
ctx.stroke();</pre>

<h4 id="Результат_3">Результат</h4>

<p>{{ EmbedLiveSample('Результат_с_большим_радиусом', 315, 165) }}</p>

<h3 id="Живая_демонстрация">Живая демонстрация</h3>

<p>Более сложная демонстрация метода. Вы можете поиграть с диапазоном ввода, чтобы увидеть, как изменяется дуга.</p>

<h4 id="HTML_4">HTML</h4>

<pre class="brush: html">&lt;div&gt;
  &lt;label for="radius"&gt;Radius: &lt;/label&gt;
  &lt;input name="radius"  type="range" id="radius" min=0 max=100 value=50&gt;
  &lt;label for="radius"  id="radius-output"&gt;50&lt;/label&gt;
&lt;/div&gt;
&lt;canvas id="canvas"&gt;&lt;/canvas&gt;</pre>

<h4 id="JavaScript_4">JavaScript</h4>

<pre class="brush: js">const canvas = document.getElementById('canvas');
const ctx    = canvas.getContext('2d');

const controlOut = document.getElementById('radius-output');
const control    = document.getElementById('radius');
      control.oninput = () =&gt; {
          controlOut.textContent = r = control.value;
      };

const mouse = { x: 0, y: 0 };

let   r  = 100; // Radius
const p0 = { x: 0, y: 50 };

const p1 = { x: 100, y: 100 };
const p2 = { x: 150, y: 50 };
const p3 = { x: 200, y: 100 };

const labelPoint = function (p, offset, i = 0){
    const {x, y} = offset;
    ctx.beginPath();
    ctx.arc(p.x, p.y, 2, 0, Math.PI * 2);
    ctx.fill();
    ctx.fillText(`${i}:(${p.x}, ${p.y})`, p.x + x, p.y + y);
}

const drawPoints = function (points){
  for (let i = 0; i &lt; points.length; i++) {
    var p = points[i];
    labelPoint(p, { x: 0, y: -20 } , i)
  }
}

// Draw arc
const drawArc = function ([p0, p1, p2], r) {
  ctx.beginPath();
  ctx.moveTo(p0.x, p0.y);
  ctx.arcTo(p1.x, p1.y, p2.x, p2.y, r);
  ctx.lineTo(p2.x, p2.y);
  ctx.stroke();
}


let t0 = 0;
let rr = 0; // радиус, который меняется со временем
let a  = 0; // angle
let PI2 = Math.PI * 2;
const loop = function (t) {
  t0 = t / 1000;
  a  = t0 % PI2;
  rr = Math.abs(Math.cos(a) * r);

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  drawArc([p1, p2, p3], rr);
  drawPoints([p1, p2, p3]);
  requestAnimationFrame(loop);
}

loop(0);</pre>

<h4 id="Результат_4">Результат</h4>

<p>{{EmbedLiveSample('Живая_демонстрация', 315, 200) }}</p>

<h2 id="Спецификации">Спецификации</h2>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Спецификация</th>
   <th scope="col">Статус</th>
   <th scope="col">Комментарий</th>
  </tr>
  <tr>
   <td>{{SpecName('HTML WHATWG', "scripting.html#dom-context-2d-arcto", "CanvasRenderingContext2D.arcTo")}}</td>
   <td>{{Spec2('HTML WHATWG')}}</td>
   <td></td>
  </tr>
 </tbody>
</table>

<h2 id="Поддержка_браузерами">Поддержка браузерами</h2>

<p>{{Compat("api.CanvasRenderingContext2D.arcTo")}}</p>

<h2 id="Смотрите_также">Смотрите также</h2>

<ul>
 <li>Элемент определяющий этот метод, {{domxref("CanvasRenderingContext2D")}}</li>
</ul>