Animazioni con il Canvas di javascript: Come cos'è e come implementarlo con un esempio base
Tags: animazione, javascript, canvas
Published: 2021-02-21 14:44:28

---
title: Animazioni con il Canvas di javascript: Come cos'è e come implementarlo con un esempio base
published: true
description: Come cos'è e come implementare le animazioni nel canvas
tags: #animazione #js #javascript #canvas
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/61vvvs852cqnyznlrri1.jpg
---

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. 

{% youtube p3q9MM__h-M %}

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](https://dev.to/camizzilla/canvas-javascript-un-potente-strumento-per-la-grafica-sul-web-4334) più completo.  

* html
``` html 
<canvas id="myCanvas"></canvas>
```

* js
``` 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](https://dev.to/camizzilla/canvas-javascript-disegnare-figure-geometriche-con-curve-1l63), per chi avesse bisogno di un ripassino.)

``` js
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.

``` js
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**. 

``` js
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.

 ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1wastl0vndukr1a170ow.jpg)

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.

``` js

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.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nci63yqfxh5t7335rckd.png)

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.

``` javascript
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.

{% codepen https://codepen.io/camizzilla/pen/YzpNYbd %}

#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.

``` javascript 
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);

```