In un mondo di shader, mesh e filtri, Canvas2D potrebbe non entusiasmarti. ma dovrebbe esserlo.
Il 30-40% delle pagine web contiene un elemento <canvas>
e il 98% di tutti i canvas utilizza un contesto di rendering Canvas2D. Esistono Canvas2D nelle auto, nei frigoriferi
e nello spazio (in realtà).
Bisogna ammettere che l'API è un po' indietro rispetto alle ultime novità in fatto di disegno 2D. Fortunatamente abbiamo lavorato duramente per implementare nuove funzionalità in Canvas2D per recuperare CSS, snellire l'ergonomia e migliorare le prestazioni.
Parte 1: aggiornamento con CSS
CSS ha alcuni comandi di disegno che mancano a Canvas2D. Con la nuova API abbiamo aggiunto alcune delle funzionalità più richieste:
Rettangolo arrotondato
Rettangoli arrotondati: la pietra angolare di internet, dell'informatica, della civiltà.
A parte gli scherzi, i rettangoli arrotondati sono estremamente utili: come pulsanti, bolle di chat, miniature, bolle di dialogo e così via. È sempre stato possibile creare un rettangolo arrotondato in Canvas2D, ma era un po' complicato:
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();
Tutto questo era necessario per un rettangolo arrotondato semplice e modesto:
Con la nuova API è disponibile un metodo roundRect()
.
ctx.roundRect(upper, left, width, height, borderRadius);
Pertanto, quanto sopra può essere completamente sostituito da:
ctx.roundRect(10, 10, 200, 100, 20);
Il metodo ctx.roundRect()
accetta anche un array per l'argomento borderRadius
di massimo quattro
numeri. Questi raggi controllano i quattro angoli del rettangolo arrotondato nello stesso modo
come per il CSS. Ad esempio:
ctx.roundRect(10, 10, 200, 100, [15, 50, 30]);
Dai un'occhiata alla demo per provare.
Gradiente conico
Hai visto le sfumature lineari:
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);
Sfumature radiali:
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);
Ma che dire di un bel gradiente conico?
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);
Modificatori di testo
Le funzionalità di rendering del testo di Canvas2D sono molto indietro. Chrome ha aggiunto diversi nuovi attributi al rendering del testo Canvas2D:
- ctx.letterSpacing
- ctx.wordSpacing
- ctx.fontVariant
- ctx.fontKerning
- ctx.fontStretch
- ctx.textDecoration
- ctx.textUnderlinePosition
- ctx.textRendering
Questi attributi corrispondono a quelli CSS con gli stessi nomi.
Parte 2: modifiche ergonomiche
In precedenza, alcune operazioni con Canvas2D erano possibili, ma inutilmente complesse da implementare. Di seguito sono riportati alcuni miglioramenti della qualità di vita per gli sviluppatori JavaScript che vogliono utilizzare Canvas2D:
Reimpostazione del contesto
Per spiegare come cancellare una tela, ho scritto una piccola funzione per disegnare un motivo retrò:
draw90sPattern();
Bene. Ora che ho finito con questo motivo, voglio cancellare la tela e disegnare qualcos\'altro.
Aspetta, come faccio a cancellare una tela? Oh sì! ctx.clearRect()
, certo.
ctx.clearRect(0, 0, canvas.width, canvas.height);
Huh... non ha funzionato. Oh sì! Devo prima reimpostare la trasformazione:
ctx.resetTransform();
ctx.clearRect(0, 0, canvas.width, canvas.height);
Perfetto! Una bella tela bianca. Ora iniziamo a disegnare una bella linea orizzontale:
ctx.moveTo(10, 10);
ctx.lineTo(canvas.width, 10);
ctx.stroke();
Grrrr! Non è corretto! 😡 Che cosa ci fa questa riga in più? Inoltre, perché è rosa? Ok, controlla su StackOverflow.
canvas.width = canvas.width;
Perché è così sciocco? Perché è così difficile?
Beh, non più. Con la nuova API abbiamo una soluzione semplice, elegante e bella, che rappresenta una vera e propria rivoluzione:
ctx.reset();
Ci dispiace molto.
Filtri
I filtri SVG sono un mondo a parte. Se non li hai mai utilizzati, ti consiglio di leggere The Art Of SVG Filters And Why It Is Awesome, che mostra alcune delle loro straordinarie potenzialità.
I filtri di stile SVG sono già disponibili per Canvas2D. Devi solo avere la volontà di passare il filtro come un URL che punta a un altro elemento filtro SVG nella pagina:
<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);
Il che rovina il nostro pattern:
E se volessi eseguire quanto sopra, ma rimanere in JavaScript e non confondere le stringhe? Con la nuova API, questo è del tutto possibile.
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 },
]);
Un gioco da ragazzi! Prova e gioca con i parametri nella demo qui.
Parte 3: miglioramenti delle prestazioni
Con la nuova API Canvas2D, volevamo anche migliorare le prestazioni, ove possibile. Abbiamo aggiunto alcune funzionalità per offrire agli sviluppatori un controllo più granulare dei loro siti web e consentire le framerate più fluide possibili:
Leggerà spesso
Utilizza getImageData()
per leggere i dati dei pixel da una tela. Può essere molto lento. La nuova API ti offre un modo per contrassegnare esplicitamente una tela per la lettura (ad esempio per gli effetti generativi).
In questo modo puoi ottimizzare il funzionamento interno e mantenere la velocità di Canvas per una maggiore varietà di casi d'uso. Questa funzionalità è disponibile in Firefox da un po' di tempo e finalmente è stata inserita nelle specifiche del canvas.
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
Perdita di contesto
Rendiamo di nuovo felici le schede tristi. Se un client esaurisce la memoria della GPU o si verifica un altro problema con la tela, ora puoi ricevere un callback e ridisegnare la tela in base alle esigenze:
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.addEventListener('contextlost', onContextLost);
canvas.addEventListener('contextrestored', redraw);
Se vuoi saperne di più sul contesto e sulla perdita di canvas, WHATWG fornisce una buona spiegazione nella sua wiki.
Conclusione
Che tu non abbia mai utilizzato Canvas2D, lo stia usando da anni o lo stia evitando da anni, ti consiglio di dare un'altra occhiata a Canvas. È l'API di cui hai sempre avuto bisogno.