2013-11-15 12 views
8

Sto provando a creare una funzione di asse che le tacche/etichette siano dinamiche e significano che si nascondono/mostrano automaticamente. Ma in cima a quello, voglio ad un certo livello di zoom per fermare il rendering di più zecche/etichette. Ecco un esempio: all'inizio l'asse mostra gli anni, quindi quando si ingrandisce, i tick diventano Mesi, e quando si ingrandisce ulteriormente, mostra i giorni (I.E., 28 dicembre). Tranne che voglio limitare d3 in modo tale che quando esegui lo zoom oltre i mesi, non rende più tick perché i mesi sono l'unità più piccola che voglio.Le etichette degli assi D3 diventano troppo granulose quando si ingrandisce

Ho un paio di esempi che se combinato sarebbe esattamente quello che voglio, ma non riesco a capire come farlo.

Inoltre: Ho aggiunto il .tickFormat perché voglio visualizzare ogni segno di spunta per avere un formato di mese abbreviato.

Esempio 1: http://jsfiddle.net/GGYKL/

var xAxis = d3.svg.axis().scale(x) 
    .tickFormat(d3.time.format('%b')) 
    .orient("bottom"); 

Questo esempio mostra come le zecche/etichette appaiono e scompaiono correttamente quando lo zoom in, ma quando si continua lo zoom in, si divide i mesi e inizia a ripetere il mese zecche/etichette, e io non voglio impedire all'utente di zoom in

Esempio 2:. http://jsfiddle.net/4kz7t/

Questo esempio corregge il problema quando si esegue lo zoom in avanti come quello che abbiamo visto con l'Esempio 1, MA non si nasconde/mostra dinamicamente le zecche/etichette durante lo zoom.

+3

D3 lo fa automaticamente, non dovrebbe essere necessario per dare un ' .tickFormat' a tutti - http://jsfiddle.net/GGYKL/1/ –

+0

Puoi semplicemente definire il tuo formato ora multi-scala - vedi http://bl.ocks.org/mbostock/4149176 –

+0

@ Lars Kotthoff La ragione per cui ho aggiunto il .tickFormat è perché voglio il formato del mese abbreviato (gennaio, febbraio, marzo non 2013, gennaio). C'è un'opzione in d3 per interrompere l'aggiunta di più segni di graduazione a un certo grado di zoom? Dire come dopo aver mostrato i segni di spunta del mese, se si ingrandisce ulteriormente NON si divide l'intervallo in giorni? Userò il TUO esempio: se fai zoom su "2004" vedrai presto "Aprile", "Luglio", Ottobre "," 2004 ", ecc. MA se continui a zoomare, vedi" Novembre "," Dicembre " , "2004", ecc. Zoom ancora di più e si divide in "28 dicembre", 29 dicembre "che è quello che sto cercando di capire. – dcryan22

risposta

5

La risposta più vicina che ho incontrato era il momento formato multi-scala che @ Lars Kotthoff suggerito. Ho modificato il tempo di formattazione personalizzata di essere:

http://jsfiddle.net/BdGv5/1/

var customTimeFormat = timeFormat([ 
    [d3.time.format("%Y"), function() { return true; }], 
    [d3.time.format("%b"), function(d) { return d.getMonth(); }], 
    [function(){return "";}, function(d) { return d.getDate() != 1; }] 
]); 

Così il zecche si sarebbe ancora essere generato quando lo zoom in, ma le etichette sarebbe stringa vuota.

UPDATE:

ho finito per creare la mia propria funzione che ho usato in .ticks(). Le zecche passano alla tua funzione l'estensione della scala come t0 e t1. Ho diviso la larghezza del grafico in base alla dimensione dell'etichetta (e al padding) per trovare la quantità massima di etichette senza sovrapposizioni e ho usato il trattino basso per rimuovere ogni altro segno di spunta se si verifica una sovrapposizione.

http://jsfiddle.net/BdGv5/3/

function customTickFunction(t0, t1, dt) 
    { 

     var labelSize = 30; // largest label is 23 pixels ("May") 
     var maxTotalLabels = Math.floor(width/labelSize); 

     function step(date, offset) 
     { 
      date.setMonth(date.getMonth() + offset); 
     } 

     var time = d3.time.month.ceil(t0), times = []; 

     while (time < t1) times.push(new Date(+time)), step(time, 1); 

     if(times.length > maxTotalLabels) 
      times = _.filter(times, function(d){ 
       return (d.getMonth() + 1) % 2; 
      }); 

     return times; 
    } 

    var domain = xScale.domain(); 
    var xAxisMonthsFunction = d3.svg.axis().scale(xScale) 
     .ticks(customTickFunction) 
     .tickFormat(d3.time.format("%b")) 
     .orient("bottom"); 

Aggiornamento 2:

http://jsfiddle.net/BdGv5/5/

fatto la zecche regolare oltre la semplice 1 livello, ora ha 4 livelli (2,3,4,6).

