Introduzione a Canvas
Impara l'elemento HTML <canvas>: sistema di coordinate, contesto di rendering 2D, scaling per schermi ad alta densità, accessibilità ed esempi.
L'elemento HTML <canvas> è una superficie di disegno rettangolare che controlli interamente tramite script. L'elemento stesso è solo un contenitore vuoto — non disegna nulla da solo. Si usa JavaScript per impartire comandi di disegno che dipingono pixel su di esso.
Questa pagina introduce l'elemento <canvas>, il suo sistema di coordinate, il contesto di rendering 2D e le operazioni di disegno più comuni: forme, testo, gradienti, linee e immagini.
Cos'è l'elemento <canvas>?
<canvas> fornisce una bitmap — una griglia di pixel su cui disegni immediatamente. Una volta che una forma è dipinta, il canvas non la ricorda come oggetto; è semplicemente pixel colorati. Questa è la differenza chiave rispetto a SVG, dove ogni forma rimane un nodo DOM che puoi ridefinire nello stile o animare individualmente.
Questo compromesso guida la scelta di quando usare il canvas:
- Scegli
<canvas>per il controllo a livello di pixel, migliaia di oggetti, animazioni veloci fotogramma per fotogramma, giochi, elaborazione di immagini, grafici con molti dati o effetti particellari. Poiché è in modalità "immediata", ridisegnare è economico. - Scegli SVG quando hai bisogno di vettori indipendenti dalla risoluzione, icone scalabili, un numero gestibile di forme da ispezionare, cliccare o animare tramite CSS/DOM.
- Scegli CSS per layout, transizioni ed effetti su elementi HTML ordinari — non per disegno libero.
Puoi inserire più di un elemento <canvas> nella stessa pagina HTML, ognuno con il proprio contesto.
Il sistema di coordinate
Un canvas utilizza una griglia di coordinate 2D. L'origine (0, 0) si trova nell'angolo in alto a sinistra. L'asse x cresce verso destra e l'asse y cresce verso il basso — nota che y cresce verso il basso, al contrario di un grafico matematico. Un punto (100, 60) si trova quindi a 100 pixel dal bordo sinistro e 60 pixel dall'alto.
L'area di disegno è definita dagli attributi width e height (in pixel CSS):
<canvas id="canvas" width="250" height="150"></canvas>Imposta le dimensioni del canvas con gli attributi width e height, non con CSS. CSS width/height si limita a stirare la bitmap esistente, rendendo il disegno sfocato. Aggiungi un bordo con l'attributo style o una classe.
Il contesto di rendering 2D
Non si disegna mai direttamente sull'elemento <canvas> — si disegna tramite un contesto di rendering, un oggetto che espone l'API di disegno. Lo si ottiene con getContext():
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');getContext('2d') restituisce un CanvasRenderingContext2D, che contiene ogni metodo e proprietà usati di seguito (fillRect, arc, fillText, strokeStyle e così via). È il punto di partenza giusto per quasi tutto il disegno 2D.
Esistono altri tipi di contesto per esigenze diverse:
'webgl'/'webgl2'— 3D accelerato dalla GPU (e 2D ad alte prestazioni) tramite l'API OpenGL ES.'bitmaprenderer'— visualizza unImageBitmapsenza una propria API di disegno.
Questo capitolo usa solo il contesto '2d'.
Accessibilità: contenuto di fallback
Tutto ciò che inserisci tra i tag di apertura e chiusura <canvas> è contenuto di fallback. I browser che supportano canvas lo ignorano; i browser (o le tecnologie assistive) che non riescono a renderizzare il canvas lo mostrano al suo posto. Poiché i pixel disegnati sono invisibili agli screen reader, usa questo spazio per descrivere il grafico, oppure aggiungi un aria-label / role affinché il canvas venga annunciato in modo significativo.
<canvas id="canvas" width="250" height="150" role="img" aria-label="A blue circle on a white background">
A blue circle on a white background.
</canvas>Per i canvas interattivi (giochi, app di disegno), fornisci come fallback veri controlli HTML con focus all'interno dell'elemento, poiché i pixel stessi non possono ricevere il focus tramite tastiera.
Esempio del tag HTML <canvas>:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="canvas" width="250" height="150" style="border:1px solid #1c87c9;">
The HTML5 canvas tag is not supported by your browser.
</canvas>
</body>
</html>Esempio del tag HTML <canvas> per disegnare un cerchio:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="exampleCanvas" width="200" height="200" style="border:1px solid #dddddd;">
HTML5 canvas tag is not supported by your browser.
</canvas>
<script>
const c = document.getElementById("exampleCanvas");
const ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(100, 100, 60, 0, 2 * Math.PI);
ctx.strokeStyle = '#009299';
ctx.stroke();
</script>
</body>
</html>Il metodo arc() accetta cinque argomenti: arc(x, y, radius, startAngle, endAngle). Qui (100, 100) è il centro del cerchio, 60 è il raggio in pixel e l'arco va dall'angolo 0 a 2 * Math.PI. Gli angoli si misurano in radianti e un cerchio completo è 2π radianti, quindi da 0 a 2 * Math.PI si disegna il cerchio per intero. beginPath() avvia un nuovo percorso e stroke() lo traccia usando il strokeStyle corrente. Per riempirlo invece, imposta fillStyle e chiama fill(). Approfondisci in Canvas drawing e Canvas coordinates.
Esempio del tag HTML <canvas> per disegnare un testo:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="exampleCanvas" width="350" height="110" style="border:1px solid #dddddd;">
HTML5 canvas tag is not supported by your browser.
</canvas>
<script>
const c = document.getElementById("exampleCanvas");
const ctx = c.getContext("2d");
ctx.font = "40px Arial";
ctx.fillStyle = '#262ac7';
ctx.fillText("Canvas Text", 55, 65);
</script>
</body>
</html>fillText(text, x, y) dipinge testo riempito alle coordinate indicate. La proprietà font usa la notazione abbreviata CSS standard per i font. Vedi Canvas text per allineamento, contorno del testo e misurazione della larghezza.
Esempio del tag HTML <canvas> per disegnare un gradiente lineare:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="exampleCanvas" width="300" height="140" style="border:1px solid #dddddd;">
The HTML5 canvas tag is not supported by your browser.
</canvas>
<script>
const c = document.getElementById("exampleCanvas");
const ctx = c.getContext("2d");
const grd = ctx.createLinearGradient(0, 0, 300, 0);
grd.addColorStop(0, "#359900");
grd.addColorStop(1, "#ffffff");
ctx.fillStyle = grd;
ctx.fillRect(20, 20, 250, 100);
</script>
</body>
</html>createLinearGradient(x0, y0, x1, y1) definisce la direzione del gradiente tramite due punti. Qui da (0, 0) a (300, 0) è un gradiente orizzontale da sinistra a destra. addColorStop(offset, color) posiziona un colore a una posizione da 0 (inizio) a 1 (fine), quindi il verde sfuma nel bianco. Assegnare il gradiente a fillStyle fa sì che fillRect(x, y, width, height) lo usi per dipingere. Approfondisci in Canvas gradients.
Esempio del tag HTML <canvas> per disegnare una linea:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="exampleCanvas" width="150" height="150" style="border:1px solid #cccccc;">
The HTML5 canvas tag is not supported by your browser.
</canvas>
<script>
const c = document.getElementById("exampleCanvas");
const ctx = c.getContext("2d");
ctx.moveTo(0, 0);
ctx.lineTo(150, 150);
ctx.strokeStyle = '#86417d';
ctx.stroke();
</script>
</body>
</html>moveTo(x, y) solleva la "penna" su un punto di partenza senza disegnare, e lineTo(x, y) aggiunge un segmento rettilineo fino a quel punto. Nulla appare finché non chiami stroke(). Vedi Canvas drawing per percorsi a più segmenti, larghezza della linea e giunzioni.
Esempio del tag HTML <canvas> per disegnare un'immagine:
Per essere autonomo (ed evitare problemi di cross-origin — vedi la nota qui sotto), questo esempio usa una piccola immagine SVG inline come data URI anziché una foto remota:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<h2>Draw an image with canvas</h2>
<canvas id="exampleCanvas" width="220" height="120" style="border:1px solid #dddddd;"></canvas>
<script>
const canvas = document.getElementById('exampleCanvas');
const ctx = canvas.getContext('2d');
const image = new Image();
image.addEventListener('load', () => {
// drawImage(image, dx, dy) draws at the given top-left position
ctx.drawImage(image, 10, 10);
// Scaled copy: drawImage(image, dx, dy, dWidth, dHeight)
ctx.drawImage(image, 120, 10, 50, 50);
});
image.src =
"data:image/svg+xml," +
encodeURIComponent(
'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">' +
'<circle cx="50" cy="50" r="45" fill="#1c87c9" /></svg>'
);
</script>
</body>
</html>drawImage() accetta tre forme: drawImage(image, dx, dy), drawImage(image, dx, dy, dWidth, dHeight) per scalare, e drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) per ritagliare un rettangolo sorgente (s*) e posizionarlo in un rettangolo destinazione (d*). Disegna sempre all'interno dell'evento load dell'immagine in modo che i pixel siano pronti. Vedi Canvas images per saperne di più.
Problema CORS. Disegnare un'immagine proveniente da un'altra origine senza gli appositi header CORS "contamina" il canvas. Dopo di che, getImageData() e toDataURL() generano un errore di sicurezza. Se hai bisogno di leggere i pixel da un'immagine remota, questa deve essere servita con header CORS permissivi e caricata con image.crossOrigin = "anonymous" prima di impostare src.
Esempio del tag HTML <canvas> per disegnare un gradiente circolare:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="exampleCanvas" width="260" height="160" style="border:1px solid #cdcdcd;">
The HTML5 canvas tag is not supported by your browser.
</canvas>
<script>
const c = document.getElementById("exampleCanvas");
const ctx = c.getContext("2d");
const grd = ctx.createRadialGradient(150, 75, 10, 115, 90, 150);
grd.addColorStop(0, "purple");
grd.addColorStop(1, "white");
ctx.fillStyle = grd;
ctx.fillRect(20, 20, 220, 120);
</script>
</body>
</html>createRadialGradient(x0, y0, r0, x1, y1, r1) sfuma tra due cerchi: un cerchio iniziale (centro (150, 75), raggio 10) e un cerchio finale (centro (115, 90), raggio 150). I color stop sfumano dal viola al cerchio interno fino al bianco a quello esterno, producendo il bagliore rotondo. Confronta con createLinearGradient sopra e approfondisci in Canvas gradients.
Display ad alta densità (Retina)
Negli schermi ad alta densità, un pixel CSS corrisponde a più pixel fisici del dispositivo. Un canvas dimensionato solo in pixel CSS risulta quindi sfocato su quei display. La soluzione è scalare la bitmap per window.devicePixelRatio e poi scalare il contesto in modo che le coordinate di disegno rimangano invariate:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const ratio = window.devicePixelRatio || 1;
// CSS size (layout) stays the same:
const cssWidth = 250;
const cssHeight = 150;
canvas.style.width = cssWidth + 'px';
canvas.style.height = cssHeight + 'px';
// Backing bitmap gets more device pixels:
canvas.width = cssWidth * ratio;
canvas.height = cssHeight * ratio;
// Scale once so you keep drawing in CSS-pixel coordinates:
ctx.scale(ratio, ratio);Dopo questo, disegnare arc(100, 100, 60, …) produce un cerchio nitido sia su schermi standard che Retina.
Capitoli correlati
- Canvas drawing — percorsi, rettangoli, riempimenti e contorni
- Canvas text — font, allineamento e misurazione del testo
- Canvas coordinates — la griglia, traslazione e rotazione
- Canvas gradients — sfumature di colore lineari e radiali
- Canvas images — disegno e manipolazione di bitmap
- Canvas reference — elenco completo dei metodi e delle proprietà del contesto