Stavo cercando un metodo per fare animazioni sul web e sono incappato su questa APi nativa di javascript... il canvas.
Capii subito che era uno strumento potente e molto utile per il mio scopo, quindi mi misi subito a studiarlo, non fu facile e ancora adesso penso di sfruttarlo in minima parte.
Una delle cose che più mi piace è che si può gestire interamente con javascript e che a fronte di grafiche complesse mantiene una buona fluidità.
Saranno solo delle spiegazioni basilari che ci serviranno per creare animazioni, grafici e videogiochi più complessi.
Cos'è l'animazione?
L'animazione è una rapida succesione di immagini statiche che ingannano l'occhio, facendole percepire in movimento.
Quando da piccolo mi annoiavo a scuola (molto spesso) mi divertivo a disegnare su gli angoli del libro un omino stilizzato che ad ogni pagina cambiava posizione così che quando lo sfogliavo velocemente si animava.
Ok, i miei non erano così belli.
Animazioni con il canvas
Vediamo come riprodurre questa tecnica nel canvas?
Come esempio faremo muovere un cerchio per il canvas.
Per prima cosa dobbiamo creare un ciclo che disegni l'oggetto ad ogni intervallo di tempo.
La prima funzione js che verrebbe in mente è setInterval(), ma non è adatto per le animazioni perchè ha delle limitazioni da non rendelo la scelta giusta.
Per questo è stato creato il metodo requestAnimationFrame() creato apposta per sopperire a queste limitazioni.
Inizializziamo il canvas.
Questa è una versione breve, se volete apporfondire vi mando in un articolo più completo.
- html
<canvas id="myCanvas"></canvas>
- js
let canvas = document.getElementById('myCanvas');
canvas.width = 600;
canvas.height = 400;
let ctx = canvas.getContext('2d');
Per gestire l'animazione dobbiamo creare una normale funzione che richiameremo ciclicamente, dove andremo a disegnare un cerchio.
(Canvas javascript : Disegnare figure geometriche con curve, per chi avesse bisogno di un ripassino.)
let loop = () => {
ctx.beginPath();
ctx.arc(0, 200, 50, 0, 2 * Math.PI);
ctx.stroke();
};
La funzione che abbiamo chimamato loop() deve essere chiamata per la prima volta dal metodo requestAnimationFrame che come parametro ha quest'ultima. La funzione loop va passata senza parentesi, perchè non dobbiamo chiamarla ma... passarla. Il metodo avvisa il bowser di preparsi che verrà usata una funzione per gestire l'animazione.
let loop = () => {
ctx.beginPath();
ctx.arc(0, 200, 50, 0, 2 * Math.PI);
ctx.stroke();
};
requestAnimationFrame(loop);
Per chiudere il cerchio, la funzione loop verrà richiamata alla fine con il metodo requestAnimationFrame così da diventare ricorsiva.
let loop = () => {
ctx.beginPath();
ctx.arc(0, 200, 50, 0, 2 * Math.PI);
ctx.stroke();
requestAnimationFrame(loop);
};
requestAnimationFrame(loop)
Il programma per adesso disegna un cerchio, ma non si muove perchè i valori x e y sono sempre fissi.
Vediamo come spostaro nelle varie direzioni.
Per prima cosa decidiamo di quanti pixel vogliamo spostarlo, in questo caso di 5px.
Quindi ad ogni ciclo lo sposteremo di 5px.
Per la direzione ho creato uno schemino esemplicativo, così da rendermi la spiegazione più facile.
Se vogliamo farlo muovere sul asse orizzontale ad ogni ciclo dobbiamo aggiungere un valore positivo alla x se vogliamo che si muova alla destra, mentre se gli assegnamo un valore negativo si sposterà a sinistra.
Uguale per l'asse verticale, valore positivo per il basso e valore negativo per mandarlo in alto.
Per le diagonali dobbiamo assegnare ad entrambi le posizioni un valore, ma alternando positivo e negativo in base alla direzione da prendere, come nello schemino.
const step = 5;
let x = 0;
let loop = () => {
ctx.beginPath();
ctx.arc(x, 200, 50, 0, 2 * Math.PI);
ctx.stroke();
x += step;
requestAnimationFrame(loop);
};
requestAnimationFrame(loop)
Abbiamo creato una costante step che ci dice di quanto si sposterà il cerchio e l'altra è la variabile x che sostituirà il primo argomento della funzione arc, adibita allo spostamento orizzontale verso destra, inizializzata a 0.
*Nella funzione loop ho aggiunto il comando che aumentera la posizione x * di 5px (step) ad ogni ciclo.
Questo è il risultato e non è quello che ci aspettavamo.
In precedenza ho scritto che l'oggetto si sposta, perchè è quello che vedono i nostri occhi, in verità, l'oggetto non si sposta ad ogni ciclo, ma viene disegnato in una nuova posizione, percui il cerchio precedentemente disegnato non sparisce, ma si somma ogni volta.
La soluzione a questo problema è che ad ogni inizio ciclo il canvas venisse ripulito e per fare questo ci viene in contro una funzione specifica, ctx.clearRect, che permette di cancellare una porzione rettangolare del canvas.
Se lo facciamo partire dal punto di origine (x:0, y:0) e lo facciamo grande delle stesse dimensioni del canvas, ripulirà il tutto, riportandolo come nuovo.
Un altro problema riscontrato è che una volta uscito dal margine destro, il cerchio partirà per la tangente e non lo rivremo più.
Ci sono varie soluzioni, come quello di creargli dei bordi, ma per adesso lo faremo ripartire dal margine sinistro ogni volta che esce dallo schermo.
const step = 5;
let x = 0;
let loop = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(x, 200, 50, 0, 2 * Math.PI);
ctx.stroke();
x = x + step;
x === canvas.width + 50 && (x = -50)
requestAnimationFrame(loop)
};
requestAnimationFrame(loop)
Quando la x del cerchio più il raggio ( se no sparisce quando il centro del cerchio raggiunge il margine) raggiunge il margine destro ricompare nella posizione x = 0 - 50, margine sinistro che vale 0 meno il raggio.
CONCLUSIONE
Abbiamo visto come funziona un animazione con il canvas, facendo spostare un cerchio. Ok, non è una grande animazione, ed è una cosa che si può fare con il css, ma questo ci ha permesso di mettere le basi per animazioni più complesse.
Nel prossimo articolo andremo ad imparare come gestire gli fps e la velocità con il quale si spostera l'oggetto.
Se avete dei consigli, suggerimenti o critiche costruttive lasciatemi un commento qui sotto oppure contattatemi trammite i miei social.
EXTRA
Vi lascio con il codice un po' più ordinato e riutilizzabile, usando le classi in js.
let canvas = document.getElementById("myCanvas");
let ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 400;
class Circle {
constructor(x, y, radius){
this.x = x;
this.y = y;
this.radius = radius;
this.step = 5;
}
draw(){
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
ctx.stroke();
}
update(){
this.x += this.step;
this.whenBorderIsFinished()
}
whenBorderIsFinished(){
this.x === canvas.width + this.radius && ( this. x = -this.radius)
}
}
let loop = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
circle.draw();
circle.update();
requestAnimationFrame(loop)
};
circle = new Circle(0, 200, 50);
requestAnimationFrame(loop);
Top comments (0)