Raphaël è una libreria JavaScript leggera che permette il rendering delle immagini SVG, inclusi i diagrammi, i grafici, le animazioni basate su vettoriale e i componenti delle GUI proprio all’interno delle vostre pagine web. Ora starete probabilmente pensando: “Posso già fare questo con jQuery, con Google Charts o addirittura con Flash!”. Sebbene questo sia vero, Raphaël offre nuove possibilità che al momento non sono disponibili con le altre tecnologie appena citate. Cerchiamo di capire come creare delle immagini vettoriali scalabili all’interno del codice che funzionino sui vari browser e che “degradino dolcemente” [“gracefully degrade”, ndr].
Un linguaggio open per un open web#section1
Il web è soprattutto open standard e tecnologie libere. Raphaël, che si avvale dello standard SVG del W3C e di una MIT License per l’open source, calza a pennello all’open web.
Ma come la mettiamo con Internet Explorer 6? Non supporta SVG! Questo è vero, ma IE6 supporta il suo VML (Vector Markup Language) proprietario. (IE9 ha messo in programma il supporto per SVG 1.1. Si noti che Raphaël si basa sulla feature detection invece che sullo user agent (UA) sniffing. IE7 e IE8 non sanno cosa farsene di un file SVG, così Raphaël cambia automaticamente modalità al posto vostro). Raphaël rimuove tutto il non-sense dai browser così che voi non dobbiate averci a che fare. Lo stesso codice JavaScript creerà una bellissima immagine SVG o VML basandosi sulle capacità del browser. Scrivetelo una volta e usatelo per sempre! Evitando Flash per la grafica vettoriale, potrete rendere il vostro output disponibile su più device, inclusi i browser mobile WebKit e i device iOS. La vostra grafica creativa, interattiva e scalabile sarà bellissima a qualunque risoluzione su qualsiasi device supportato.
jQuery#section2
E jQuery? Ha moltissimi plugin per la grafica, perché dovrei passare a Raphaël?
Ci sono moltissimi interessanti plugin di jQuery per la grafica, quali jqPlot, Flot, jQuery SVG e altri. Con jQuery dovete destinare più di 50 KB alla versione ridotta della libreria. Poi, dovete aggiungere il core UI, alcuni plugin e delle librerie extra per farlo funzionare con IE. Byte per byte, jQuery ci va pesante, ma avete dei bit extra che non sono sempre necessari.
Raphaël è nel complesso più piccolo per creare delle grafiche vettoriali di base. Tenere d’occhio il peso in KB del vostro lavoro è qualcosa da tenere in considerazione mentre si stanno sviluppando applicazioni su larga scala, ma lo stesso vale anche per la scelta del miglior tool per eseguire un lavoro.
Non deve essere uno scenario “aut aut”, o l’uno o l’altro: se state già usando jQuery, potete benissimo usare anche Raphaël senza alcun conflitto e mixare ed usare contemporaneamente i due. Molte di queste librerie JavaScript convivono armoniosamente, il che rende la vita più semplice a noi sviluppatori.
Immagini dinamiche#section3
Prima di avere tutte queste librerie, tool e web services a nostra disposizione, la grafica generata dinamicamente era creata sul server dagli script Common Gateway Interface (CGI). Come sono cambiate le cose! Adesso abbiamo accesso a servizi come Google Charts e altri che utilizzano la Representational State Transfer (REST). Specificate semplicemente i parametri ed otterrete una graziosa immagine!
Integrare Google Charts in un elemento<img>
è un modo facile e flessibile per creare al volo un gradevole grafico a barre, ma ha i suoi risvolti negativi. In quanto elemento immagine, vi rimane solo l’attributo alt
: dovete usare longdesc
o un qualche tipo di mappa immagine per assegnare una label alle regioni. Tutti i dati risiedono nei pixel, non nel HTML. Le immagini statiche vengono rese ad una data dimensione: ciò implica che quando ingrandite l’immagine, questa risulta “spixellata”. Man mano che comincerete a creare dei workflow professionali, vi imbatterete in problemi con le immagini raster come GIF, JPEG e PNG, che non si scalano molto bene né per quel che riguarda l’ingrandimento né per la riduzione. Al contrario, SVG è fatto di vettori, così da essere indipendente dalla risoluzione. Dal momento che il web è disponibile in qualunque forma e dimensione, e dal momento che i dati vengono spesso passati da online a offline, le immagini devono mantenere la loro risoluzione, dalla qualità di stampa fino alla bassa definizione di 72dpi delle risoluzioni dei monitor, passando per tutti i valori tra questi due estremi.
Esempi#section4
Progressive Enhancement#section5
Raphaël usa JavaScript per inserire SVG o VML nelle vostre pagine HTML. Questo significa che il vostro browser deve supportare JavaScript per poter visualizzare la grafica risultante. Mentre vi aspettereste che la maggior parte delle persone che visitano il vostro sito con un qualunque browser moderno abbia JavaScript attivato, così come il supporto per SVG, la maggior parte ed i più importanti tra i vostri clienti non l’avranno: i robot dei motori di ricerca, come Google Bot, non interpretano JavaScript. Non vedono la vostra magnifica grafica, ma solo un div
vuoto, senza contenuto!
E’ qui che entra in gioco il progressive enhancement. I puri dati HTML fungono da base. Potrebbe non sembrare carino come una tabella o una lista, ma è semanticamente corretto ed aggiunge degli aggangi per i motori di ricerca affinché indicizzino il vostro contenuto. E’ ora possibile usare HTML come vostra sorgente dati quando costruite la grafica con Raphaël.
Calorie | 45% |
---|---|
Grassi Saturi | 25% |
Proteine | 15% |
Vitamina B | 10% |
Vitamina C | 5% |
// <![CDATA[
/* [CDATA[ */ function pieMe() { var values = [], labels = [], nfTable = document.getElementById("nutritionFacts"), i = 0, rows = nfTable.rows.length;
for(;i < rows;i++) { trRow = nfTable.getElementsByTagName("tr")[i]; labels.push(trRow.getElementsByTagName("th")[0].firstChild.nodeValue); values.push(parseInt(trRow.getElementsByTagName("td")[0].firstChild.nodeValue, 10)); } nfTable.style.position = 'absolute'; nfTable.style.left = '-999em'; Raphael("myHolderPie", 540, 400).pieChart(270, 200, 100, values, labels, "#fff"); } pieMe(); /* ]] */ // --> // ]]>
Per prima cosa, creiamo una tabella di valori che sommati danno il 100%. Questi saranno i valori per ciascuno spicchio nel diagramma a torta. Possiamo potenziare la tabella regolare se il browser lo supporta.
<table id="nutritionFacts">
<caption>Informazioni nutrizionali di un prodotto X</caption>
<tr>
<th scope="row">Calorie</th>
<td>45%</td>
</tr>
<tr>
<th scope="row">Grassi Saturi</th>
<td>25%</td>
</tr>
<tr>
<th scope="row">Proteine</th>
<td>15%</td>
</tr>
<tr>
<th scope="row">Vitamina B</th>
<td>10%</td>
</tr>
<tr>
<th scope="row">Vitamina C</th>
<td>5%</td>
</tr>
</table>
Ora che abbiamo i nostri dati di base, possiamo aggiungere qualche libreria esterna. Per prima cosa dobbiamo includere Raphaël.
<script src="raphael.js" type="text/javascript" charset="utf-8"></script>
Poi useremo il sistema di plugin di Raphaël per includere il plugin Pie Charts. ["grafici a torta", ndr]
<script src="pie.js" type="text/javascript" charset="utf-8"></script>
Questo ci dà accesso a tutti i tool di cui abbiamo bisogno per convertire in maniera semplice la tabella in un'immagine SVG. Per generare un grafico a torta, dobbiamo prima creare due array, uno per le label ed uno per i valori.
(Gli a-capo sono segnati con » —Ed.)
var values = [],
labels = [],
nfTable = document.getElementById("nutritionFacts"),
i = 0,
rows = nfTable.rows.length;
for( ;i < rows; i++) {
trRow = nfTable.getElementsByTagName("tr")[i];
labels.push(trRow.getElementsByTagName("th")[0].firstChild.nodeValue);
values.push(parseInt(trRow.getElementsByTagName("td")[0]
.firstChild.nodeValue, 10));
}
nfTable.style.position = 'absolute';
nfTable.style.left = '-999em';
Ora, per ogni elemento <tr>
facciamo un loop, mettendo ciascun <th>
nell'array del label e ciascun <td>
nell'array dei valori. Alla fine, nascondiamo la tabella, dal momento che la rimpiazzeremo con il grafico a torta tra poco.
raphael("myHolderPie", 540, 400).pieChart(270, 200, 100,
values, labels, "#fff");
Per visualizzare il grafico a torta, usiamo l'oggetto Raphaël, specifichiamo un id
per l'elemento ed alcune dimensioni. In questo caso, stiamo usando il div
myHolderPie. Gli assegniamo una larghezza di 540 pixel ed un'altezza di 400 pixel. Poi aggiungiamo la funzione pieChart a quell'area. La funzione pieChart ha diverse variabili, tra cui il punto centrale da sinistra e da destra. In questo caso partiamo a 270px dal lato sinistro dell'elemento contenitore. L'argomento successivo è 200, che è il numero di pixel dal top dell'elemento contenitore. Il 100 dice al codice di creare un grafico a torta con un diametro di 100 pixel. (Provate voi stessi ad aumentare il numero a 200 o a diminuirlo fino a 50 per vedere cosa succede). I prossimi due argomenti sono i valori del grafico a torta e delle label che abbiamo costruito usando jQuery. L'ultimo argomento è il valore HEX per il profilo dello spicchio. Se cancellate questo argomento, allora non ci saranno bordi.
gRaphaël ha più informazioni riguardanti i tipi di grafici che potete usare per creare le immagini.
Ricordatevi che ogni volta che sostituite una tabella o un'altra informazione con un'immagine creativa o con un'interfaccia interattiva, dovete considerare quel che guadagnate e quel che perdete. L'accessibilità è importante: se i vostri lettori hanno solo una tastiera, possono ancora usare il tasto tab per accedere ai dati? Gli utenti non vedenti possono accedere all'informazione nel nuovo contenuto come potevano con l'originale? Nel nostro caso, una tabella accessibile è stata sostituita con una risorsa meno accessibile, ma la vecchia tabella è stata nascosta ed è ancora disponibile per gli utenti che utilizzano uno screen reader. Tuttavia, il nuovo contenuto limita l'utilizzo da parte degli utenti che hanno solo la tastiera. Il supporto per i roles di Accessible Rich Internet Applications (ARIA) del W3C e per tabIndex="0"
in SVG potrebbero essere d'aiuto in futuro per affrontare i limiti imposti dall'accessibilità, ma al momento non fanno parte del plugin Raphaël.
Animazioni#section6
Al suo interno, Raphaël ha implementate diverse funzionalità di animazione interessanti. Una veramente interessate è la capacità di tracciare un percorso. Immaginate di lavorare per l'Edinburgh Tourist Council. Il Castello di Edinburgo è una destinazione popolare e volete mostrare il percorso più rapido e semplice per raggiungerlo partendo dalla stazione dei treni. Non sarebbe bellissimo se poteste tracciare un percorso da fare a piedi?

