DataJoin_tutorial.md
D3.js Data-Join
============
>**Nota:** Questo tutorial lavora con la console Javascript di *Chrome*, ma non dovrebbero esserci grosse differenze con altri browser.
------------------------
Creare il seguente file `index.html`:
```html
<!DOCTYPE html>
<html>
<head>
<!-- character encoding -->
<meta charset="utf-8">
<!-- ratio between the device width and the viewport size -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- latest d3 release -->
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<!-- CSS rules -->
<style type="text/css">
</style>
</head>
<body>
<!-- graph container -->
<div id="graph"></div>
</body>
<!-- javascript code -->
<script type="text/javascript">
console.log("Hello World");
</script>
</html>
```
Visualizzare a browser il file `index.html` ed ispezionare il DOM mediante gli strumenti per sviluppatori.
-----------------------------
#### Selettori CSS
D3 offre la possibilità di selezionare elementi specifici del DOM mediante i *selettori CSS*.
Per esempio, digitare nella console javascript il seguente comando per selezionare il nodo con `id="graph"` presente nel DOM
```js
d3.select("#graph")
```
Aggiungere ora due elementi `<span>` dentro il nodo con `id="graph"`
```html
<!-- graph container -->
<div id="graph">
<span>First</span>
<span>Second</span>
</div>
```
e selezionare a console i due elementi
```js
d3.select("span")
```
Notare che `d3.select` ritorna solo il primo dei due, per selezionarli entrambi digitare
```js
d3.selectAll("span")
```
Per ora abbiamo selezionato elementi del DOM mediante *id selectors* e *type selectors*, ma possiamo selezionare anche in base alla classe (*class selectors*). Aggiungiamo dello style al documento:
```html
<!-- CSS rules -->
<style type="text/css">
.first {
color: #0072ba;
}
</style>
```
ed associamo la classe `.first` al primo elemento `span`
```js
<!-- graph container -->
<div id="graph">
<span class="first">First</span>
<span>Second</span>
</div>
```
Come prima, usiamo la console per selezionare il nodo
```js
d3.select(".first")
```
----------------------------------
#### Le selezioni hanno metodi
D3 offre numerosi metodi per gli elementi selezionati, vediamo alcuni esempi direttamente nella console
```js
var el = d3.select(".first")
el.text()
el.text("D3")
el.style("font-size","40px")
el.attr("id","title")
```
Possiamo creare anche nuovi nodi, per esempio potremmo aggiungere un link
```js
var x = d3.select("#graph")
x.append("a").text("link").attr("href","https://drupal.org/").style("color","red")
```
E' anche possibile transire con fluidità tra due valori, iniziale e finale, associati ad attributi o stili
```
d3.select(".first").transition().duration(2000).style("padding-left","500px")
```
--------------------------------------
#### Il data-join
Fin qui D3 non è molto diverso da JQuery, ciò che lo rende uno strumento diverso è il *data-join*. D3 offre infatti un meccanismo per legare un dato (cioè un oggetto javascript) ad un nodo del DOM. Fatto questo, diventa facile modificare il DOM in funzione dei dati ad esso associati, non per nulla "D3" sta per *Data Drive Documents*.
Mettiamo mano alla console, cominciamo con selezionare qualcosa che non esiste :P
```js
var p = d3.selectAll("p")
p[0]
```
Ovviamente ritorna un array di 0 elementi.
> Nota: più esattamente ritorna un array di un elemento, il quale è un array di zero elementi.
Detto questo, definiamo ora la variabile che contiene i dati, cominciamo con un array di interi
```js
var data = [3,2,1]
```
Applichiamo il *data-join* associando i dati ad una selezione, così
```js
var p = d3.selectAll("p").data(data)
```
Abbiamo associato i dati una selezione di zero elementi, ma così definita la variabile `p` contiene ora tre elementi che scopriamo essere non definiti
```js
p
p[0]
```
In javascript, avere array con elementi non definiti non è una grossa novità, provate questo per esempio
```js
var v = []
v[10] = "hey"
v
v.length
v[0]
v[100]
```
E a volte javascript sa essere [ben più strambo][2].
*Dove sono finiti i dati?*
Facciamo un passo indietro e ragioniamo sui possibili scenari che possono emergere nell'unione di una lista di dati ad una lista di elementi del DOM. Mettiamo che le due liste hanno lunghezze diverse, sia `n` la lunghezza della lista di dati e `m` la lunghezza della lista di nodi, abbiamo così tre possibilità:
- `n = m`: dati e nodi sono in numero uguale, abbiamo una unica selezione che è definita *update*
- `n < m`: i dati sono meno dei nodi, abbiamo due selezioni differenti. La selezione *update* contiene i nodi a cui sono associati dei dati, la selezione *exit* invece contiene i nodi non associati a dei dati.
- `n > m`: i dati sono più dei nodi, ancora abbiamo due selezioni differenti. La selezione *update* contiene i nodi a cui sono associati dei dati, la selezione *enter* contiene invece nuovi nodi, per ora indefiniti, associati ai dati in eccessi.
Nel nostro caso `n = 3` e `m = 0`, dunque abbiamo una *enter selection*
```js
p
p[0]
p.enter()
p.enter()[0]
p.exit()
p.exit()[0]
```
Appendiamo ai nodi presenti nella enter selection dei paragrafi `p` il cui testo è il dato associato:
```js
p.enter().append("p").text(function(d){ return d; })
```
ed osserviamo nuovamente le selezioni
```js
p
p[0]
p.enter()
p.enter()[0]
p.exit()
p.exit()[0]
```
Notare che ora la variabile `p` contiene i tre paragrafi, ciascuno dei quali è associato ad un dato.
Facciamo una nuova selezione e un nuovo data-join e come prima osserviamo le selezioni
```js
var q = d3.selectAll("p").data(["a","b","c"])
q
q.enter()
q.exit()
```
Le selezioni enter ed exit sono vuote, la update invece contiene i tre paragrafi e ciscuno di essi è associato al nuovo dato.
Aggiorniamo i nodi cin base ai nuovi dati con il seguente comando
```js
q.text(function(d){return d;})
```
Possiamo usare i dati anche per modificare lo stile, per esempio la dimensione del font
```js
d3.selectAll("p").data([10,40,70]).style("font-size", function(d) { return d + "px"; })
```
Sperimentiamo ancora, selezioniamo nuovamente i paragrafi ed associamo ad essi una lista di soli due dati, che in questo esempio sono due oggetti
```js
z = d3.selectAll("p").data([{"pl":10, "col":"red"},{"pl":20, "col":"blue"}])
```
Osserviamo le selezioni
```js
z
z[0]
z.enter()
z.enter()[0]
z.exit()
z.exit()[0]
```
La selezione update contiene due nodi, la enter nessun nodo e la exit un nodo. Usualmente la update si aggiorna e la exit si butta
```js
z.style("padding-left",function(d){return d.pl + "px";}).style("color",function(d){return d.col;})
z.exit().remove()
```
----------------------------------
#### D3 ed i web standards
Avrete notato che il vocabolario di D3 proviene direttamente dagli Standard Web *HTML*, *CSS* ed *SVG*. Questo significa che è possibile trasmettere la propria conoscenza degli Standards nell'uso di D3 e che, vicersa, l'uso disinvolto di D3 necessita di conoscenze solide degli Standards.
Facciamo un esempio, prima abbiamo usato i comandi
```js
var p = d3.selectAll("p").data([1,2,3])
p.enter().append("p").text(function(d){ return d; })
```
ora, per ottenere elementi grafici, utilizziamo il linguaggio SVG e gli stessi comandi D3
```js
var graph = d3.select("#graph").append("svg")
var p = graph.selectAll("circle").data([1,2,3])
p.enter().append("circle").attr("r",function(d){ return d*10; }).attr("cx",function(d){ return d*100;}).attr("cy","500").style("fill","green")
```
Notate che non c'è nulla di speciale nei nomi degli attrinuti `r`, `cx` e `cy`, questi sono infatti gli attributi dell'elemento `circle` come definito dal [W3C][3].
#### Eventuali esercizi
- applicare transizioni ai cerchi
- usare nuove figure geometriche (rect, line, path)
- implementare il codice nella pagina web
- visualizzare dati tipo: `[{'x': x, 'y': y, 'r': r}, ..]`
----------------------
**Tutorial introduttivo a D3 preparato in occasione del DrupalDay**
*( [Riccardo Scalco][1] | Milano, 9 Maggio 2014 )*
[1]: http://eidogram.com/
[2]: https://www.destroyallsoftware.com/talks/wat
[3]: http://www.w3.org/TR/SVG/shapes.html#CircleElement