Pagine

19 febbraio 2012

Nuova versione dei grafici dei reattori

Sono stato un po' latitante questa settimana, perché il poco tempo libero disponibile l'ho voluto investire in migliorare la pagina da cui è possibile sfogliare i grafici dei reattori di Fukushima.



Prima di inoltrarmi negli aspetti tecnici, che ovviamente non interessano al grande pubblico, ma possono essere di spunto per qualcuno che deve fare una cosa simile, voglio brevemente raccontarvi le novità implementate in questa nuova versione e che possono essere d'aiuto ai visitatori.

Le novità

Innanzitutto è cambiata la navigazione che a mio parere è stata resa più intuitiva. Dalla parte superiore della pagina è possibile scegliere quali grandezze rappresentare ed è possibile saltare direttamente ad un grafico di interesse cliccando sull'iconcina con la lente di ingrandimento riportata sotto ogni grafico. Vi ricordo che dopo ogni modifica dei parametri di visualizzazione, in altre parole ogni cambiamento che effettuate nella parte alta della pagina, dovete cliccare sul bottone Invia per aggiornare i grafici.

Tra le altre icone che trovate sotto ogni grafico, oltre alla lente di ingrandimento (terza icona da sinistra), trovate anche la possibilità di scaricare sul vostro PC i dati utilizzati per la costruzione del grafico in formato CSV (prima icona), che potete aprire con Excel o OpenOffice per costruire i vostri grafici personalizzati. La seconda icona è comoda se volete salvare il grafico in formato immagine (PNG) perché i grafici interattivi non possono essere salvati in formato grafico sul PC. L'ultima icona serve per ottenere il codice per incorporare il grafico interattivo nel vostro sito/blog, così che potete sempre tenerlo sotto controllo e mostrarlo anche ai vostri visitatori/lettori.


Gli aspetti tecnici: il nostro database anziché Google Spreadsheet

Se siete arrivati a leggere fino a qui è perché vi interessano anche gli aspetti tecnici che sono dietro alla nuova versione dei grafici. Il primo grosso cambiamento è stato sostituire al vecchio foglio di calcolo Google Spreadsheet con i dati, un nostro database MySQL dedicato come sorgente dei dati.

Google Chart Tools, lo strumento che ci permette di realizzare i grafici interattivi, può utilizzare come sorgente dei dati sia i fogli di calcolo di Google Documents sia le tavole di Fusion Tables. Nulla vieta però di recuperare i dati da altre sorgenti, e qui vi spiego come ho fatto. Come al solito si tratta di mettere d'accordo la parte Javascript che viene eseguita dal client (ovvero il vostro browser), con quella che viene eseguita a livello server che interroga il database e restituisce i dati nel formato acconcio. Sono partito dal codice Javascript che utilizzavo anche prima e che potete trovare a questo indirizzo. E' un semplice wrapper che si preoccupa di iniviare la query alla sorgente di dati e di lanciare la visualizzazione dei dati una volta che i dati sono stati resi disponibili. Non dimenticatevi che il processo è asincrono!

Ho leggermente modificato il metodo sendAndDraw inviando una richiesta dati al lato server come si vede nelle righe evidenziate dell'estratto di codice qui sotto.

QueryWrapper.prototype.sendAndDraw = function() {
  var query = this.query;
  var self = this;
  $.ajax({
    url: "functions/query.php",
    data: self.queryMap,
    dataType:"json",
    error: function( jqXHR, textStatus, errorThrown ) {
           self.handleErrorResponse( jqXHR, textStatus, errorThrown );
               },
    success: function(data, textStatus, jqXHR ) {
    self.handleResponse(data);
        }
  });

};

Questo codice richiede che utilizziate jQuery per inviare la richiesta ajax, se usate un framework differente dovrete adattare il codice di conseguenza. Alla riga 5 dovete specificare l'indirizzo della pagina che rispondere alla vostra richiesta dati lato server, nel mio caso si tratta di una pagina PHP che prende i parametri della query, interroga il database e costruisce la risposta. Ecco appunto, quello che non si vede è la query, ci saremmo aspettati di vedere dei parametri nell'url, ma questi sono contenuti all'interno di data alla riga 6.  queryMap deve essere scritto come un oggetto javascript e sarà poi la funziona ajax a costruire l'url in modo adeguato.
Fondamentale è la specifica del tipo di risposta (riga 7): infatti è possibile costruire una DataTable, ovvero la struttura che poi si va a disegnare, partendo da una stringa json opportunamente formattata. La struttura del json è ben spiegata qui, dove però non è specificata la parte relativa all'utilizzo dei ruoli e delle annotazioni; quello qui sotto è il contenuto del json che produce questo grafico.