// <![CDATA[
function tracePath(){ document.getElementById("myMapHolder").removeChild(document.getElementById("myMapHolder").childNodes[0]); var r = Raphael("myMapHolder", 540, 403), c = r.image("https://149572954.v2.pressablecdn.com/wp-content/uploads/2012/07/map.png", 0, 0, 540, 403), p = r.path("M513.859,35.222l-95.332,24.667l18.666,76.667l-131.334,46c0,0-10.667,3.333-11.333,13.333c-0.891,13.371-42.748,23.018-42.748,23.018s-13.252,3.648-9.252,18.315s14.667,43.333,14.667,43.333l-104.667,22.667").attr({stroke: "#f00", opacity: .7, "stroke-width": 5}),e = r.ellipse(513.859,35.333, 7, 7).attr({stroke: "none", opacity: .7, fill: "#f00"});
function run() { e.animateAlong(p, 20000, false, function () { e.attr({cx: 513.859 , cy: 35.333, rotation: 0}); run(); }); } run(); } tracePath(); // ]]>
Creare questa animazione con Raphaël è come schioccare le dita! Per prima cosa, avete bisogno di una mappa che funga da base sullo sfondo. Seconda cosa, dovete creare un percorso da seguire e alla fine qualche riga di JavaScript metterà tutto insieme.
Innanzitutto, dobbiamo creare un'area di Raphaël in cui mettere tutta la nostra SVG. In questo esempio, useremo il div
myMapHolder e creeremo un'area che sarà larga 540 pixel e alta 403 pixel.
var myMap = raphael("myMapHolder", 540, 403);
Poi inseriamo un'immagine di sfondo di una mappa. Io ho usato uno screenshot da Open Street Map, ma potete usare una qualsiasi immagine. Per essere sicuri che gli utenti senza JavaScript siano in grado di visualizzare la mappa, aggiungiamo un elemento <img>
con un link all'immagine della mappa all'interno del div
myMapHolder. La prima cosa da fare con JavaScript è rimuovere questa immagine di base così che la mappa più dinamica possa essere caricata al suo posto.
var myMapHolder = document.getElementById("myMapHolder");
myMapHolder.removeChild(myMapHolder.childNodes[0]);
var myImage = myMap.image("map.png", 0, 0, 540, 403);
L'ho posizionata a zero pixel dal top e a zero pixel da sinistra nel contenitore, poi ho specificato le dimensioni dell'immagine stessa: 540 per 403 pixel.
var myPath = myMap.path("M513.859,35.222l-95.332,24.667l" +
"18.666,76.667l-131.334,46c0,0-10.667," +
"3.333-11.333,13.333c-0.891,13.371-42.748," +
"23.018-42.748,23.018s-13.252,3.648-9.252," +
"18.315s14.667,43.333,14.667,43.333l-104.667,22.667")
.attr({
stroke: "#f00",
opacity: .7,
"stroke-width": 5
});
Adesso arriva la parte un po' più critica: il codice per il percorso SVG. Ho tracciato la mappa in Illustratore e ho salvato il percorso come SVG e l'ho copiato qui: il modo più facile per creare velocemente un percorso complesso. Come potete vedere, inoltre, abbiamo attaccato la funzione attr()
per specificare il colore, l'opacità e la larghezza del percorso. Questo creerà una linea rossa, con opacità al 70%, larga cinque pixel.
var myMarker = myMap.ellipse(513.859,35.333, 7, 7).attr({
stroke: "none",
opacity: .7,
fill: "#f00"
});
Una volta creata la mappa ed il percorso, dobbiamo creare un piccolo punto “da far girare nel labirinto”. Questo è il codice che crea un cerchio con un raggio di sette pixel che parte dal punto 513.859,35.333. Abbiamo anche attaccato alcuni attributi aggiuntivi per rimuovere il bordo, cambiare l'opacità ed il colore del punto.
function run() {
myMarker.animateAlong(p, 20000, false, function () {
myMarker.attr({ cx: 513.859, cy: 35.333, rotation: 0 });
run();
});
}
run();
Alla fine, mettiamo tutto insieme e facciamo partire l'animazione. Creiamo una funzione chiamata run()
, che sposta il punto lungo il percorso. Quando termina la sua esecuzione, si resetta e va in loop più e più volte.
Ora, per animare il punto, lo piazziamo nella variabile myMarker e scriviamo myMarker.animationAlong()
. Questa funzione ha diversi argomenti: per primo specifichiamo il percorso che vogliamo che segua, nel nostro caso “myPath,”; poi, specifichiamo la durata per la lunghezza di tempo che vogliamo che il punto impieghi per percorrere il percorso. L'argomento successivo ruota l'oggetto lungo il percorso. Noi non vogliamo questo effetto, pertanto impostiamo questo argomento a "false". Infine, abbiamo una funzione callback, che in questo caso riporta il puntino alla posizione di partenza, per creare il loop.
Potete guardare l'intero script insieme all'esempio, così potete vedere il sorgente per adattarlo alle vostre esigenze.
Benefici di SVG sul web#section7
Con l'aumentare della popolarità di HTML5, SVG ha come rivale l'elemento<canvas>
. Entrambe possono disegnare immagini sullo schermo, il che rende un po' difficile decidere quale usare. La differenza più grande è che gli elementi SVG fanno parte dell'alberatura DOM. Con canvas
potete solo accedere all'elemento root <canvas>
.
Dal momento che SVG fa parte del DOM, potete aggiungere degli eventi a tutte le porzioni individuali di un'immagine SVG. Le azioni come onClick
, onTap
o onHover
rendono tutte le immagini SVG flessibili al punto da diventare un sostituto completo di Flash. Dal momento che questi eventi possono essere creati a run time, a seconda del browser/device e delle sue capacità, si può creare un'esperienza "progressively enhanced". Con <canvas>
il disegno non fa parte del DOM e sacrificate l'interattività per un'alberatura DOM che richiede meno memoria. Inserire un'immagine SVG complessa potrebbe far bloccare le macchine più lente mentre stanno renderizzando migliaia di nodi DOM.
SVG è scalabile, così, mentre sempre più browser si muovono verso il meccanismo “zoom” piuttosto che “scale” per aumentare la dimensione dei font e delle immagini, SVG mantiene i suoi bordi ben definiti. L'elemento <canvas>
è rasterizzato e quindi diventa "spixellato".
SVG: uno standard W3C#section8
SVG è uno standard W3C, il che significa che nessuno prenderà le sue cose e se ne andrà via, lasciandovi bloccati con tonnellate di codice inutile. Dal momento che non solo è open, ma anche royalty-free, sempre più applicazioni, device e servizi saranno sia fruitori sia distributori di SVG. Un ecosistema valido è emerso, al punto che SVG non sparirà. Significa anche che non dovete preoccuparvi dell'implementazione dei dettagli. Le applicazioni fanno tutto il duro lavoro, creando i nodi SVG ed i path per voi. Il puro XML c'è ancora, se volete dare un'occhiata al codice e cambiarlo a seconda delle vostre esigenze.
Illustrazioni dell'articolo: {carlok}
nuovo commento
Interessante, vale la pena di approfondire.
Mi preoccupa un po’ la compatibilità (ovvero la visibilità degli oggetti) su browser e piattaforme diverse, comprendendo in questi anche quelle mobili.