Ricerca…


Sintassi

  • d3. seleziona (selettore)
  • d3. selectAll (selector)
  • selezione . seleziona (selettore)
  • selezione . selectAll (selector)
  • selezione . filtro (filtro)
  • selezione . unire (altro)

Osservazioni

Letture correlate:

Selezione e modifiche di base

Se hai familiarità con la sintassi di jQuery e Sizzle, le selezioni di d3 non dovrebbero essere molto diverse. d3 imita l'API dei selettori W3C per facilitare l'interazione con gli elementi.

Per un esempio di base, per selezionare tutto <p> e aggiungere una modifica a ciascuno di essi:

d3.selectAll('p')
  .attr('class','textClass') 
  .style('color', 'white');

In poche parole, questo è relativamente lo stesso che fare in jQuery

$('p')
  .attr('class','textClass') 
  .css('color, 'white')

Generalmente inizierai con una singola selezione al contenitore div per aggiungere un elemento SVG che verrà assegnato a una variabile (più comunemente chiamato svg).

var svg = d3.select('#divID').append('svg');

Da qui possiamo richiamare svg per fare le nostre sottosezioni di più oggetti (anche se non esistono ancora).

svg.selectAll('path')

Selettori diversi

È possibile selezionare elementi con diversi selettori:

  • per tag: "div"
  • per classe: ".class"
  • per id: "#id"
  • per attributo: "[color=blue]"
  • selettori multipli (OR): "div1, div2, class1"
  • più selettori (AND): "div1 div2 class1"

Selezione limitata di dati semplice

var myData = [
    { name: "test1", value: "ok" },
    { name: "test2", value: "nok" }
]

// We have to select elements (here div.samples)
// and assign data. The second parameter of data() is really important,
// it will determine the "key" to identify part of data (datum) attached to an 
// element.
var mySelection = d3.select(document.body).selectAll("div.samples") // <- a selection
                   .data(myData, function(d){ return d.name; }); // <- data binding

// The "update" state is when a datum of data array has already
// an existing element associated.
mySelection.attr("class", "samples update")

// A datum is in the "enter" state when it's not assigned
// to an existing element (based on the key param of data())
// i.e. new elements in data array with a new key (here "name")
mySelection.enter().append("div")
    .attr("class", "samples enter")
    .text(function(d){ return d.name; });

// The "exit" state is when the bounded datum of an element
// is not in the data array
// i.e. removal of a row (or modifying "name" attribute)
// if we change "test1" to "test3", "test1" bounded
//          element will figure in exit() selection
// "test3" bounded element will be created in the enter() selection
mySelection.exit().attr("class", "samples remove");

Il ruolo dei segnaposto nelle selezioni "entra"

Cos'è una selezione di inserimento?

In D3.js, quando si uniscono i dati agli elementi DOM, sono possibili tre situazioni:

  1. Il numero di elementi e il numero di punti dati sono gli stessi;
  2. Ci sono più elementi dei punti dati;
  3. Ci sono più punti dati che elementi;

Nella situazione n. 3, tutti i punti dati senza un elemento DOM corrispondente appartengono alla selezione di inserimento . Pertanto, in D3.js, immettere le selezioni sono selezioni che, dopo aver unito elementi ai dati, contengono tutti i dati che non corrispondono a nessun elemento DOM. Se usiamo una funzione di append in una selezione di inserimento , D3 creerà nuovi elementi che vincolano i dati per noi.

Questo è un diagramma di Venn che spiega le possibili situazioni riguardanti il ​​numero di punti dati / numero di elementi DOM:

inserisci la descrizione dell'immagine qui

Come possiamo vedere, la selezione di inserimento è l'area blu a sinistra: punti dati senza elementi DOM corrispondenti.

La struttura della selezione di invio

In genere, una selezione di inserimento ha questi 4 passaggi:

  1. selectAll : Seleziona elementi nel DOM;
  2. data : conta e analizza i dati;
  3. enter : confrontando la selezione con i dati, crea nuovi elementi;
  4. append : append gli elementi reali nel DOM;

Questo è un esempio molto semplice (guarda i 4 passaggi nei var divs ):

var data = [40, 80, 150, 160, 230, 260];

var body = d3.select("body");

var divs = body.selectAll("div")
    .data(data)
    .enter()
    .append("div");

divs.style("width", function(d) { return d + "px"; })
    .attr("class", "divchart")
    .text(function(d) { return d; });

E questo è il risultato ( jsfiddle qui ):

inserisci la descrizione dell'immagine qui

Nota che, in questo caso, abbiamo usato selectAll("div") come prima riga nella nostra variabile di selezione " selectAll("div") . Abbiamo un set di dati con 6 valori e D3 ha creato 6 div per noi.

Il ruolo dei segnaposto

Ma supponiamo di avere già un div nel nostro documento, qualcosa come <div>This is my chart</div> in alto. In quel caso, quando scriviamo:

body.selectAll("div")

stiamo selezionando quel div esistente. Quindi, la nostra selezione di invio avrà solo 5 origini senza elementi corrispondenti. Per esempio, in questo jsfiddle , dove c'è già un div in HTML ("Questo è il mio grafico"), questo sarà il risultato:

inserisci la descrizione dell'immagine qui

Non vediamo più il valore "40": la nostra prima "barra" è scomparsa, e la ragione è che la nostra selezione "entra" ora ha solo 5 elementi.

Quello che dobbiamo capire qui è che nella prima riga della nostra variabile di selezione selectAll("div") , seleziona selectAll("div") , quelle div sono solo segnaposto . Non dobbiamo selezionare tutti i divs se stiamo aggiungendo divs , o tutto il circle se stiamo aggiungendo il circle . Possiamo selezionare cose diverse. E, se non pianifichiamo di avere una selezione "aggiornamento" o "uscita", possiamo selezionare qualsiasi cosa :

var divs = body.selectAll(".foo")//this class doesn't exist, and never will!
    .data(data)
    .enter()
    .append("div");

In questo modo, stiamo selezionando tutto ".foo". Qui "foo" è una classe che non solo non esiste, ma non è mai stata creata da nessun'altra parte nel codice! Ma non importa, questo è solo un segnaposto. La logica è questa:

Se nella tua selezione "inserisci" selezioni qualcosa che non esiste, la tua selezione "inserisci" conterrà sempre tutti i tuoi dati.

Ora, selezionando .foo , la nostra selezione " .foo " ha 6 elementi, anche se abbiamo già un div nel documento:

inserisci la descrizione dell'immagine qui

Ed ecco il corrispondente jsfiddle .

Selezione null

Di gran lunga il modo migliore per garantire di selezionare nulla è selezionare null . Non solo, ma questa alternativa è molto più veloce di qualsiasi altra.

Quindi, per una selezione di inserimento, basta fare:

selection.selectAll(null)
    .data(data)
    .enter()
    .append(element);

Ecco un demo fiddle: https://jsfiddle.net/gerardofurtado/th6s160p/

Conclusione

Quando si ha a che fare con le selezioni "enter", fare molta attenzione a non selezionare qualcosa che già esiste. Puoi usare qualsiasi cosa nel tuo selectAll , anche cose che non esistono e non esisteranno mai (se non hai intenzione di avere una "aggiornamento" o una selezione di "uscita").

Il codice negli esempi è basato su questo codice di Mike Bostock: https://bl.ocks.org/mbostock/7322386

Usando "questo" con una funzione di freccia

La maggior parte delle funzioni in D3.js accetta una funzione anonima come argomento. Gli esempi più comuni sono .attr , .style , .text , .on e .data , ma la lista è molto più grande di quello.

In questi casi, la funzione anonima viene valutata per ciascun elemento selezionato, nell'ordine, passando:

  1. Il dato corrente ( d )
  2. L'indice corrente ( i )
  3. Il gruppo corrente ( nodes )
  4. this come l'attuale elemento DOM.

Il dato, l'indice e il gruppo corrente vengono passati come argomenti, il famoso primo, secondo e terzo argomento in D3.js (i cui parametri sono tradizionalmente denominati d , i e p in D3 v3.x). Per l'utilizzo di this , tuttavia, non è necessario utilizzare alcun argomento:

.on("mouseover", function(){
    d3.select(this);
});

Il codice qui sopra selezionare this quando il mouse si trova sopra l'elemento. Controlla che funzioni in questo fiddle: https://jsfiddle.net/y5fwgopx/

La funzione della freccia

Come nuova sintassi ES6, una funzione a freccia ha una sintassi più breve rispetto all'espressione di funzione. Tuttavia, per un programmatore D3 che usa this costantemente, v'è una trappola: una funzione freccia non crea un proprio this contesto. Ciò significa che, in una funzione di freccia, this ha il suo significato originario dal contesto che la racchiude.

Questo può essere utile in diverse circostanze, ma è un problema per un programmatore abituato a utilizzare this in D3. Ad esempio, utilizzando lo stesso esempio nel fiddle sopra, questo non funzionerà:

.on("mouseover", ()=>{
    d3.select(this);
});

Se ne dubiti, ecco il violino: https://jsfiddle.net/tfxLsv9u/

Beh, questo non è un grosso problema: si può semplicemente usare un'espressione di funzione regolare, vecchio stile quando necessario. Ma cosa succede se si desidera scrivere tutto il codice utilizzando le funzioni freccia? E 'possibile avere un codice con le funzioni di direzione e continuare a utilizzare correttamente this in D3?

Il secondo e il terzo argomento combinati

La risposta è , perché this è lo stesso dei nodes[i] . Il suggerimento è effettivamente presente su tutte le API D3, quando descrive questo:

... con this come l'attuale elemento DOM ( nodes[i] )

La spiegazione è semplice: poiché i nodes sono il gruppo di elementi corrente nel DOM e i è l'indice di ciascun elemento, i nodes[i] riferiscono all'attuale elemento DOM stesso. Cioè, this .

Pertanto, si può usare:

.on("mouseover", (d, i, nodes) => {
    d3.select(nodes[i]);
});

Ed ecco il corrispondente fiddle: https://jsfiddle.net/2p2ux38s/



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow