gennaio 27, 2021 · NodeJS

Creare un grafico con NodeJS e Chart.js

Una delle migliori librerie per la creazione di grafici in Javascript è Chart.js. E' stata però pensata per disegnare grafici su pagine web, e il suo uso in una applicazione NodeJS non è così immediato poichè ChartJS disegna sul canvas, un componente che esiste solo in un browser web. Per fortuna esiste una libreria per NodeJS (ChartjsNodeCanvas) che simula il canvas e permette di usare ChartJS in un'applicazione NodeJS. Proviamo a costruire assieme un piccolo esempio.

Per prima cosa creiamo un nuovo progetto NodeJS con le solite modalità.

Aggiungiamo le nostre dipendenze:

npm install chart.js chartjs-node-canvas

Predisponiamo il nostro file src/index.js. Per prima cosa importiamo il componente ChartJSNodeCanvas dalla libreria chartjs-node-canvas, e il componente fs (già presente in NodeJS) che ci servirà per il salvataggio dell'immagine prodotta su filesystem.

import { ChartJSNodeCanvas } from 'chartjs-node-canvas';
import fs from 'fs';

Inizializziamo il componente, impostando le dimensioni in pixel del canvas su cui andare a disegnare il grafico:

const width = 500;
const height = 250;
const chartJSNodeCanvas = new ChartJSNodeCanvas({width, height});

Predisponiamo un piccolo metodo per costruire un dataset casuale. Il dataset sarà un array composto da 20 oggetti, ciascuno dei quali contenente una label (sequenziale 0-19) e un value (intero casuale tra 0 e 20).

/**
 * Returns an array of {label, value} elements. Labels are sequential from 0,
 * values are random integers from 0 to 20.
 * @param {number} length Length.
 * @returns Random dataset of length elements.
 */
function randomDataset(length = 20){

  const dataset = [];
  
  let i;
  for (i=0; i<length; i++){
    dataset.push({
      label: i,
      value: Math.floor(Math.random()*20)
    })
  }

  return dataset;

}

A questo punto possiamo creare il metodo principale, quello che genera il grafico.

/**
 * Creates histogram.
 * @param {Object[]} dataset
 */
async function createPlot(dataset) {

  const configuration = {
    type: 'bar',
    data: {
      labels: dataset.map(element => element['label']),
      datasets: [
        {
          label: `Valori a caso`,
          backgroundColor: 'red',
          borderColor: 'red',
          data: dataset.map(element => element['value'])
        },
      ]
    },
    options: {
      title: {
        display: true,
        text: `Valori a caso, così, tanto per ridere`
      },
      legend: {
        position: 'bottom',
        display: false
      }
    }
  };

  const image = await chartJSNodeCanvas.renderToBuffer(configuration, 'image/png');
  fs.writeFileSync(`chart.png`, image);

}

Il metodo sopra fa sostanzialmente tre cose:

A questo punto dobbiamo solo richiamare il metodo createPlot(), passandogli un dataset creato da randomDataset(). Il metodo createPlot() non può essere chiamato semplicemente dal corpo del programma poichè è asincrono, e vogliamo attenderne il termine per essere certi che il file sia stato scritto completamente su disco prima del termine del nostro programma. Per poterlo chiamare dobbiamo creare un ulteriore metodo asincrono, e in questo chiamare l'await del nostro metodo. Tutto questo può essere risolto con una sola riga:

(async () => await createPlot(randomDataset()))()

A questo punto il nostro programma è completato. Proviamo ad eseguirlo, e se tutto è andato per il verso giusto dovremmo trovarci nella root del progetto un file "chart.png" simile a questo:

Voilà!