{"cols":[
 {"id":"8","label":"Data","type":"datetime","role":"domain",
              "p":{"role":"domain"}},
 {"id":"9","label":"Pressione","type":"number","role":"data",
              "p":{"role":"data"}},
 {"id":"20","label":"Annotazione (Pressione)","type":"string",
              "role":"annotation","p":{"role":"annotation"}},
 {"id":"21","label":"Testo annotazione (Pressione)","type":"string",
              "role":"annotationText","p":{"role":"annotationText"}}
 ],
"rows":[
 {"c":[{"v":"Date(2012, 1, 16, 6, 0, 0)"},{"v":113},{"v":null},{"v":null}]},
 {"c":[{"v":"Date(2012, 1, 16, 12, 0, 0)"},{"v":113},{"v":null},{"v":null}]},
 {"c":[{"v":"Date(2012, 1, 17, 6, 0, 0)"},{"v":113},{"v":null},{"v":null}]},
 {"c":[{"v":"Date(2012, 1, 17, 12, 0, 0)"},{"v":113},{"v":null},{"v":null}]},
 {"c":[{"v":"Date(2012, 1, 18, 6, 0, 0)"},{"v":113},{"v":null},{"v":null}]},
 {"c":[{"v":"Date(2012, 1, 18, 12, 0, 0)"},{"v":113},{"v":null},{"v":null}]}
 ]}

Notate la presenza dei campi opzionali p nella definizione delle colonne che diventano obbligatori se volete utilizzare le funzioni avanzate per le annotazioni. Importante anche notare la particolarità della definizione della data, infatti un campo json non può contenere un oggetto Date, ma le API di Google Chart Tools (link) sono in grado di interpretare una stringa formattata che contiene il costruttore della data.

La cosa più facile da realizzare è il lato server, trovate un PHP d'esempio qui: in parole molto povere eseguite la o le query al database e dai risultati costruite un grosso array multidimensionale che contiene la struttura json. Sfruttate il comando json_encode di PHP per trasformare l'array nella stringa json con cui il server risponde alla richiesta. Utilizzate gli strumenti per sviluppatori (FireBug per Firefox e quello integrato per Chrome, se usate IE allora cambiate browser!) per verificare se la struttura che si ottiene è esattamente quella che volete rappresentare.

Un consiglio per i vostri progetti: evitate di chiamare un parametro della query "param", infatti molti browser quando troveranno &param lo interpreteranno erroneamente come ¶m ovvero ¶m che ovviamente non viene gestito correttamente dal server.

Le altre visualizzazioni

Nella prima versione era possibile visualizzare i grafici solo nel formato SVG, il che li rende interattivi, ma per esempio non possono essere salvati come una semplice immagine. Per ovviare a questo limite ho pensato di utilizzare canvg in modo da analizzare il contenuto dell'SVG e di poterlo trasformare in immagine. L'idea me l'ha data questo codice che ho trovato sulla rete, in cui proprio un grafico di Google Chart viene convertito in un file PNG.

Nel mio caso specifico, se l'utente preferisce visualizzare i grafici in formato PNG, può selezionare "Immagine Statica" e al posto del SVG verrà utilizzato il PNG così che sarà anche possibile salvare i grafici sul proprio PC. Per mantenere il codice pulito e generico, quello che faccio è disegnare i grafici in formato SVG sempre e nel caso di visualizzazione statica, il canvas viene sostituito dalla grafica, come vedete nell'estratto qui sotto:

function sendAndDraw( div_name, graphOptions, queryMap ) {

  var container = document.getElementById( div_name );
  var options = (graphOptions);
  
  if ( queryMap['vis'] == 'table' ) {
    var visualization = new google.visualization.Table( container );
  } else if ( (queryMap['vis'] == 'graph' ) || ( queryMap['vis'] == 'chart' )) {
    var visualization = new google.visualization.LineChart( container );
    if  ( queryMap['vis'] == 'chart' ) {
      google.visualization.events.addListener( visualization, 
            'ready', function() { toImg( container, container ); });
    }
  } 
  var queryWrapper = new QueryWrapper( queryMap, visualization, options, 
      container );
  queryWrapper.sendAndDraw();
}

