Introduzione

Da qualche tempo ho la necessita’ di dover mantenere aggiornato un grafico di dati e di mostrarlo nei contesti piu’ differenti. I dati sono relativi al monitoraggio di tre grandezze con l’andare del tempo, a ognuna di queste terne e’ possibile associare delle descrizioni testuali (al momento inutilizzate).

La prima soluzione che ho adottato per gestire il problema e’ stata quella usare un foglio di calcolo di OpenOffice, condividendolo online con un servizio gratuito (DropBox nel mio caso) in modo da potervi accedere ogni qualvolta ne avessi bisogno.

Questa soluzione ha velocemente mostrato i suoi limiti:

  1. le capacita’ di plot dei fogli elettronici non mi soddisfano, soprattutto se la quantita’ di dati e’ considerevole ( > 500 elementi)
  2. per consultare/mostrare i dati, e’ necessario un computer con accesso internet e OpenOffice installato; come alternativa avrei potuto fare una immagine del grafico e metterla su una pagina web statica ma avrei dovuto poi aggiornarla ogni volta che venivano inseriti nuovi dati

Un mio collega mi ha allora suggerito di fare una piccola web application in php che permettesse l’inserimento e la visualizzazione dei dati da qualsiasi posto, a patto di avere una connessione internet.

Il vantaggi di questa scelta sarebbero stati:

  1. non aver bisogno di OpenOffice
  2. poter modificare/visualizzare i dati anche da una mobile device
  3. avere modo di personalizzare in piena liberta’ la visualizzazione dei dati

Cosi’ mi sono messo d’impegno e questo e’ il risultato dei miei sforzi.

La struttura della applicazione

L’idea e’ quella di fare una singola pagina html contentente:

  1. una form html con cui passare i dati ad una pagina php che a sua volta li scriva su un file csv
  2. la visualizzazione dei dati tramite un’altra funzione php che si occupi di caricarli e produrre un grafico tramite una libreria grafica php esterna.

Questa e’ una schematizzazione dell’intero processo:

Quando la pagina web viene caricata vengono costruiti i campi della form e si fa una visualizzazione dei dati esistenti. Al “submit” dei dati, viene invocata una routine php che li scrive su file e richiama la pagina web di partenza che, al caricamento, aggiornera’ i grafici.

La scelta della libreria grafica esterna

A questo punto mi sono messo alla ricerca di una libreria grafica php, all’inizio ho dato una occhiata alla arcinota GD e mi sono reso conto che avevo bisogno di una cosa molto piu’ ad alto livello.

Dopo qualche ricerca sono arrivato ad una rosa di candidate:

  1. Libchart
  2. pChart
  3. jpGraph

le prime due sono piu’ semplici da utilizzare e completamente gratuite, la terza e’ piu’ complessa e ha una versione “Professional” (commerciale). All’inizio ho pensato potessi procedere con una delle prime due, il rendering sembrava piu’ bello e le righe di codice meno, ma alla fine ho scelto jpGraph proprio perche’, cosi’ flessibile, mi ha permesso di gestire meglio i valori in ascissa.

L’esperienza di aver provato tutte e tre le librerie e’ stata in ogni caso positiva: mi ha “costretto” a migliorare il design iniziale della applicazione separando il codice di visualizzazione da quello con cui faccio I/O dal file csv.

Implementazione

L’applicazione e’ composta dunque dei seguenti elementi:

  1. una singola pagina web dove sono mostrati sia la form di input che il grafico dei dati
  2. un file php target della “action” della form
  3. un file php che si occupa dell’I/O
  4. un file php che si occupa della creazione di una immagine a partire dai dati di input

andiamo ad analizzarli uno per uno.

La pagina web

E’ una normalissima pagina web php con un suo minimale foglio di stile, qualche routine JavaScript, una form e qualche chiamata php.

