2013-11-15 10 views
8

ティック/ラベルが動的に表示される軸機能を作成しようとしているため、自動的に表示/非表示されます。しかし、その上に、いくつかのズームレベルで、より多くのティック/ラベルのレンダリングを止めたいと思っています。次に例を示します。最初に軸に年が表示され、次に目盛りが月になり、さらにズームインすると日が表示されます(I.E.、Dec 28)。月を私が望む最も小さい単位であるので、月よりもズームするときにそれ以上のダニをレンダリングしないように、d3を制限したいとします。ズーム時にD3軸のラベルが細かすぎる

私はいくつかの例がありますが、組み合わせると正確に私が望むものになりますが、その方法を理解できません。

また、ティックフォームを追加しました。すべてのティックを省略した月形式で表示したいからです。

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

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

この例は、ダニが/ラベルが表示され、中にズームするときに正しく消えていますが、中にズーム継続する場合、それは/ヶ月分割し、月がダニ繰り返し起動する方法を示していますラベルは、と私はズームインからユーザーを制限しない

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

この例では、例1のように拡大を続けても、ズーム時に目盛りやラベルを動的に隠す/表示しないように問題を修正しています。

+3

D3が自動的にそれを行うには、 '与える必要はありません.tickFormat' at all - http://jsfiddle.net/GGYKL/1/ –

+0

あなたは単にあなた自身のマルチスケールの時間フォーマットを定義することができます - http://bl.ocks.org/mbostock/4149176 –

+0

@Lars Kotthoff .tickFormatを追加した理由は、月のティック形式を短縮したいからです(Jan、Feb、Mar、2013ではなくJanuary)。 d3に特定のズーム度で目盛りを追加するオプションがありますか?月のダニを表示した後のように、さらにズームするとその範囲を日に分割しませんか?私はあなたの例を使用します: "2004"をズームインすると "April"、 "July"、October "、" 2004 "などが表示されますが、ズームを続けると" November "、" December " 「2004年」など、さらに拡大すると、「Dec 28」、12月29日に分割されます。これは私が把握しようとしているものです。 – dcryan22

答えて

5

は、私が遭遇してきた最も近い答えが@Lars Kotthoffが示唆されたマルチスケールの時間フォーマットでした。

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; }] 
]); 

はそうでズーム時に自分自身がまだ生成されるダニが、ラベルが空の文字列のようになります。私はするカスタム時刻フォーマッタを編集しました。

UPDATE:

I)は、(私は.ticksで使用される自分の関数を作成することになりました。 Ticksは、スケールエクステントをt0とt1として関数に渡します。グラフの幅をラベルサイズ(およびパディング)で割って、重複しないラベルの最大量を見つけ出し、オーバーラップが発生すると、他のすべての目盛りを削除するためにアンダースコアを使用しました。

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"); 

アップデート2:ティックは今では4つのレベル(2,3,4,6)を有し、さらにわずか1レベルより調整製

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

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

私もこれを達成しようとしていました。しかし、私は月関数が何月か分かっていないのですが、それが何のために使われているのかを教えてください。 – Himanshu

+0

時間がt0からt1までのすべての月で入力された後、_.filter()はmonthFactorsを使用して、重複することなく月ラベルに収まる最適な解決策を見つけます。 – dcryan22

+1

これを展開する必要があります日、分、秒で作業することができますが、なぜこのメソッドをデフォルトのtime.scaleのtick関数よりも使用するのですか?このようにします:http://bl.ocks.org/mbostock/1667367 – dcryan22

-1

.tickFormatを削除すると、D3は自動的にティックを動的に更新します。 ダニを制限することもできます。

例:

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

ダニを動的に更新することを意味するとき、最初の例のようにダニ/ラベルを自動的に隠す/表示することを意味しました。私がしようとしているのは、ある程度のズームをした後で、最小の単位をMonthsにしたいので、d3がダミー/ラベルを生成しないようにしたいのです。 – dcryan22

1

私はd3 charting components layerでの作業中に同様の問題があったと私は軸のレンダリングの前に呼び出して、この方法でそれを解決:この例では

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); 
     } 
    } 

、期間が対象ですが、難しい提供することができますperiod.seconds(1つの間隔の継続時間)と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'}); 

私はxAxis.ticks内のすべての時間がxAxis.ticks(d3.time.seconds、86400)として日最小を表現するとき、私は巨大なパフォーマンスの低下を持っていたということですので、私は、保存された秒を使用していない理由フィールド内のd3に必要な要素

考え方は、間隔やカウントのうちの2つの軸の動作を再生することです。しきい値を下回ると、一定の間隔を使用します。これを超えると、d3の自動動作に戻ります。これはズームインした後にズームアウトの問題を解決します。else部分がなければ、指定した間隔にとどまる多くのティックになります。

そして、あなただけのコピー/簡単な例を貼り付けたい場合には、ここでは1日の最小間隔の例です:

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); 
     } 
    }