Em um mundo de shaders, malhas e filtros, o Canvas2D pode não ser tão interessante. Mas deveria estar.
Entre 30% e 40% das páginas da Web têm um elemento <canvas>
, e 98% de todas as telas usam um contexto de renderização
Canvas2D. Há Canvas2Ds em carros, em geladeiras
e no espaço (sério).
É verdade que a API está um pouco desatualizada em relação ao desenho 2D de última geração. Felizmente, trabalhamos muito para implementar novos recursos no Canvas2D e acompanhar o CSS, simplificar a ergonomia e melhorar a performance.
Parte 1: atualização do CSS
O CSS tem alguns comandos de desenho que estão faltando na Canvas2D. Com a nova API, adicionamos alguns dos recursos mais solicitados:
Retângulo arredondado
Retângulos arredondados: a base da Internet, da computação, da noite, da civilização.
Os retângulos arredondados são extremamente úteis: como botões, balões de chat, miniaturas, balões de fala, você escolhe. Sempre foi possível fazer um retângulo arredondado no Canvas2D, mas era um pouco confuso:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'magenta';
const top = 10;
const left = 10;
const width = 200;
const height = 100;
const radius = 20;
ctx.beginPath();
ctx.moveTo(left + radius, top);
ctx.lineTo(left + width - radius, top);
ctx.arcTo(left + width, top, left + width, top + radius, radius);
ctx.lineTo(left + width, top + height - radius);
ctx.arcTo(left + width, top + height, left + width - radius, top + height, radius);
ctx.lineTo(left + radius, top + height);
ctx.arcTo(left, top + height, left, top + height - radius, radius);
ctx.lineTo(left, top + radius);
ctx.arcTo(left, top, left + radius, top, radius);
ctx.stroke();
Tudo isso foi necessário para um retângulo arredondado simples e modesto:
Com a nova API, há um método roundRect()
.
ctx.roundRect(upper, left, width, height, borderRadius);
Portanto, o exemplo acima pode ser substituído por:
ctx.roundRect(10, 10, 200, 100, 20);
O método ctx.roundRect()
também recebe uma matriz para o argumento borderRadius
de até quatro
números. Esses raios controlam os quatro cantos do retângulo arredondado da mesma maneira
que no CSS. Exemplo:
ctx.roundRect(10, 10, 200, 100, [15, 50, 30]);
Confira a demonstração para brincar.
Gradiente cônico
Você já viu gradientes lineares:
const gradient = ctx.createLinearGradient(0, 0, 200, 100);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(0.5, 'magenta');
gradient.addColorStop(1, 'white');
ctx.fillStyle = gradient;
ctx.fillRect(10, 10, 200, 100);
Gradientes radiais:
const radialGradient = ctx.createRadialGradient(150, 75, 10, 150, 75, 70);
radialGradient.addColorStop(0, 'white');
radialGradient.addColorStop(0.5, 'magenta');
radialGradient.addColorStop(1, 'lightblue');
ctx.fillStyle = radialGradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
Mas e um gradiente cônico legal?
const grad = ctx.createConicGradient(0, 100, 100);
grad.addColorStop(0, 'red');
grad.addColorStop(0.25, 'orange');
grad.addColorStop(0.5, 'yellow');
grad.addColorStop(0.75, 'green');
grad.addColorStop(1, 'blue');
ctx.fillStyle = grad;
ctx.fillRect(0, 0, 200, 200);
Modificadores de texto
Os recursos de renderização de texto de Canvas2Ds ficaram muito atrasados. O Chrome adicionou vários novos atributos à renderização de texto do Canvas2D:
- ctx.letterSpacing
- ctx.wordSpacing
- ctx.fontVariant
- ctx.fontKerning
- ctx.fontStretch
- ctx.textDecoration
- ctx.textUnderlinePosition
- ctx.textRendering
Todos esses atributos correspondem às contrapartes do CSS com os mesmos nomes.
Parte 2: ajustes ergonômicos
Antes, algumas coisas com o Canvas2D eram possíveis, mas a implementação era desnecessariamente complicada. Confira algumas melhorias na qualidade de vida para desenvolvedores de JavaScript que querem usar o Canvas2D:
Redefinição de contexto
Para explicar como limpar uma tela, escrevi uma pequena função para desenhar um padrão retro:
draw90sPattern();
Ótimo! Agora que terminei esse padrão, quero limpar a tela e desenhar outra coisa.
Como limpar uma tela? Boa! ctx.clearRect()
, é claro.
ctx.clearRect(0, 0, canvas.width, canvas.height);
Não funcionou. Boa! Primeiro, preciso redefinir a transformação:
ctx.resetTransform();
ctx.clearRect(0, 0, canvas.width, canvas.height);