Le parti salienti sono:

  1. La dichiarazione dei nomi dei files in php con tanto di costruzione di un path URI (path interno al server) e URL (per l’accesso esterno). Da notare che tutta questa costruzione di path serve soprattuto nel caso dati, pagina e codice php risiedano in cartelle diverse, altrimenti potremmo ignorare i path completamente (come d’altra parte avevo fatto in una prima implementazione). Perche’ farlo allora? per poter integrare queste cose in un CMS … ne discuteremo piu’ di seguito.
    Le URL servono per l’html, ad esempio:

    1. <img src=‘<?php echo $imageFileURL ?>’ />

    Le URI invece servono per passare i path dei file per l’elaborazione php, ad esempio:

    1. if ( file_exists($dataFileURI) )
  2. La form: oltre ai campi di inserimento dei dati, c’e’ un campo “password” che ragionevolmente sarebbe presente nel caso di una applicazione completa. Inoltre, sono presenti dei parametri nascosti che vengono passati alle routine php in modo da rendere il codice portabile: il nome del file dati da modificare e l’indirizzo per tornare alla pagina web una volta terminata l’elaborazione (poteva essere hardcoded ma non avrebbe funzionato bene in un CMS, vedi sotto).
  3. La part JavaScript serve per la validazione dei dati e per sapere l’URL di apertura della pagina. Quest’ultimo serve per passare l’indirizzo di ritorno alle routine php che andremo a vedere dopo; di nuovo, se pensassimo ad una semplice pagina web non ci sarebbe motivo per conoscere l’URL della pagina di apertura per “tornare” alla form, il passaggio dell’URL di ritorno serve per l’integrazione con un CMS. Da notare che per attaccare la routine di validazione della form all’evento “onsubmit” avrei potuto mettere il codice nell’header html e invece ho scelto questa soluzione perche’ e’ piu’ pulita e perche’, di nuovo, in un CMS non avremmo questa alternativa (e dovremo mettere il codice JavaScript inline).
  4. La parte php per costruire e mostrare i grafici: qui c’e’ la logica per costruire i due plot. Le librerie di charting permettono la creazione di una immagine al volo: all’inizio la cosa mi e’ sembrata molto comoda, soprattutto alla luce della integrazione con il CMS (dove salvare le immagini? molto piu’ comodo sarebbe costruirle al volo); pero’ salvando le immagini su file ho la possibilita’ di introdurre una ottimizzazione ed evitare di ricalcolare i grafici qualora i file di dati fossero meno recenti delle immagini dei plot:
    1.  
    2. // optimization: if csv file is older than image do not rebuild them
    3. if ( (file_exists($imageFileURI) &amp;&amp; filemtime($imageFileURI) < filemtime($dataFileURI)) || !file_exists($imageFileURI))
    4. {
    5.  

    Dunque la logica di questa parte e’ molto semplice: se esistono i file di dati e sono piu’ recenti delle immagini li rileggo e ricreo queste ultime:

    1.  
    2. read($dataFileURI, $xvalues, $yvalues1, $yvalues2, $yvalues3, $comments);
    3. buildPlotImage($imageFileURI, $xvalues, $yvalues1, $yvalues2, $yvalues3, $comments);
    4.  
    5. $xvaluesS = array_slice($xvalues, count($xvalues)-100);
    6. $yvalues1S = array_slice($yvalues1, count($xvalues)-100);
    7. $yvalues2S = array_slice($yvalues2, count($xvalues)-100);
    8. $yvalues3S = array_slice($yvalues3, count($xvalues)-100);
    9. buildPlotImage($imageTailFileURI, $xvaluesS, $yvalues1S, $yvalues2S, $yvalues3S, $comments);
    10.  

    da notare che:

    1. i grafici sono due, il secondo e’ fatto solo con la “coda” dei dati, gli ultimi 100 per la precisione (la scelta e’ del tutto arbitraria)
    2. (si’ sono pigro e questa parte non la voglio cambiare) adesso passo alle routine di plot anche le note testuali anche se al momento restano inutilizzate
    3. alle routine di plot vengono passati gli URI dei files, ossia i path interni al filesystem del server
  5. Infine vengono mostrati i due grafici:

    1.  
    2. if ($dataExists)
    3. {
    4. ?>
    5. <div style="text-align: center;">
    6. <h2>Output – complete set</h2>
    7. <img src="<?php echo $imageFileURL ?>" alt="" />
    8.  
    9. <img src="<?php echo $imageTailFileURL ?>" alt="" /></div>
    10. <?php
    11. }
    12. else
    13. {
    14. ?>
    15. <h2>Output – no data</h2>
    16.  

    in caso non ci fossero dati evitiamo di mostrare i plot

La routine target della form

Questa routine passa semplicemente i dati alla routine I/O di scrittura su file, avrei potuto scrivere i dati direttamente ma ho preferito isolare le routine di I/O in un file separato. I dati vengono prelevati dai parametri di POST, viene aggiunto ad essi il tempo corrente, cosi’ non sono costretto ad inserirlo io. La routine jpGraph ha modo di gestire automaticamente le ascisse in formato tempo quando questi dati sono espressi nella forma intera (formato della funzione POSIX time()).
Il controllo sulla “pseudo-password” l’ho messo in questo file, non so neanche se metterle una password hardcoded nel codice sia sicuro, ma non ho intenzione di approfondire questo tema perche’ lo scopo del post e’ un altro.

Le funzioni di I/O

Qui non c’e’ nessun mistero: la funzione write scrive su file un record (time, terna di 3 dati, descrizione testuale) la read legge tutti i dati dal file.

In questa occasione ho imparato a passare dei parametri by ref al php.

Le funzioni di disegno

Qui si utilizzano le funzioni della libreria jpGraph e i dati estratti dal file con la funzione read per costruire il plot; la libreria jpGraph non e’ semplice da utilizzare ma ha una estesa documentazione e una notevole quantita’ di esempi.

Per poter utilizzare dei font TrueType senza dovermi mettere il problema di cercarli nel server e trovare una soluzione alternativa nel caso mancassero, ho allegato i loro files alla applicazione. Segnalare dove cercare i font alla libreria jpGraph e’ semplicissmo:

  1. DEFINE("TTF_DIR","fonts/");

L’integrazione con WordPress

Adesso andiamo ad analizzare le scelte che ho adottato per poter inserire questa app dentro ad un CMS:

  1. problema dei path: le routine php, i file di dati, le immagini dei grafici non possono risiedere nella cartella dove e’ contenuta la pagina web, perche’ essa in realta’ viene costruita al volo dai dati presenti nel database
  2. indirizzo di ritorno: per la stessa ragione di cui sopra, l’indirizzo di ritorno va scoperto dinamicamente.
  3. il codice JavaScript non puo’ risiedere nell’header html perche’ quando si scrive un post non si puo’ accedere/modificare quella parte della pagina web ma solo il contenuto. Sono dunque costretto a metterlo inline (di nuovo: se lo metto in un file .js esterno poi come lo trovo?)
  4. Per poter creare una pagina di WP contentente codice php e Javascript ho forzato WordPress a rinunciare ad ogni tipo di interpretazione del contenuto della pagina; l’ho fatto usando il plugin “Text Control”;

Ecco cosa e’ venuto fuori

Ho preparato una pagina di esempio qui; ho fatto si’ che il campo che “simula” la password di cui abbiamo parlato sopra fosse riempito automaticamente.

Qui potete invece scaricare uno zip da mettere su un web server per vederlo all’opera da voi e modificarlo per fare degli esperimenti, eccolo qui: OnlinePlotExample.

Non ho voluto pero’ includere la libreria jpGraph perche’ altrimenti l’archivio diventava troppo grande, e’ da scaricare da qui e da mettere nella cartella php.

Futuri sviluppi

Questa piccola applicazione potrebbe essere migliorata in tanti modi, in particolare, come e’ possibile notare da subito, il design e’ piuttosto scadente, bisognerebbe fare una classe PHP ed evitare tutti gli intrecci html/php che ci sono nella pagina di plot e inserimento dati.

Inoltre, immagino che un prodotto finito e degno di tal nome dovrebbe prevedere una “installazione” in cui l’utente scelga

  1. il nome e la posizione del file dati
  2. una password per evitare che chiunque possa sporcargli i dati
  3. il numero di serie di record
  4. i valori da mostrare in ascissa
  5. il dominio dei record (per la validazione e la creazione del grafico: ad esempio valore minimo e massimo permessi)

in questo modo sarebbe anche possibile fornire un servizio multi-utente in cui chiuque possa accedere ad una pagina di configurazione e crearsi il proprio set di dati da mostrare.

Share

Un Commento a “Grafici online con PHP”

Lascia un Commento

Devi aver fatto il login per inviare un commento