Notate anche in questo caso come la programmazione deve adattarsi all'asincronia dell'ajax (righe evidenziate). Infatti quando viene lanciato il metodo draw di una visualizzazione, questo fa partire il processo e ritorna immediatamente al client. Si ovvia a questo asincronismo aggiungendo un listener che viene innescato solo quando il grafico è completamente realizzato.

Un'operazione simile avviene quando l'utente clicca sull'icona immagine: il grafico corrispondente viene convertito in PNG e visualizzato in una div separata.

Per la visualizzazione tabellare non ci sono problemi, perché Google Chart ne ha una sua intrinseca che viene implementata interamente in HTML, mentre il discorso è differente se l'utente vuole scaricarsi i dati in formato CSV. In quel caso viene inviata nuovamente una richiesta di dati al server il quale anziché rispondere con un json dovete semplicemente ritornare i dati separati da una virgola. Per forzare il browser a  trattare il flusso di dati come un file da salvare o da aprire aggiungente le righe seguenti al flusso di dati:

header('Content-Type: text/csv');
header('Content-disposition: attachment;filename=file.csv);

L'embedding

Per permettere ad altri utenti di aggiungere un grafico interattivo al loro sito ho scelto la via più semplice di tutte, ovvero quella dell'iframe. Come src del frame viene impostata una pagina PHP con tutti i parametri necessari che esegue la query e produce una pagina html contenente sul il grafico in questione. Il codice permette di incorporare la versione interattiva del grafico ed è live, nel senso che tutte le volte che viene visualizzato, viene eseguita la query al database. In questo modo è possibile avere sempre l'ultimo mese semplicemente eliminando i parametri temporali dalla query come riportato qui sotto:

<iframe frameborder="0" height="250" 
src="http://grafici-reattori.tk/embed.php?react=r2&par=Flux&size=small"
width="295">
Spiacenti, ma il vostro browser non supporta i frame;</iframe>

Cosa manca?

A parte correggere tutti i bachi che voi avrete la pazienza di trovare quello che sicuramente manca è una versione per dispositivi mobili. Infatti, se i grafici sono visibili sull'iPhone, non sono certo di facile navigazione e non sono nemmeno visualizzati nativamente sui dispositivi Android. Per la versione mobile sto pensando di scrivere qualcosa usando jQuerymobile.

Vorrei anche aggiungere una miglior gestione degli eventi così che quando l'utente seleziona un punto su un grafico, viene mostrato il valore corrispondente alla stessa data anche su tutti gli altri grafici.

Ma per queste migliorie ci sarà da aspettare, al momento ci sono altre priorità nella mia to-do list!

Chiunque può lasciare commenti su questo blog, ammesso che vengano rispettate due regole fondamentali: la buona educazione e il rispetto per gli altri.

Per commentare potete utilizzare diversi modi di autenticazione, da Google a Facebook e Twitter se non volete farvi un account su Disqus che resta sempre la nostra scelta consigliata.

Potete utilizzare tag HTML <b>, <i> e <a> per mettere in grassetto, in corsivo il testo ed inserire link ipertestuali come spiegato in questo tutorial. Per aggiungere un'immagine potete trascinarla dal vostro pc sopra lo spazio commenti.

A questo indirizzo trovate indicazioni su come ricevere notifiche via email sui nuovi commenti pubblicati.

3 commenti:

  1. toto........l'uomo dalle 1000 vite ;.) bravo ...ma come farai te a conciliare tutto ? ;.)))))

    RispondiElimina
  2. mi alzo presto la mattina... ecco qui svelato il mio segreto!

    ti piace la nuova versione? 

    RispondiElimina
  3. certo che mi piace !!!! 

    RispondiElimina

Chiunque può lasciare commenti su questo blog, ammesso che vengano rispettate due regole fondamentali: la buona educazione e il rispetto per gli altri.

Per commentare potete utilizzare diversi modi di autenticazione, da Google a Facebook e Twitter se non volete farvi un account su Disqus che resta sempre la nostra scelta consigliata.

Potete utilizzare tag HTML <b>, <i> e <a> per mettere in grassetto, in corsivo il testo ed inserire link ipertestuali come spiegato in questo tutorial. Per aggiungere un'immagine potete trascinarla dal vostro pc sopra lo spazio commenti.

A questo indirizzo trovate indicazioni su come ricevere notifiche via email sui nuovi commenti pubblicati.