Perfeito! Uma tela em branco. Agora vamos começar a desenhar uma linha horizontal:
ctx.moveTo(10, 10);
ctx.lineTo(canvas.width, 10);
ctx.stroke();
Grrrr! Isso não está certo. 😡 O que essa linha extra está fazendo aqui? Além disso, por que ele está rosa? Ok, vamos verificar o StackOverflow.
canvas.width = canvas.width;
Por que isso é tão? Por que isso é tão difícil?
Mas isso acabou. Com a nova API, temos uma API simples, elegante e inovadora:
ctx.reset();
Lamentamos a demora.
Filtros
Os filtros SVG são um mundo à parte. Se você não conhece esse recurso, recomendamos a leitura de The Art Of SVG Filters And Why It Is Awesome, que mostra um pouco do potencial incrível deles.
Os filtros de estilo SVG já estão disponíveis para Canvas2D. Você só precisa transmitir o filtro como um URL que aponta para outro elemento de filtro SVG na página:
<svg>
<defs>
<filter id="svgFilter">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" />
<feConvolveMatrix kernelMatrix="-3 0 0 0 0.5 0 0 0 3" />
<feColorMatrix type="hueRotate" values="90" />
</filter>
</defs>
</svg>
const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 400;
const ctx = canvas.getContext('2d');
document.body.appendChild(canvas);
ctx.filter = "url('#svgFilter')";
draw90sPattern(ctx);
O que atrapalha bastante o nosso padrão:
Mas e se você quiser fazer o que foi mencionado acima, mas permanecer no JavaScript e não mexer com strings? Com a nova API, isso é totalmente possível.
ctx.filter = new CanvasFilter([
{ filter: 'gaussianBlur', stdDeviation: 5 },
{
filter: 'convolveMatrix',
kernelMatrix: [
[-3, 0, 0],
[0, 0.5, 0],
[0, 0, 3],
],
},
{ filter: 'colorMatrix', type: 'hueRotate', values: 90 },
]);
Simples assim. Teste e brinque com os parâmetros na demonstração aqui.
Parte 3: melhorias de desempenho
Com a nova API Canvas2D, também queríamos melhorar o desempenho sempre que possível. Adicionamos alguns recursos para dar aos desenvolvedores um controle mais detalhado dos sites e permitir as taxas de quadros mais suaves possíveis:
Vai ler com frequência
Use getImageData()
para ler os dados de pixels de uma tela. Isso pode ser muito lento. A nova API oferece
uma maneira de marcar explicitamente uma tela para leitura (para efeitos generativos, por exemplo).
Isso permite otimizar as coisas em segundo plano e manter a tela rápida para uma variedade maior de casos de uso. Esse recurso já existe há algum tempo no Firefox, e agora ele faz parte da especificação
da tela.
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
Perda de contexto
Vamos deixar as guias tristes felizes de novo! Caso um cliente fique sem memória da GPU ou algum outro problema ocorra na tela, agora é possível receber um callback e redesenhar conforme necessário:
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.addEventListener('contextlost', onContextLost);
canvas.addEventListener('contextrestored', redraw);
Se você quiser saber mais sobre o contexto e a perda de tela, o WHATWG tem uma boa explicação no wiki.
Conclusão
Não importa se você é novo no Canvas2D, se já o usa há anos ou se evita usá-lo há anos, dê outra olhada no canvas. É a API vizinha que estava lá o tempo todo.