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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
|
---
title: Desenhando formas com canvas
slug: Web/API/Canvas_API/Tutorial/Drawing_shapes
tags:
- Canvas
- Gráficos(2)
- HTML
- HTML Canvas
- HTML5
- Intermediário
- Tutorial
translation_of: Web/API/Canvas_API/Tutorial/Drawing_shapes
original_slug: Web/Guide/HTML/Canvas_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>Agora que criamos nosso <a href="https://developer.mozilla.org/pt-BR/docs/Web/API/Canvas_API/Tutorial/Basic_usage">ambiente em canvas</a>, podemos entrar nos detalhes de como desenhar no canvas. No final deste artigo, você terá aprendido a desenhar retângulos, triângulos, linhas, arcos e curvas, proporcionando familiaridade com algumas das formas básicas. Trabalhar com caminhos (<em>shapes</em>) é essencial ao desenhar objetos na tela e veremos como isso pode ser feito.</p>
</div>
<h2 id="A_grade">A grade</h2>
<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/224/Canvas_default_grid.png" style="float: right; height: 220px; width: 220px;">Antes que possamos começar a desenhar, precisamos falar sobre a grade de tela ou <strong>espaço de coordenadas</strong>. O modelo HTML na página anterior tinha um elemento canvas de 150 pixels de largura e 150 pixels de altura. À direita, você verá este canvas com a grade padrão sobreposta. Normalmente 1 unidade na grade corresponde a um pixel na tela. A origem desta grade está posicionada no canto superior esquerdo (coordenadas (0,0)). Todos os elementos são colocados em relação a esta origem. Assim, a posição do canto superior esquerdo do quadrado azul, se torna x pixels dos pixels da esquerda e y a partir do topo (coordenadas (x,y)). Mais tarde nesse tutorial vamos ver como podemos traduzir a origem para uma posição diferente, girar a grade e até mesmo escaloná-la. Por enquanto vamos ficar com o padrão.</p>
<h2 id="Desenhando_retângulos">Desenhando retângulos</h2>
<p>Diferente do {{Glossary("SVG")}} , o {{HTMLElement("canvas")}} suporta somente formas primitivas: retângulos. Todas as outras formas são criadas a partir da combinação de um ou mais caminhos (<em>paths</em>), lista de pontos conectados por uma linha. Felizmente, temos uma variedade de funções de desenho que tornam possíveis criar formas muito complexas.</p>
<p>Primeiramente vamos olhar o retângulo. Aqui está listado três funções para desenhar retângulos pelo canvas:</p>
<dl>
<dt>{{domxref("CanvasRenderingContext2D.fillRect", "fillRect(x, y, width, height)")}}</dt>
<dd>Desenha um retângulo preenchido.</dd>
<dt>{{domxref("CanvasRenderingContext2D.strokeRect", "strokeRect(x, y, width, height)")}}</dt>
<dd>Desenha a borda do retângulo.</dd>
<dt>{{domxref("CanvasRenderingContext2D.clearRect", "clearRect(x, y, width, height)")}}</dt>
<dd>Limpa um retângulo específico, tornando-o totalmente transparente.</dd>
</dl>
<p>Cada umas das funções recebem os mesmos parâmetros. <code>x</code> e <code>y</code> determinam a posição no canvas (em relação a origem) no canto superior esquerdo do retângulo. O <code>width</code> (largura) e o <code>height</code> (altura) definem o tamanho do retângulo.</p>
<p>Abaixo esta listado a função <code>draw()</code> da página anterior, porém utilizando as três funções.</p>
<h3 id="Exemplo_de_forma_retangular">Exemplo de forma retangular</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>O resultado desse exemplo é mostrado abaixo.</p>
<p>{{EmbedLiveSample('Exemplo_de_forma_retangular', 160, 160, "https://mdn.mozillademos.org/files/245/Canvas_rect.png")}}</p>
<p>A função <code>fillRect()</code> desenha um grande quadrado preto de 100 pixels. A função <code>clearRect()</code> por sua vez apaga um quadrado de 60x60 pixels a partir do centro, por fim, a função <code>strokeRect()</code> é chamada para criar uma borda de 50x50 pixels em volta do quadrado apagado.</p>
<p>Posteriormente veremos duas alternativas à função <code>clearRect()</code>, nós também aprenderemos como alterar a cor e o estilo das linhas nas camadas renderizadas.</p>
<p>Ao contrário das funções de <em>paths</em> que veremos na próxima seção, todas as três funções de retângulo desenham imediatamente no canvas.</p>
<h2 id="Desenhando_caminhosregiões_paths">Desenhando caminhos/regiões (paths)</h2>
<p>Para criar uma camada usando caminhos (regiões ou <em>paths</em>) é necessário alguns passos extras. Primeiro, cria-se a região de desenho. Depois usa-se comandos de desenho para desenhar nesta região. Por fim, você limita a região (path). Uma vez que a região de desenho está criada, você pode traçar ou preencher o caminho para que seja renderizado. Aqui estão as funções utilizadas para isso:</p>
<dl>
<dt>{{domxref("CanvasRenderingContext2D.beginPath", "beginPath()")}}</dt>
<dd>Cria um novo path. Uma vez criado, futuros comandos de desenho são direcionados do path atual para a construção de um novo path no canvas.</dd>
</dl>
<dl>
<dt><a href="https://developer.mozilla.org/pt-BR/docs/Web/API/CanvasRenderingContext2D#Paths">Métodos de Caminhos (Path)</a></dt>
<dd>Métodos para manipuliar diferentes paths para objetos.</dd>
</dl>
<dl>
<dt>{{domxref("CanvasRenderingContext2D.closePath", "closePath()")}}</dt>
<dd>Finaliza o path para futuros comandos de desenho, fazendo com que voltem a ser direcionados ao contexto.</dd>
<dt>{{domxref("CanvasRenderingContext2D.stroke", "stroke()")}}</dt>
<dd>Desenha uma borda na camada.</dd>
<dt>{{domxref("CanvasRenderingContext2D.fill", "fill()")}}</dt>
<dd>Desenha uma forma sólida através de preenchimento.</dd>
</dl>
<p>O primeiro passo para criar um caminho é chamar o <code>beginPath()</code>. Internamente, caminhos são armazenados como uma lista de sub-caminhos (linhas, arcos, etc.) que juntos formam uma forma (<em>shape</em>). Sempre que esse método é chamado, a lista é redefinida e podemos começar a desenhar novas formas.</p>
<div class="note"><strong>Nota:</strong> Quando o caminho atual está vazio, assim como imediatamente depois de chamar <code>beginPath()</code>, ou em uma tela recém-criada, o primeiro comando de construção de caminho é sempre tratado como um <code>moveTo()</code>, independentemente do que ele seja realmente. Por essa razão, você quase sempre vai precisar definir especificamente sua posição inicial após redefinir um caminho.</div>
<p>A segunda etapa é chamar os métodos que realmente especificam os caminhos a serem desenhados. Vamos ver isso em breve.</p>
<p><br>
O terceiro, e um passo opcional, é chamar <code>closePath()</code>. Este método tenta fechar a forma desenhando uma linha reta do ponto atual para o início. Se a forma (<em>shape</em>) já foi fechada ou existe apenas um ponto na lista, esta função não faz nada.</p>
<div class="note"><strong>Nota:</strong> Quando você chama <code>fill()</code>, todas as formas abertas são fechadas automaticamente, assim você não precisa chamar <code>closePath()</code>. Isso <strong>não acontece</strong> quando você chamar <code>stroke()</code>.</div>
<h3 id="Desenhando_um_triângulo">Desenhando um triângulo</h3>
<p>Por exemplo, o código para desenhar um triângulo seria algo parecido com isto:</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');
ctx.beginPath();
ctx.moveTo(75,50);
ctx.lineTo(100,75);
ctx.lineTo(100,25);
ctx.fill();
}
}
</pre>
<p>O resultado se parece com isso:</p>
<p>{{EmbedLiveSample('Desenhando_um_triângulo', 160, 160, "https://mdn.mozillademos.org/files/9847/triangle.png")}}</p>
<h3 id="Desenhando">Desenhando</h3>
<p>Uma função muito útil, que na verdade não desenha nada, mas torna-se parte da lista de caminhos descritos acima, é a função <code>moveTo()</code>. Você provavelmente pode imaginar melhor isso como se fosse o levantar uma caneta ou lápis de um ponto em um pedaço de papel e colocá-lo no próximo ponto.</p>
<dl>
<dt>{{domxref("CanvasRenderingContext2D.moveTo", "moveTo(x, y)")}}</dt>
<dd>Move a caneta (<em>pen</em>) para as coordenadas especificadas por <code>x</code> e <code>y</code>.</dd>
</dl>
<p>Quando o canvas é inicializado ou <code>beginPath()</code> é chamado, você normalmente vai querer usar a função <code>moveTo()</code> para colocar o ponto inicial em outro lugar. Poderíamos também usar <code>moveTo()</code> para desenhar caminhos não conectados. Dê uma olhada no rosto sorridente abaixo. Eu marquei os lugares onde eu usei o método <code>moveTo()</code> (as linhas vermelhas).</p>
<p>Caso queira tentar fazer isso, você pode usar o snippet de código abaixo. Basta colá-lo na função <code>draw()</code> que vimos anteriormente.</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');
ctx.beginPath();
ctx.arc(75, 75, 50, 0, Math.PI * 2, true); // Círculo exterior
ctx.moveTo(110, 75);
ctx.arc(75, 75, 35, 0, Math.PI, false); // Boca (sentido horário)
ctx.moveTo(65, 65);
ctx.arc(60, 65, 5, 0, Math.PI * 2, true); // Olho esquerdo
ctx.moveTo(95, 65);
ctx.arc(90, 65, 5, 0, Math.PI * 2, true); // Olho direito
ctx.stroke();
}
}
</pre>
<p>O resultado aparece como:</p>
<p>{{EmbedLiveSample("Desenhando", 160, 160, "https://mdn.mozillademos.org/files/252/Canvas_smiley.png")}}</p>
<p>Se você não gosta de ver linhas conectadas, você pode remover as linhas que chamam a função <code>moveTo()</code>.</p>
<div class="note">
<p><strong>Nota:</strong> Para aprender mais sobre a função <code>arc()</code>, veja sobre {{anch("Arcos")}}.</p>
</div>
<h3 id="Linhas">Linhas</h3>
<p>Para desenhar linhas retas, use o método <code>lineTo().</code></p>
<dl>
<dt>{{domxref("CanvasRenderingContext2D.lineTo", "lineTo(x, y)")}}</dt>
<dd>Desenha uma linha do ponto atual a até a posição especificada por <code>x</code> e <code>y</code>.</dd>
</dl>
<p>Esse método recebe dois argumentos, <code>x</code> e <code>y</code>, que são as coordenadas do ponto final da linha. O ponto inicial é dependente de caminhos previamente desenhados, onde o ponto final do caminho anterior é o ponto inicial para o seguinte, e assim por diante. O ponto inicial também pode ser alterado usando o método <code>moveTo()</code>.<br>
<br>
O exemplo abaixo desenha dois triângulos, um preenchido e um delineado.</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');
// 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>Isso começa chamando o método <code>beginPath()</code> para iniciar um novo <em>shape path</em>. Em seguida, usamos o método <code>moveTo()</code> para mover o ponto inicial para a posição desejada. Logo abaixo, duas linhas, que compõem os dois lados do triângulo, são desenhadas.</p>
<p>{{EmbedLiveSample("Linhas", 160, 160, "https://mdn.mozillademos.org/files/238/Canvas_lineTo.png")}}</p>
<p>Você notará a diferença entre o triângulo preenchido (<em>filled</em>) e não prenchido (<em>stroked</em>). Isto ocorre, como mencionado acima, porque as formas são automaticamente fechadas quando um caminho é preenchido, mas não quando são não preenchidos. Se deixássemos de fora o <code>closePath()</code> para os triângulos não preenchidos, apenas duas linhas teriam sido desenhadas, não um triângulo completo.</p>
<h3 id="Arcos">Arcos</h3>
<p>Para desenhar arcos, nós usamos os métodos <code>arc()</code> ou <code>arcTo()</code>.</p>
<dl>
<dt>{{domxref("CanvasRenderingContext2D.arc", "arc(x, y, radius, startAngle, endAngle, anticlockwise)")}}</dt>
<dd>Desenha um arco centralizado na posição <em>(x, y)</em> com um raio <em>r</em> iniciando em <em>startAngle e</em> terminando em <em>endAngle</em> apontando na direção indicada pelo sentido anti-horário (padronizando para o sentido horário).</dd>
<dt>{{domxref("CanvasRenderingContext2D.arcTo", "arcTo(x1, y1, x2, y2, radius)")}}</dt>
<dd>Desenha um arco com os pontos de controle e raio, conectados ao ponto anterior por uma linha reta.</dd>
</dl>
<p>Vamos dar uma olhada mais detalhada sobre o método <code>arc</code>, que tem seis parâmetros: <code>x</code> e <code>y</code> são as coordenadas do centro do círculo em que o arco deve ser desenhado. <code>radius</code> é o raio. Os parâmetros <code>startAngle</code> e <code>endAngle</code> definem os pontos inicial e final do arco em radianos, ao longo da curva do círculo. Estes são medidos a partir do eixo <code>x</code>. O parâmetro <code>anticlockwise</code> é um valor Booleano que, quando verdadeiro, desenha o arco no sentido anti-horário; Caso contrário, o arco é desenhado no sentido horário.</p>
<div class="note">
<p><strong>Nota</strong>: Os ângulos na função <code>arc</code> são medidos em radianos, não em graus. Para converter graus em radianos você pode usar a seguinte expressão JavaScript: <code>radians = (Math.PI/180)*degrees</code>.</p>
</div>
<p>O exemplo a seguir é um pouco mais complexo do que os que vimos anteriormente. Ele desenha 12 arcos diferentes, todos com diferentes ângulos e preenchimentos.</p>
<p>Os dois laços <code>for</code> são para iterar através das linhas e colunas de arcos. Para cada arco, é criado um novo caminho chamando <code>beginPath()</code>. No código, cada um dos parâmetros para o arco estão em uma variável somente para demonstração, assim você não precisa fazer isso na vida real.</p>
<p>As coordenadas <code>x</code> e <code>y</code> devem ser suficientemente claras. O parâmetros <code>radius</code> e <code>startAngle</code> são fixos. O <code>endAngle</code> começa em 180 graus (metade de um círculo) na primeira coluna e aumenta gradualmente em 90 graus, culminando em um círculo completo na última coluna.</p>
<p>A manipulação do parâmetro <code>clockwise</code> faz com que a primeira e terceira linhas sejam desenhadas como arcos no sentido horário, e a segunda e quarta linhas como arcos no sentido anti-horário. Finalmente, a instrução <code>if</code> faz com que a metade superior dos arcos não sejam preenchidos e a metade inferior dos arcos sejam.</p>
<div class="note">
<p><strong>Note:</strong> Este exemplo requer um canvas um pouco maior que as outras desta página: 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 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; // coordenada x
var y = 25+i*50; // coordenada y
var radius = 20; // Raio do Arco
var startAngle = 0; // Ponto inicial no círculo
var endAngle = Math.PI+(Math.PI*j)/2; // Ponto final no círculo
var anticlockwise = i%2==0 ? false : true; // horário ou anti-horário
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
if (i>1){
ctx.fill();
} else {
ctx.stroke();
}
}
}
}
}
</pre>
<p>{{EmbedLiveSample("Arcos", 160, 210, "https://mdn.mozillademos.org/files/204/Canvas_arc.png")}}</p>
<h3 id="Curvas_de_Bézier_Cúbicas_e_Quadráticas">Curvas de Bézier Cúbicas e Quadráticas</h3>
<p>O próximo tipo de caminhos disponíveis são as Curvas de Bézier, disponíveis nas variedades cubícas e quadráticas. Elas são geralmente usadas para desenhar complexas formas orgânicas.</p>
<dl>
<dt>{{domxref("CanvasRenderingContext2D.quadraticCurveTo", "quadraticCurveTo(cp1x, cp1y, x, y)")}}</dt>
<dd>Desenha uma curva de Bézier quadrática da posição atual indicada pelo cursor, até a posição final especificada por <code>x</code> e <code>y</code>, usando o controle de pontos guiados por <code>cp1x</code> <code>e cp1y</code>.</dd>
<dt>{{domxref("CanvasRenderingContext2D.bezierCurveTo", "bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)")}}</dt>
<dd>Desenha uma curva de Bézier cúbica partindo da posição atual indicada pelo cursor, até a posição final especificada por <code>x</code> e <code>y</code>, usando o controle de pontos guiados por (<code>cp1x</code>, <code>cp1y</code>) e (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;">A diferença entre estes métodos pode ser descrita de forma melhor usando a imagem à direita. Uma curva quadrática de Bézier tem um ponto inicial e final (pontos azuis) e apenas um ponto de controle (indicado pelo ponto vermelho) enquanto que uma curva cúbica de Bézier utiliza dois pontos de controles.</p>
<p>Os parâmetros <code>x</code> e <code>y</code> em ambos os métodos são as coordenadas do ponto final. <code>cp1x</code> e<code> cp1y</code> são as coordenadas do primeiro ponto de controle, e <code>cp2x</code> e <code>cp2y</code> são as coordenadas do segundo ponto de controle.</p>
<p>Usando curvas de Bézier quadráticas e cúbicas pode ser algo bastante desafiador, porque ao contrário de um software de desenho vetorial, como o Adobe Illustrator, não temos resultados visuais imediatos sobre o que estamos fazendo. Isso torna bastante difícil desenhar formas complexas. No exemplo a seguir, vamos desenhar algumas formas orgânicas simples, mas se você tiver tempo e, acima de tudo, paciência, formas muito mais complexas podem ser criadas.</p>
<p>Não há nada muito difícil nestes exemplos. Em ambos os casos vemos uma sucessão de curvas sendo desenhadas, resultando no fim, em uma forma (<em>shape</em>) completa.</p>
<h4 id="Curvas_de_Bézier_Quadráticas">Curvas de Bézier Quadráticas</h4>
<p>Este exemplo usa múltiplas curvas de Bézier quadráticas para renderizar um balão de fala.</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');
// Exemplo de curvas de Bézier quadráticas
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('Curvas_de_Bézier_Quadráticas', 160, 160, "https://mdn.mozillademos.org/files/243/Canvas_quadratic.png")}}</p>
<h4 id="Curvas_de_Bézier_Cúbicas">Curvas de Bézier Cúbicas</h4>
<p>Este exemplo desenha um coração usando curvas de Bézier cúbicas.</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');
// Exemplo de curvas de Bézier cúbicas
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('Curvas_de_Bézier_Cúbicas', 160, 160, "https://mdn.mozillademos.org/files/207/Canvas_bezier.png")}}</p>
<h3 id="Retângulos">Retângulos</h3>
<p>Além dos três métodos que vimos em {{anch("Desenhando retângulos")}}, que desenham formas retangulares diretamente no canvas, há também o método <code>rect()</code>, que adiciona uma forma retangular a um caminho (<em>path</em>) atualmente aberto.</p>
<dl>
<dt>{{domxref("CanvasRenderingContext2D.rect", "rect(x, y, width, height)")}}</dt>
<dd>
<p>Desenha um retângulo cujo canto superior esquerdo é especificado por (<code>x</code>, <code>y</code>) com base em uma largura (<code>width</code>) e uma altura (<code>height</code>).</p>
</dd>
</dl>
<p>Quando este método é executado, o método <code>moveTo()</code> é automaticamente chamado com os parâmetros (0,0). Em outras palavras, a posição atual do cursor é automaticamente redefinida para as coordenadas padrões.</p>
<h3 id="Combinando_Elementos">Combinando Elementos</h3>
<p>Até agora, em cada exemplo dessa página foi usada apenas um tipo de função de caminho (<em>path</em>) para cada forma (<em>shape</em>). No entanto, não há nenhuma limitação para o número ou tipos de caminhos que você pode usar para criar um <em>shape</em>. Então, neste exemplo final, vamos combinar todas as funções de caminho para fazer um conjunto de personagens de jogo muito conhecido.</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();
}
}
// Uma função útil para desenhar um retângulo com cantos arredondados.
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>O resultado é:</p>
<p>{{EmbedLiveSample("Combinando_Elementos", 160, 160, "https://mdn.mozillademos.org/files/9849/combinations.png")}}</p>
<p>Não vamos discutir isso em detalhes, uma vez que é realmente muito simples. As coisas mais importantes a serem observadas são o uso da propriedade <code>fillStyle</code> no contexto de desenho e o uso de uma função auxiliar (neste caso <code>roundedRect()</code>). Usando funções auxiliares para construir um desenho frequentemente pode ser muito útil, além de reduzir a quantidade de código que você precisa, bem como a sua complexidade.</p>
<p>Vamos dar uma nova olhada em <code>fillStyle</code>, em mais detalhes, mais adiante neste tutorial. Aqui, tudo o que estamos fazendo é apenas usando-o para alterar sucessivamente a cor de preenchimento dos caminhos (<em>paths</em>) de cor preta (padrão) para branca.</p>
<h2 id="Path2D">Path2D</h2>
<p>Como vimos no último exemplo, pode haver uma série de <em>paths</em> e comandos de desenho para desenhar objetos em sua tela. Para simplificar o código e melhorar o desempenho, o objeto {{domxref("Path2D")}}, disponível em versões recentes dos navegadores, permite armazenar em cache ou gravar esses comandos de desenho. Com ele, você pode construir seus <em>paths</em> rapidamente.<br>
Vamos ver como podemos construir um objeto de <code>Path2D</code>:</p>
<dl>
<dt>{{domxref("Path2D.Path2D", "Path2D()")}}</dt>
<dd>
<p>O construtor de <code><strong>Path2D()</strong></code> retorna um objeto <code>Path2D</code> instanciado recentemente, opcionalmente através de um outro objeto <code>Path2D</code> como argumento (cria uma cópia) ou, opcionalmente, com uma <em>string</em> que representam dados de <a href="/en-US/docs/Web/SVG/Tutorial/Paths"><em>paths</em> em SVG</a>.</p>
</dd>
</dl>
<pre class="brush: js notranslate">new Path2D(); // objeto vazio de Path2D
new Path2D(path); // cópia de outro objeto de Path2D
new Path2D(d); // objeto criado a partir de <em>paths</em> em SVG</pre>
<p>Todos os <a href="/pt_BR/docs/Web/API/CanvasRenderingContext2D#Paths">métodos de caminho (path methods)</a> como <code>moveTo</code>, <code>rect</code>, <code>arc</code> ou <code>quadraticCurveTo</code>, etc., que temos de saber acima, estão disponíveis em <code>Path2D</code>.</p>
<p>A API <code>Path2D</code> também adiciona uma maneira de combinar caminhos usando o método <code>addPath</code>. Isso pode ser útil quando você deseja criar objetos com vários componentes, por exemplo.</p>
<dl>
<dt>{{domxref("Path2D.addPath", "Path2D.addPath(path [, transform])")}}</dt>
<dd>Adiciona um <code>path</code> para o <code>path</code> atual através de uma matriz de transformação opcional.</dd>
</dl>
<h3 id="Exemplo_de_Path2D">Exemplo de Path2D</h3>
<p>Neste exemplo, estamos criando um retângulo e um círculo. Ambos são armazenados como um objeto de <code>Path2D</code>, de modo que eles estão disponíveis para uso posterior. Com a nova API <code>Path2D</code>, vários métodos foram atualizados como, por exemplo, opcionalmente usar um objeto <code>Path2D</code> em vez do <code>path</code> atual. Aqui, os métodos <code>stroke</code> e <code>fill</code> são usados, com um argumento de <em>path</em>, para desenhar ambos os objetos na tela, por exemplo.</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("Exemplo_de_Path2D", 140, 110, "https://mdn.mozillademos.org/files/9851/path2d.png")}}</p>
<h3 id="Usando_paths_em_SVG">Usando <em>paths</em> em SVG</h3>
<p>Outro recurso poderoso da nova API de Path2D é a utilização de dados de <em>path</em> em SVG para inicializar caminhos (<em>paths</em>) no canvas. Isso permite que você crie dados de <em>paths </em>que possam ser utilizados tanto no SVG como no canvas.</p>
<p>O caminho se moverá para o ponto <code>(M10 10)</code> e então se moverá horizontalmente 80 pontos para a direita <code>(h 80)</code>, depois 80 pontos para baixo <code>(v 80)</code>, então 80 pontos para a esquerda (h -80) e, por fim, volta para o início (<code>z</code>). Você pode ver este exemplo na página do <a href="/en-US/docs/Web/API/Path2D.Path2D#Using_SVG_paths">construtor do Path2D</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>
|