function customTickFunction(t0, t1, dt) 
{ 

    var labelSize = 30; // largest label is 23 pixels ("May") 
    var maxTotalLabels = Math.floor(width/labelSize); 

    function step(date, offset) 
    { 
     date.setMonth(date.getMonth() + offset); 
    } 

    var time = d3.time.month.ceil(t0), times = [], monthFactors = [2,3,4,6]; 

    while (time < t1) times.push(new Date(+time)), step(time, 1); 

    var i; 
    for(i=1 ; times.length > maxTotalLabels ; i++) 
     times = _.filter(times, function(d){ 
      return (d.getMonth()) % monthFactors[i] == 0; 
     }); 

    return times; 
} 
+0

Stavo anche cercando di ottenere questo, e questo sembra utile Però, non capisco per che meseFactors è possibile. Potresti spiegare per cosa è usato? Voglio estendere questa funzione per funzionare anche con giorni, minuti e secondi. Anche il ciclo for non si interrompe mai se la condizione non è È vero – Himanshu

+0

Dopo che i tempi sono stati riempiti con tutti i mesi da t0 a t1, il _.filter() utilizza i meseFactors per trovare la soluzione migliore possibile per adattare le etichette del mese senza sovrapposizioni – dcryan22

+1

Dovrai sicuramente espandere questo lavorare con giorni, minuti e secondi, ma perché dovresti utilizzare questo metodo rispetto alla funzione di spunta predefinita time.scale? come questa: http://bl.ocks.org/mbostock/1667367 – dcryan22

-1

Rimuovere .tickFormat poiché D3 aggiorna automaticamente i segni di graduazione in modo dinamico. Puoi anche limitare i tick.

Esempio:

d3.svg.axis().scale(x) 
.ticks(6) /*Number of Ticks you desire to display in x-axis scale*/ 
.orient("bottom") 
+0

Quando intendo aggiornare i tick in modo dinamico, intendevo che nascondono/mostrano automaticamente le zecche/etichette come il mio primo esempio. Quello che sto cercando di fare è dopo un certo grado di zoom, non voglio d3 generare più tick/etichette perché voglio che l'unità più piccola sia Mesi. – dcryan22

1

ho avuto un problema simile mentre si lavora su un d3 charting components layer e risolto con questo metodo che io chiamo prima del rendering asse:

function preventTooSmallTimeIntervals(period) { 
     var tickSeconds = (xScale.ticks()[1] - xScale.ticks()[0])/1000; 
     var minSecondsPerInterval = period.seconds; 
     if (tickSeconds < minSecondsPerInterval) { 
      xAxis.ticks(period.d3TimeInterval.unit, period.d3TimeInterval.value); 
     } else { 
      xAxis.ticks(6); 
     } 
    } 

In questo esempio, il periodo è un oggetto, ma è in grado di fornire duro i valori codificati per la situazione anziché i periodi period.seconds (che è la durata di un intervallo) e period.d3TimeInterval.

sc.model.period.day1 = periodFactory({ 
     display: '1 Day', 
     seconds: 86400, 
     d3TimeInterval: {unit: d3.time.day, value: 1}, 
     timeFormat: '%b-%d'}); 
    sc.model.period.hour1 = periodFactory({ 
     display: '1 Hour', 
     seconds: 3600, 
     d3TimeInterval: {unit: d3.time.hour, value: 1}, 
     timeFormat: '%b-%d %Hh'}); 
    sc.model.period.minute5 = periodFactory({ 
     display: '5 Minutes', 
     seconds: 300, 
     d3TimeInterval: {unit: d3.time.minute, value: 5}, 
     timeFormat: '%H:%M'}); 
    sc.model.period.minute1 = periodFactory({ 
     display: '1 Minute', 
     seconds: 60, 
     d3TimeInterval: {unit: d3.time.minute, value: 1}, 
     timeFormat: '%H:%M'}); 

Il motivo per cui non sto usando secondi ogni volta che in xAxis.ticks è che ho avuto un enorme calo di prestazioni quando esprime un minimo giorno come xAxis.ticks (d3.time.seconds, 86400), così ho conservato gli elementi necessari per d3 in un campo.

L'idea è di giocare con i 2 comportamenti di axis.ticks, un intervallo o un conteggio. Sotto la soglia, usiamo un intervallo fisso, al di sopra ritorniamo al comportamento automatico d3. Che risolve il problema dello zoom dopo aver ingrandito. Senza la parte else, si ottengono molti tick che restano nell'intervallo specificato.

E nel caso in cui si desidera solo per copiare/incollare un semplice esempio, ecco un esempio per un intervallo minimo di 1 giorno:

function preventTimeIntervalsSmallerThanADay() { 
     var tickSeconds = (xScale.ticks()[1] - xScale.ticks()[0])/1000; 
     var secondsPerDay = 86400; 
     if (tickSeconds < secondsPerDay) { 
      xAxis.ticks(d3.time.day, 1); 
     } else { 
      xAxis.ticks(6); 
     } 
    } 
Problemi correlati