Este é o quarto artigo de uma série que irá apresentar os recursos disponibilizados pela nova tag <canvas> do HTML5. Nesse artigo, veremos
No artigo que falamos sobre o desenho de formas, usamos apenas as linhas e estilos de preenchimento padrão. Nesse artigo, exploraremos todas as opções que temos a nossa disposição para tornar nossos desenhos mais atraentes.
Cores
Até agora apenas vimos métodos do contexto de desenho. Se quisermos aplicar cores a uma forma, existem duas propriedades importantes que podem usar: fillStyle
e strokeStyle
.
fillStyle = color
- Ajusta o estilo usado ao preencher as formas.
strokeStyle = color
- Ajusta o estilo do contorno das formasS.
color
é uma String que representa um código CSS para <color>
, um objeto de gradiente ou objeto de um padrão. Nós iremos ver sobre gradientes e padrões mais pra frente. Por padrão, as cores do contorne e de preenchimento são ajustadas para preto (valor em CSS da cor = #000000).
strokeStyle
e/ou fillStyle
, o novo valor torna-se o padrão para todas as formas que forem ser desenhadas. Para cada forma que quiser desenhar em uma cor diferente, precisa associar um novo valor para as propriedades fillStyle
ou strokeStyle
.As Strings válidas que você pode informar devem ser, de acordo com especificação, valores CSS3 para <color>
. Cada um dos exemplos a seguir descreve a mesma cor.
// these all set the fillStyle to 'orange' ctx.fillStyle = "orange"; ctx.fillStyle = "#FFA500"; ctx.fillStyle = "rgb(255,165,0)"; ctx.fillStyle = "rgba(255,165,0,1)";
hsl(100%,25%,0)
ou rgb(0,100%,0)
não são permitidos. Se você se ater aos valores acima, não terá nenhum problema.Nota do tradutor: Para visualizar uma lista de valores de cores, clique nesse link.
Um exemplo com fillStyle
Nesse exemplo, novamente usaremos dois loops for
para desenhar um grid de retângulos, cada um com uma cor diferente. A imagem resultante deve parecer com o screenshot abaixo. Não há nada de espetacular acontecendo aqui. Usamos suas variáveis i
e j
para gerar uma cor RGB única para cada quadrado, e apenas modificamos os valores para o vermelho e para o verde. Ao modificar esses canais, você pode gerar todos os tipos de paleta. Ao aumentar os passos, você pode conseguir algo similar a paleta de cores usada pelo Photoshop.
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); for (var i=0;i<6;i++){ for (var j=0;j<6;j++){ ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' + Math.floor(255-42.5*j) + ',0)'; ctx.fillRect(j*25,i*25,25,25); } } }
<canvas id="canvas" width="150" height="150"></canvas>
draw();
O resultado será o seguinte:
Screenshot | Live sample |
---|---|
![]() |
Um exemplo com strokeStyle
Esse exemplo é similar ao anterior, mas usa a propriedade strokeStyle
para alterar as cores do contorno das formas. Usamos o método arc()
para desenhar círculos ao invés de quadrados.
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); for (var i=0;i<6;i++){ for (var j=0;j<6;j++){ ctx.strokeStyle = 'rgb(0,' + Math.floor(255-42.5*i) + ',' + Math.floor(255-42.5*j) + ')'; ctx.beginPath(); ctx.arc(12.5+j*25,12.5+i*25,10,0,Math.PI*2,true); ctx.stroke(); } } }
<canvas id="canvas" width="150" height="150"></canvas>
draw();
O resultado deve ser o seguinte:
Screenshot | Live sample |
---|---|
![]() |
Transparência
Além do desenho de formas opacas no canvas, podemos também desenhar formas semi-transparentes ou translúcidas. Isso é feito pela definição da propriedade globalAlpha
ou associando uma cor semi-transparente ao estilo do contorno ou do preenchimento.
globalAlpha = transparencyValue
- Aplica o valor de transparência à todas as formas que serão desenhadas futuramente no canvas. O valor precisa estar entre 0.0 (totalmente transparente) à 1.0 (totalmente opção). O valor 1.0 (totalmente opaco) é o padrão.
A propriedade globalAlpha
pode ser útil se quiser desenhar várias formas no canvas com transparência similar, mas normalmente é mais útil configurar a transparência de formas individuais quando se ajusta suas cores.
Como as propriedades strokeStyle
e fillStyle
aceitam valores de cores CSS3, podemos usar a seguinte notação para definir a transparência da cor:
// Assigning transparent colors to stroke and fill style ctx.strokeStyle = "rgba(255,0,0,0.5)"; ctx.fillStyle = "rgba(255,0,0,0.5)";
A função rgba()
é parecida com a função rgb()
mas possui um parâmetro extra. O último parâmetro ajusta a transparência dessa cor em particular. A faixa válida de valores é, novamente, entre 0.0 (totalmente transparente) e 1.0 (totalmente opaco).
Um exemplo com globalAlpha
Nesse exemplo, um fundo de quatro diferentes quadrados coloridos. Em cima deles, desenharemos um conjunto de círculos semi-transparentes, A propriedade globalAlpha
será ajustada para 0.2 que será usada para todas as formas dessa ponto em diante, Cada passo do loop for
desenha um conjunto de círculos com um raio crescente. O resultado final é um gradiente radial. Ao sobrepor cada vez mais círculos um sobre o outro, reduzimo efetivamente a transparência dos círculos que já foram desenhados. Ao aumentar o contador e, assim, desenhando mais círculos, o fundo desaparece completamente no centro da imagem.
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // draw background ctx.fillStyle = '#FD0'; ctx.fillRect(0,0,75,75); ctx.fillStyle = '#6C0'; ctx.fillRect(75,0,75,75); ctx.fillStyle = '#09F'; ctx.fillRect(0,75,75,75); ctx.fillStyle = '#F30'; ctx.fillRect(75,75,150,150); ctx.fillStyle = '#FFF'; // set transparency value ctx.globalAlpha = 0.2; // Draw semi transparent circles for (i=0;i<7;i++){ ctx.beginPath(); ctx.arc(75,75,10+10*i,0,Math.PI*2,true); ctx.fill(); } }
<canvas id="canvas" width="150" height="150"></canvas>
draw();
Screenshot | Live sample |
---|---|
![]() |
Um exemplo usando rgba()
Nesse segundo exemplo, faremos algo similar ao exemplo acima, mas ao invés de desenhar círculos um sobre o outro, desenharemos quadrados com opacidade crescente. O uso da função rgba()
dá a você um pouco mais de controle e flexibilidade pois podemos ajustar o preenchimento e o contorno individualmente.
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // Draw background ctx.fillStyle = 'rgb(255,221,0)'; ctx.fillRect(0,0,150,37.5); ctx.fillStyle = 'rgb(102,204,0)'; ctx.fillRect(0,37.5,150,37.5); ctx.fillStyle = 'rgb(0,153,255)'; ctx.fillRect(0,75,150,37.5); ctx.fillStyle = 'rgb(255,51,0)'; ctx.fillRect(0,112.5,150,37.5); // Draw semi transparent rectangles for (var i=0;i<10;i++){ ctx.fillStyle = 'rgba(255,255,255,'+(i+1)/10+')'; for (var j=0;j<4;j++){ ctx.fillRect(5+i*14,5+j*37.5,14,27.5) } } }
<canvas id="canvas" width="150" height="150"></canvas>
draw();
Screenshot | Live sample |
---|---|
![]() |
Estilos de linha
Existem diversas propriedades que nos permitem definir o estilo das linhas.
lineWidth = value
- Ajusta a largura das linhas desenhas a partir desse ponto em diante.
lineCap = type
- Ajusta a aparência do final das linhas.
lineJoin = type
- Ajusta a aparência dos “cantos” onde as linhas se encontram.
miterLimit = value
- Estabelece um limite da esquadria (miter) quando duas linhas se juntam em um ângulo agudo, para permitir que você controle quão denso a junção será.
Você entenderá melhor do que cada propriedade faz através da observação dos exemplos a seguir.
Um exemplo com lineWidth
Essa propriedade ajusta a espessura atual da linha. Os valores devem ser números positivos. Por padrão esse valor é ajustada para 1.0 unidade.
A largura da linha é a espessura do contorno centralizado em um caminho dado. Em outras palavras, a área que é desenhada e estende-se para metade da largura da linha em qualquer lado da caminho. Como as coordenadas do canvas não referenciam diretamente pixels, cuidados especiais devem ser tomados para obter linhas horizontais e verticais limpas.
No exemplo a seguir, 10 linhas retas são desenhadas com larguras crescentes. A linha da extremidade mais à esquerda tem largura 1.0. Porém, as outras linhas que tem uma densidade com um valor inteiro diferente não aparentam pureza, por causa do posicionamento do caminho.
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); for (var i = 0; i < 10; i++){ ctx.lineWidth = 1+i; ctx.beginPath(); ctx.moveTo(5+i*14,5); ctx.lineTo(5+i*14,140); ctx.stroke(); } }
<canvas id="canvas" width="150" height="150"></canvas>
draw();
Screenshot | Live sample |
---|---|
![]() |
Obter linhas limpas requer conhecimento de como os caminhos são feitos. Nas imagens abaixo, o grid representa o grid de coordenadas do canvas. Os quadrados entre as as linhas do grid são pixels da tela. Na imagem do primeiro grid, um retângulo de (2,1) a (5,5) é preenchido. Toda a área entre os pontos (linha vermelha) está dentro dos limites do pixel, de forma que o retângulo resultante terá cantos limpos.
Se você considerar um caminho de (3,1) a (3,5) com uma espessura de linha de 1.0, terminará com a situação da segunda imagem. A área a ser preenchida (azul escuro) se estende apenas a metade dos pixels em cada lado no caminho. Uma aproximação disso precisa ser renderizada, o que significa que pixels estão sendo parcialmente sombreados, e o resultado é que toda a área (azul claro e azul escuro) será preenchida com uma cor apenas metade escura em relação a cor do contorno. Isso é o que acontece com a espessura de linha 1.0 no exemplo anterior.
Para corrigir isso, temos que ser bastante precisos na criação de nosso caminho. Sabendo que uma largura de 1.0 irá se estender meia unidade para cada lado do caminho, criar um caminho de (3.5,1) a (3.5,5) resulta na situação da terceira imagem – a linha de espessura 1.0 acaba preenchendo completamente e precisamente o espaço de um único pixel vertical.
lineCap
cujo valor padrão é butt
; você pode querer computar contornos consistentes com coordenadas de meio pixel para linhas com larguras estranhas, pela definição de lineCap
para square
, de forma que as bordas externas do contorno em torno do endpoint sejam automaticamente estendidas para cobrir exatamente o pixel inteiro.Observe também que apenas os endpoints iniciais e finais de um caminho são afetados: se um caminho for fechado com
closePath()
, não haverá um endpoint inicial ou final; ao invés disso, todos os endpoints do caminho serão conectados aos seus segmentos anteriores e posteriores usando o ajuste atual de lineJoin
, cujo valor padrão é miter
, tendo como efeito a extensão automática das bordas externas dos segmentos conectados para seus pontos de itersecção, de forma que os contornos renderizados irão cobrir exatamente os pixels centralizados em cada endpoint se estes segmentos forem horizontais e/ou verticais. Veja as próximas seções para demonstrações desses estilos de linhas adicionais.Para linhas de mesma largura, cada metade acaba sendo uma quantidade inteira de pixels, de forma que você quer um caminho que esteja esteja entre os pixels (3,1) e (3,5), ao invés de algo no meio desses valores.
Enquanto é um pouco doloroso se trabalhar com gráficos 2D escaláveis inicialmente, prestando atenção ao grid de pixels e à posição dos caminhos garante que seus desenhos irão parecer corretos não importando a escala ou qualquer outra transformação envolvida. Uma linha vertical de largura 1.0 desenhada na posição correta tornará-se uma linha limpa de 2 pixels quando escalonada em 2 unidades, e aparecerá na posição correta.
Um exemplo com lineCap
A propriedade lineCap
determina como os endpoints de cada linha serão desenhados. Existem três valores para essa propriedade, que são: butt
, round
e square
. Por padrão, o valor dessa propriedade é butt
.
butt
- Os finais da linha são retos nos endpoints.
round
- Os finais da linha são arredondados.
square
- Os finais da linha são retos pelo acréscimo de uma caixa com uma largura igual e metada da altura da espessura da linha.
Nesse exemplo, desenhamos três linhas, cada uma com um valor diferente para a propriedade lineCap
. Também é recomendado adicionar dois guias para visualizar as diferenças exatas entre as três. Cada uma dessas linhas inicia e termina exatamente nessas guias.
A linha a esquerda usa a opção padrão butt
. Você observará que ela é desenhada completamente nivelada com as guias. A segunda usa a opção round
. Isso adiciona um semi-circulo no final cujo raio é metade da espessura da linha. A linha à direita usa a opção square
. Isso adiciona uma caixa com uma largura igual e cuja altura é metade da espessura da linha.
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var lineCap = ['butt','round','square']; // Draw guides ctx.strokeStyle = '#09f'; ctx.beginPath(); ctx.moveTo(10,10); ctx.lineTo(140,10); ctx.moveTo(10,140); ctx.lineTo(140,140); ctx.stroke(); // Draw lines ctx.strokeStyle = 'black'; for (var i=0;i<lineCap.length;i++){ ctx.lineWidth = 15; ctx.lineCap = lineCap[i]; ctx.beginPath(); ctx.moveTo(25+i*50,10); ctx.lineTo(25+i*50,140); ctx.stroke(); } }
<canvas id="canvas" width="150" height="150"></canvas>
draw();
Screenshot | Live sample |
---|---|
![]() |
Um exemplo de lineJoin
A propriedade lineJoin
determina como dois segmentos que se conectam (de linhas, arcos ou curvas) com comprimentos não nulos em uma forma são conectados entre si (segmentos degenerados com comprimento nulo, cujos endpoints especificados e pontos de controle estão exatamente na mesma posição, são ignorados).
Existem três valores possíveis para essa propriedade: round
, bevel
e miter
. Por padrão, o valor dessa propriedade é miter
. Observe que o ajuste dessa propriedade não tem nenhum efeito se os dois segmentos tiverem a mesma direção, porque nesse caso nenhuma área de junção será adicionada.
round
- Arredonda os cantos de um forma pelo preenchimento de um setor adicional de disco centralizado no endpoint comum aos segmentos. O raio desses cantos é igual a largura da linha.
bevel
- Preenche uma área triangular adicional entre os endpoints comuns dos segmentos, e os cantos retangulares externos e separados de cada segmento.
miter
- Segmentos que se conectam são juntados pela extensão de seus cantos externos para conecta-los em um único ponto, com o efeito de preencher uma área em forma de um losango adicional. Esse ajuste é afetada pela propriedade
miterLimit
que é explicada a seguir.
O exemplo a seguir desenha três caminhos diferentes, demonstrando cada um desses ajustes da propriedades lineJoin
; a saída é mostrada logo abaixo.
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var lineJoin = ['round','bevel','miter']; ctx.lineWidth = 10; for (var i=0;i<lineJoin.length;i++){ ctx.lineJoin = lineJoin[i]; ctx.beginPath(); ctx.moveTo(-5,5+i*40); ctx.lineTo(35,45+i*40); ctx.lineTo(75,5+i*40); ctx.lineTo(115,45+i*40); ctx.lineTo(155,5+i*40); ctx.stroke(); } }
<canvas id="canvas" width="150" height="150"></canvas>
draw();
Screenshot | Live sample |
---|---|
![]() |
Uma demonstração da propriedade miterLimit
Como foi visto no exemplo anterior, quando se une duas linhas com a opção miter
, os cantos externos das duas linhas que se unem são estendidas até o ponto onde elas de unem. Para linhas que estão a grandes distâncias angulares umas da outras, esse ponto não fica longe do ponto de conexão. Porém, a medida que esse ângulo entre as linhas diminui, a distância (comprimento do esquadro – miter) entre esses pontos aumenta exponencialmente.
A propriedade miterLimit
determina quão distantes os pontos de conexão externos podem ser posicionados a partir dos pontos de conexão internos. Se duas linhas excederem esses valor, uma junta bisel é desenhada no lugar. Observe que o comprimento máximo do esquadro (miter) é o produto da largura da linha medida no sistema de coordenadas atual, pelo valor de sua propriedade miterLimit
(cujo valor padrão é 10.0 no .<canvas>
do HTML), de forma que miterLimit
pode ser configurada independentemente da escala de exibição atual ou qualquer transformação afim: ele influencia apenas forma efetivamente renderizada dos cantos da linha.
Mais exatamente, o limite do esquadro é a maior taxa de extensão do comprimento permitido (no canvas do HTML, é a medida entre o canto externo dos cantos juntados da linha e o endpoint comum dos segmentos que se conectam) para metade da espessura da linha. Ele pode ser definido de forma equivalente como a maior razão permitida da distância entre os pontos de junção internos e externos, para a espessura total da linha. É igual, finalmente, ao cosecante da metade do menor ângulo interno dos segmentos que se conectam abaixo, onde nenhuma junção será renderizada, apenas um chanfro:
miterLimit
= maxmiterLength
/lineWidth
= 1 / sin ( min θ / 2 )- O limite padrão do esquadro (miter) de 10.0 irá tirar todos os esquadros de ângulos agudos menores que 11 graus.
- Um limite de esquadro (miter) igual a √2 ≈ 1.4142136 (arredondado) irá tirar todos os ângulos agudos, mantendo as juntas dos esquadros apenas para ângulos obtusos ou retos.
- Um limite de esquadro (miter) igual a 1.0 é válido mas irá desabilitar todos os esquadros.
- Valores menores que 1.0 são inválidos.
A seguir uma pequena demonstração na qual você pode ajustar dinamicamente a propriedade miterLimit
e visualizar como isso afeta as formas no canvas. As linhas azuis mostram onde os endpoints começam e terminam para cada uma das linhas no zig-zag.
Se você especificar um valor de 4.2 para miterLimit
nessa demonstração, nenhum dos cantos visíveis irá se juntar com uma extensão do esquadro, mas apenas um pequeno chanfro próximo as linhas azuis; com um miterLimit
acima de 10, muitos cantos dessa demonstração devem se juntar com um esquadro bem distante das linhas azuis, e seus tamanhos estarão diminuindo entre os cantos da esquerda para a direita porque eles se conectam com ângulos maiores; com valores intermediários, os cantos do lado esquerdo irão de juntar com um chanfro próximo as linhas azuis, e os do lado direito com uma extensão do esquadro (também com comprimento decrescente).
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // Clear canvas ctx.clearRect(0,0,150,150); // Draw guides ctx.strokeStyle = '#09f'; ctx.lineWidth = 2; ctx.strokeRect(-5,50,160,50); // Set line styles ctx.strokeStyle = '#000'; ctx.lineWidth = 10; // check input if (document.getElementById('miterLimit').value.match(/\d+(\.\d+)?/)) { ctx.miterLimit = parseFloat(document.getElementById('miterLimit').value); } else { alert('Value must be a positive number'); } // Draw lines ctx.beginPath(); ctx.moveTo(0,100); for (i=0;i<24;i++){ var dy = i%2==0 ? 25 : -25 ; ctx.lineTo(Math.pow(i,1.5)*2,75+dy); } ctx.stroke(); return false; }
<table> <tr> <td><canvas id="canvas" width="150" height="150"></canvas></td> <td>Change the <code>miterLimit</code> by entering a new value below and clicking the redraw button.<br><br> <form onsubmit="return draw();"> <label>Miter limit</label> <input type="text" size="3" id="miterLimit"/> <input type="submit" value="Redraw"/> </form> </td> </tr> </table>
document.getElementById('miterLimit').value = document.getElementById('canvas').getContext('2d').miterLimit; draw();
Screenshot | Live sample |
---|---|
![]() |
Gradientes
Como em qualquer programa de desenho normal, podem preencher e contornar as formas usando gradientes lineares ou radiais. Criamos um objeto canvasGradient
pelo uso de um dos seguintes métodos. Podemo assim associar esse objetos às propriedades fillStyle
ou strokeStyle
.
createLinearGradient(x1, y1, x2, y2)
- Crie um objeto de gradiente linear com ponto inicial em (
x1
,y1
) e ponto final em (x2
,y2
). createRadialGradient(x1, y1, r1, x2, y2, r2)
- Cria um gradiente radial. Os parâmetros representam dois círculos, um com centro em (
x1
,y1
) e raior1
, e o outro com centro em (x2
,y2
) com raio emr2
.
Por exemplo:
var lineargradient = ctx.createLinearGradient(0, 0, 150, 150); var radialgradient = ctx.createRadialGradient(75, 75, 0, 75, 75, 100);
Uma vez que tenhamos criado um objeto canvasGradient
podemos associar cores a ele usando o método addColorStop()
.
gradient.addColorStop(position, color)
- Cria um novo ponto de cor para o objeto
gradient
. O parâmetroposition
é um número entre 0.0 e 1.0 e define a posição relativa da cor no gradiente, e o argumentocolor
precisa ser uma String que represente um código CSS para<color>
, indicando a cor que o gradiente deve alcançar no intervalo da transição.
Você pode adicionar quantos pontos de cor quiser a um gradiente. Abaixo segue um exemplo bastante simples de gradiente linear da cor branca para a preta.
var lineargradient = ctx.createLinearGradient(0,0,150,150); lineargradient.addColorStop(0, 'white'); lineargradient.addColorStop(1, 'black');
Um exemplo com createLinearGradient
Nesse exemplo, criaremos dois gradientes diferentes. Como pode ver, tanto a propriedade strokeStyle
quanto a propriedade fillStyle
aceitam o objeto canvasGradient
como entrada válida.
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // Create gradients var lingrad = ctx.createLinearGradient(0,0,0,150); lingrad.addColorStop(0, '#00ABEB'); lingrad.addColorStop(0.5, '#fff'); lingrad.addColorStop(0.5, '#26C000'); lingrad.addColorStop(1, '#fff'); var lingrad2 = ctx.createLinearGradient(0,50,0,95); lingrad2.addColorStop(0.5, '#000'); lingrad2.addColorStop(1, 'rgba(0,0,0,0)'); // assign gradients to fill and stroke styles ctx.fillStyle = lingrad; ctx.strokeStyle = lingrad2; // draw shapes ctx.fillRect(10,10,130,130); ctx.strokeRect(50,50,50,50); }
<canvas id="canvas" width="150" height="150"></canvas>
draw();
O primeiro é um gradiente de fundo. Como pode ver, associamos duas cores na mesma posição. Você faz isso para criar transições de cores bastante agudas – nesse caso, do branco para o verde; Normalmente não importa em que ordem você define os pontos de cor, mas nesse caso em especial, importa significativamente; Se você manter as associações na ordem em que quer que elas apareçam, isso não será um problema.
No segundo gradiente, não associamos uma cor inicial (na posição 0.0) pois isso não é estritamente necessário, porque será assumida automaticamente a cor do próximo do ponto. Por isso, associando a cor preta à posição 0.5 automaticamente faz o gradiente, do início até esse ponto, preto.
Screenshot | Live sample |
---|---|
![]() |
Um exemplo com createRadialGradient
Nesse exemplo, definiremos gradientes radiais; Por termos controle sobre os pontos de início e termino do gradiente, podem conseguir efeitos mais complexos do que normalmente conseguiríamos em gradientes radiais “clássicos” já vistos, por exemplo, no Photoshop (isto é, um gradiente com um ponto central único de onde o gradiente se expande em uma forma circular).
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // Create gradients var radgrad = ctx.createRadialGradient(45,45,10,52,50,30); radgrad.addColorStop(0, '#A7D30C'); radgrad.addColorStop(0.9, '#019F62'); radgrad.addColorStop(1, 'rgba(1,159,98,0)'); var radgrad2 = ctx.createRadialGradient(105,105,20,112,120,50); radgrad2.addColorStop(0, '#FF5F98'); radgrad2.addColorStop(0.75, '#FF0188'); radgrad2.addColorStop(1, 'rgba(255,1,136,0)'); var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40); radgrad3.addColorStop(0, '#00C9FF'); radgrad3.addColorStop(0.8, '#00B5E2'); radgrad3.addColorStop(1, 'rgba(0,201,255,0)'); var radgrad4 = ctx.createRadialGradient(0,150,50,0,140,90); radgrad4.addColorStop(0, '#F4F201'); radgrad4.addColorStop(0.8, '#E4C700'); radgrad4.addColorStop(1, 'rgba(228,199,0,0)'); // draw shapes ctx.fillStyle = radgrad4; ctx.fillRect(0,0,150,150); ctx.fillStyle = radgrad3; ctx.fillRect(0,0,150,150); ctx.fillStyle = radgrad2; ctx.fillRect(0,0,150,150); ctx.fillStyle = radgrad; ctx.fillRect(0,0,150,150); }
<canvas id="canvas" width="150" height="150"></canvas>
draw();
Nesse caso, deslocamos o ponto inicial levemente do ponto final para conseguir uma efeito 3D esférico. É melhor evitar que os círculos internos e externos se sobreponham pois isso resulta em efeitos estranhos difíceis de serem previstos.
O último ponto de cor dos quatro gradientes usa uma cor totalmente transparente. Se quiser ter uma transição legal deste ponto para o anterior, as duas cores devem ser iguais. Isso não é muito óbvio no código porque ele usa dois métodos de cor CSS diferentes para efeitos de demonstração, mas no primeiro gradiente #019F62 = rgba(1,159,98,1)
.
Screenshot | Live sample |
---|---|
![]() |
Padrões
Em um dos exemplos do artigo anterior, usamos uma série de loops para criar um padrão de imagens. Existe, porém, um método muito mais simples: o método createPattern()
.
createPattern(image, type)
- Crie e retorna um novo objeto de padrão.
image
é umCanvasImageSource
(isto é, um element is used to embed video content in an HTML or XHTML document.” href=”/en-US/docs/Web/HTML/Element/video”><video>
, ou o que preferir).type
é uma String que indica como usar essa imagem.
O tipo especifica como usar a imagem de forma a criar o padrão, e precisa ter um dos seguintes valores:
repeat
- Ladrilha a imagem tanto nas direções verticais quanto horizontais.
repeat-x
- Ladrilha a imagem horizontalmente mas não verticalmente.
repeat-y
- Ladrilha a imagem verticalmente mas não horizontalmente.
no-repeat
- Não ladrilha a imagem. Ela é usada apenas uma vez.
repeat
. Se você usar qualquer outra, não verá nenhuma mudança.CanvasPattern
de forma análoga aos métodos para criar gradientes visto acima. Uma vez que tenhamos criado um padrão, podemos associa-lo as proprieddes fillStyle
ou strokeStyle
. Por exemplo:var img = new Image(); img.src = 'someimage.png'; var ptrn = ctx.createPattern(img,'repeat');
drawImage()
, você deve se certificar que a imagem que você está usando esteja carregada antes de chamar esse método ou o padrão pode ser desenhado incorretamente.Um exemplo com createPattern
Nesse último exemplo, criaremos um padrão para ser associada à propriedade fillStyle
. A única coisa que vale a pena ser mencionada é o uso do manipulador onload
de image. Isso é feito para garantir que a imagem tenha sido carregada antes dela ser associada ao padrão.
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); // create new image object to use as pattern var img = new Image(); img.src = '/files/222/Canvas_createpattern.png'; img.onload = function(){ // create pattern var ptrn = ctx.createPattern(img,'repeat'); ctx.fillStyle = ptrn; ctx.fillRect(0,0,150,150); } }
<canvas id="canvas" width="150" height="150"></canvas>
draw();
O resultado deve ser o seguinte:
Screenshot | Live sample |
---|---|
![]() |
Sombras
O uso de sombras envolve apenas quatro propriedades:
shadowOffsetX = float
- Indica a distância horizontal que a sombra deve tomar do objeto. Esse valor não é afetado pela matriz de transformação. O padrão é 0.
shadowOffsetY = float
- Indica a distância vertical que a sombra deve tomar do objeto. Esse valor não é afetado pela matriz de transformação. O padrão é 0.
shadowBlur = float
- Indica o tamanho do efeito de obscurecimento; esse valor não corresponde ao número de pixel e não é afetado pela matriz de transformação. O padrão é 0.
shadowColor =
<color>
- Um valor de cor CSS padrão que indica a cor do efeito de sombreamento; por padrão, é preto totalmente transparente.
shadowOffsetX
e shadowOffsetY
indicam quão longe a sombra deve se estender do objeto nas direções X e Y; esses valores não são afetados pela matriz de transformação atual. Use valores negativos para fazer com que a sombra se estenda para cima ou para a esquerda, e valores positivos para fazer com que se estenda para baixo ou para a direita. Eles são 0 por padrão.
shadowBlur
indica o tamanho do efeito de sombreamento; esse valor não corresponde ao número de pixel e não é afetado pela matriz de transformação. O padrão é 0.
shadowColor
é um valor de cor CSS padrão que indica a cor do efeito de sombreamento; por padrão, é preto totalmente transparente.
Um exemplo de texto sombreado
Esse exemplo desenha uma String de texto com um efeito de sombreamento.
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); ctx.shadowOffsetX = 2; ctx.shadowOffsetY = 2; ctx.shadowBlur = 2; ctx.shadowColor = "rgba(0, 0, 0, 0.5)"; ctx.font = "20px Times New Roman"; ctx.fillStyle = "Black"; ctx.fillText("Sample String", 5, 30); }
<canvas id="canvas" width="150" height="80"></canvas>
draw();
Screenshot | Live sample |
---|---|
![]() |