2012-11-12 22 views
8

Sto usando d3 per visualizzare un diagramma di gantt semplificato, con panning e zoom usando d3.behavior.zoom.Scala ordinale pan/zoom?

La scala x è una scala temporale (leggermente modificata per centrare i giorni del calendario in colonne, ecc.) E funziona in modo soddisfacente, ma sto riscontrando problemi nel decidere come ingrandire/eseguire la scala y, il cui dominio è un elenco di attività che spesso saranno troppi per adattarsi all'area del grafico, quindi la necessità di eseguire panning/zoom.

C'è un modo per dire alla scala ordinale di default di reagire agli eventi zoom/pan, o dovrei scrivere una scala personalizzata? E se ho bisogno di scrivere una scala personalizzata, sarebbe meglio basarlo su d3.scale.ordinal (avendo esso memorizza l'intero elenco di attività e usa solo il sottoinsieme visibile come dominio), o su d3.scale. lineare (e quindi implementare qualcosa di simile alla scala ordinale per le bande di frequenze ecc.).

Oppure c'è qualcosa che mi manca (del tutto probabile poiché è il mio primo progetto che utilizza d3)?

risposta

3

Ampliare un po 'dalla mia precedente risposta, come sono stato contattato privatamente spiega come ho fatto questo

In primo luogo, uno screenshot dell'app in questione, il cui lavoro è in fase di aggregazione e visualizzazione dei dati di pianificazione raccolti da varie fonti (file PowerPoint, database aziendali, ecc.).

screenshot

Il bit rilevante è l'asse verticale destra con i punti colorati, in cui ogni punto rappresenta lo sforzo di un progetto e l'organizzazione coinvolta. L'area grigia sull'asse è un pennello d3.js e può essere spostato/ridimensionato per modificare i dati del grafico/tabella in tempo reale.

// the axis is a regular ordinal axis, with a brush 
y2 = d3.scale.ordinal(), 
brush = d3.svg.brush().y(y2).on('brush', brushReact), 
// [...] 
// brush event handler 
function brushReact() { 
    if (tasksSlice == null) 
     return; 
    var yrb = y2.rangeBand(), 
     extent = brush.extent(), 
     s0 = Math.round(extent[0]/yrb), 
     s1 = Math.round(extent[1]/yrb); 
    if (s0 == tasksSlice[0] && s1 == tasksSlice[1]) 
     return; 
    tasksSlice = [s0, s1]; 
    inner.refresh(); 
} 

Cosa accade all'interno del gestore è piuttosto semplice:

  • ottenere l'estensione spazzola
  • trasposizione in Fa indici nel mio array di dati
  • fetta gamma miei dati e impostare il risultato come dati da visualizzare
  • aggiornare il grafico e la tabella

Spero che questo chiarisca.

2

Si scopre che non è così difficile, ho dovuto:

  • scrivere una scala personalizzata, per lo più identico a d3.scale.ordinal, tranne che memorizza l'intera gamma di valori di dominio e implementa una fetta ([min, max]) metodo che imposta l'intervallo di valori del dominio visibile
  • traccia il delta di traduzione y nel richiamo dell'evento zoom e lo aggiunge a una variabile che memorizza la traduzione totale y
  • verifica se l'importo totale della traduzione è > = rispetto al delta y tra due valori di intervallo, se si verifica che non siamo già su uno dei domini (visibili o non visibili) limiti (0 o lunghezza), e se non siamo di incremento o decremento degli indici fetta di 1, reimpostare la variabile traduzione totale, quindi ridisegnare l'asse
+0

puoi pubblicare uno snippet? Grazie! – Dan

+0

+1 per qualche esempio di codice. – Thomas

+0

Sarebbe davvero fantastico con un esempio, grazie! – Kristoffer