Introduzione
HTML5 Canvas è uno strumento molto potente per disegnare grafica 2D direttamente nel browser. A differenza degli elementi HTML tradizionali, Canvas non descrive contenuti “statici” come testo o immagini: offre invece una superficie di disegno su cui possiamo tracciare forme, linee, colori, immagini e animazioni tramite JavaScript.
In questo tutorial vedremo un sotto-argomento pratico e utile: realizzare un misuratore circolare interattivo, simile a un indicatore di volume, velocità o avanzamento. È un esempio molto utile perché combina diversi concetti fondamentali di Canvas:
- disegno di archi e cerchi;
- uso delle coordinate polari;
- testo centrato nel canvas;
- aggiornamento dinamico della grafica in risposta all’input dell’utente.
Questo tipo di componente è frequente in dashboard, pannelli di controllo, applicazioni IoT e interfacce di monitoraggio. Impararlo significa acquisire una base solida per costruire elementi grafici più complessi.
Codice completo
<canvas id="gauge" width="420" height="420"></canvas>
<div>
<label for="value">Valore: <span id="valueLabel">65</span>%</label>
<input id="value" type="range" min="0" max="100" value="65">
</div>
<script>
const canvas = document.getElementById("gauge");
const ctx = canvas.getContext("2d");
const slider = document.getElementById("value");
const valueLabel = document.getElementById("valueLabel");
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 140;
function drawGauge(value) {
// Pulizia completa del canvas prima di ridisegnare
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Sfondo
ctx.fillStyle = "#f7f9fc";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Cerchio esterno
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
ctx.fillStyle = "#ffffff";
ctx.fill();
ctx.lineWidth = 12;
ctx.strokeStyle = "#d9e2ec";
ctx.stroke();
// Arco di base: rappresenta il range totale
const startAngle = Math.PI * 0.75; // 135°
const endAngle = Math.PI * 2.25; // 405°
const totalAngle = endAngle - startAngle;
ctx.beginPath();
ctx.arc(centerX, centerY, radius - 20, startAngle, endAngle);
ctx.strokeStyle = "#e6eef7";
ctx.lineWidth = 22;
ctx.lineCap = "round";
ctx.stroke();
// Arco progressivo: rappresenta il valore corrente
const progressAngle = startAngle + (totalAngle * value) / 100;
ctx.beginPath();
ctx.arc(centerX, centerY, radius - 20, startAngle, progressAngle);
ctx.strokeStyle = value < 50 ? "#2f9e44" : value < 80 ? "#f59f00" : "#e03131";
ctx.lineWidth = 22;
ctx.lineCap = "round";
ctx.stroke();
// Tacche di riferimento
for (let i = 0; i <= 10; i++) {
const tickValue = i * 10;
const angle = startAngle + (totalAngle * tickValue) / 100;
const innerX = centerX + Math.cos(angle) * (radius - 55);
const innerY = centerY + Math.sin(angle) * (radius - 55);
const outerX = centerX + Math.cos(angle) * (radius - 35);
const outerY = centerY + Math.sin(angle) * (radius - 35);
ctx.beginPath();
ctx.moveTo(innerX, innerY);
ctx.lineTo(outerX, outerY);
ctx.strokeStyle = "#94a3b8";
ctx.lineWidth = 3;
ctx.stroke();
}
// Valore centrale
ctx.fillStyle = "#1f2937";
ctx.font = "bold 54px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(value + "%", centerX, centerY - 10);
// Etichetta
ctx.fillStyle = "#64748b";
ctx.font = "18px Arial";
ctx.fillText("Carico sistema", centerX, centerY + 38);
// Indicatore puntatore
const needleAngle = progressAngle;
const needleLength = radius - 65;
const needleX = centerX + Math.cos(needleAngle) * needleLength;
const needleY = centerY + Math.sin(needleAngle) * needleLength;
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.lineTo(needleX, needleY);
ctx.strokeStyle = "#0f172a";
ctx.lineWidth = 5;
ctx.lineCap = "round";
ctx.stroke();
// Centro del puntatore
ctx.beginPath();
ctx.arc(centerX, centerY, 10, 0, Math.PI * 2);
ctx.fillStyle = "#0f172a";
ctx.fill();
}
// Primo disegno
drawGauge(Number(slider.value));
// Aggiornamento interattivo
slider.addEventListener("input", () => {
const value = Number(slider.value);
valueLabel.textContent = value;
drawGauge(value);
});
</script> Spiegazione
Il codice crea un misuratore circolare composto da più livelli grafici. Vediamo i passaggi principali.
1. Inizializzazione del canvas
La prima operazione è ottenere il contesto 2D con getContext("2d"). Questo oggetto, chiamato spesso ctx, contiene tutti i metodi per disegnare forme, testo e immagini.
Le variabili centerX e centerY servono per posizionare il centro del gauge, mentre radius definisce la dimensione complessiva del componente.
2. Pulizia e sfondo
Ogni volta che il valore cambia, il canvas viene ridisegnato da zero. Questo è importante perché Canvas non aggiorna automaticamente i singoli elementi: se vuoi cambiare qualcosa, devi cancellare e ridisegnare l’intera scena.
Per questo usiamo clearRect() e poi riempiamo lo sfondo con fillRect().
3. Cerchio esterno e arco di base
Il misuratore ha un anello esterno bianco con bordo grigio e un arco di base che rappresenta il range totale. Il range non è un cerchio completo: parte da 135° e arriva a 405°, così il gauge resta aperto nella parte inferiore e risulta più leggibile.
Gli angoli in Canvas sono espressi in radianti, non in gradi. Per questo troviamo valori come Math.PI * 0.75 invece di 135°.
4. Arco progressivo
L’arco colorato mostra il valore corrente. Se il valore è basso, il colore è verde; se cresce diventa arancione, e oltre una certa soglia passa al rosso. Questo è un esempio semplice ma efficace di feedback visivo.
5. Tacche di riferimento
Le tacche vengono disegnate con un ciclo for. Per ogni tacca calcoliamo un angolo e poi ricaviamo le coordinate usando Math.cos() e Math.sin(). Questo è un passaggio fondamentale nella grafica circolare: il cerchio viene costruito matematicamente a partire dagli angoli.
6. Testo centrale
Il valore percentuale viene mostrato al centro del gauge. Per centrare il testo usiamo:
- textAlign = "center";
- textBaseline = "middle".
Queste proprietà semplificano molto la gestione del layout grafico nel canvas.
7. Puntatore
Il puntatore è una linea che parte dal centro e si estende fino al valore corrente. Serve a rendere la lettura più immediata, come in uno strumento analogico.
Infine disegniamo un piccolo cerchio centrale per coprire l’origine della linea e dare un aspetto più rifinito.
Best practice
Quando lavori con Canvas, ci sono alcune abitudini che migliorano molto qualità, manutenzione e prestazioni del codice.
- Separare logica e disegno: crea funzioni dedicate, come drawGauge(), invece di scrivere tutto in linea.
- Ridisegnare solo quando necessario: nel nostro caso aggiorniamo il canvas solo quando cambia lo slider.
- Usare variabili esplicite: centro, raggio e angoli sono più leggibili se dichiarati con nomi chiari.
- Gestire i colori in modo coerente: un sistema di colori chiaro aiuta l’utente a interpretare i dati più rapidamente.
- Tenere conto della leggibilità: testo e contrasti devono restare leggibili anche su schermi piccoli.
- Considerare il responsive design: in un progetto reale potresti adattare il canvas alla dimensione del contenitore e allo device pixel ratio.
Un’altra buona pratica è evitare di abusare di operazioni costose dentro cicli di animazione continui. Se il tuo gauge non deve animarsi ogni frame, è meglio ridisegnarlo solo in risposta agli input dell’utente.
Riepilogo
In questo tutorial abbiamo visto come creare un misuratore circolare interattivo con Canvas HTML5. L’esempio ti ha mostrato come combinare archi, linee, testo e interazione per costruire una grafica 2D utile e professionale.
- Canvas permette di disegnare elementi grafici dinamici nel browser.
- Gli archi sono perfetti per rappresentare valori progressivi.
- Le funzioni trigonometriche sono essenziali per lavorare con forme circolari.
- Un input range rende il componente interattivo e immediato.
- La pulizia e il ridisegno del canvas sono parte normale del flusso di lavoro.
Questo tipo di componente è un ottimo punto di partenza per dashboard, strumenti di monitoraggio e visualizzazioni personalizzate.
Approfondisci con risorse ufficiali
- MDN Web Docs - Canvas API: documentazione completa sui metodi di disegno e sul contesto 2D.
- MDN Web Docs - Using canvas: guida introduttiva molto utile per comprendere il flusso di lavoro base.
- MDN Web Docs - HTMLCanvasElement: riferimento sull’elemento canvas e sulle sue proprietà.
- WHATWG HTML Standard: specifica ufficiale per approfondire il comportamento standard di HTML5.
Se vuoi fare un passo successivo, prova a trasformare questo misuratore in un componente più avanzato: aggiungi animazione fluida, etichette numeriche lungo l’arco o una soglia di allarme lampeggiante. È un ottimo esercizio per consolidare le basi della grafica 2D con HTML5.
