2016-12-01 10 views
1

ドロップダウンから来る固定エクステント値のブラシを作成する必要があります(3,6,12、 24時間)ブラシの範囲をここではhttp://jsfiddle.net/9yccpjbu/とし、ドロップダウンを使用するボタン(ここではhttp://jsfiddle.net/gordonwoodhull/400wd2nd/16/など)の代わりにブラシの効果を得ることを試みます。 ボタンへの修正も歓迎されます。からの適切な値を表示するために、最初のクリックにg.chart-body- g.stack):ドロップダウン変更時のブラシエクステント/幅(dc.js、moment.js、d3.js、crossfilter)

ドロップダウン

1)ドロップダウンが表示スタック(バーを変更しますドロップダウン:それはドロップダウンから別の値をクリックすると、画像に(ドロップダウン(灰色のバーから6を選択した結果をスタックをレンダリングせずに白の値を加算し

enter image description here

)と3(whi TE):

enter image description here

2)をクリックした後、ドロップダウンブラシ程度(rect.extent)は
g.chart-body- g.stack
からdiconnectedれます。 (画像の赤い枠線):

enter image description here。に示す選択されたレコードの数をドロップダウンをクリックした後

enter image description here

3):ドロップダウンなし

は、タイムスライダは良い作品とこのようになりますからブラシを選択し、クリックされました「すべてリセット」リンクは0です(スタック上のrect.extentを移動すると選択したレコードの数が表示されます)。

4)**リンクはグラフをリセットしない「すべてリセット」と表示さドロップダウンで選択された項目の数

ボタン:

4)をクリックすると、彼らが表示さg.chart-body- g.stackの予想図及び寸法上の相補rect.extent(スタック+ rect.extent = dimesion):

enter image description here

Iは

filterDimension.filterRange([start, start.add('hours,amountHours).hours()]) 

から

filterDimension.filterRange([start.add('hours', amountHours).hours(), end]) 

g.chart-body- g.stackとRECTの範囲を変更します。範囲が補足されていますが、ブラシの範囲をドロップダウンから表示する必要がある範囲の補完的な範囲(必要な範囲(灰色)+範囲(青色の境界線付き)=ドメイン)は

enter image description here

5)「すべてリセット」リンクはグラフをリセットしたように見えますが、「すべてリセット」をクリックすると間違った番号が表示されます。

マイフィドル:https://jsfiddle.net/dani2011/upa3eowb/

JAVASCRIPT

  'use strict'; 
      // chart objects 
      var bitChart = dc.compositeChart("#bitrate-move-chart");//Before dynamic Y-Axis nonzero_min used var bitChart = dc.lineChart('#bitrate-move-chart'); 
      var bitChart2 = dc.compositeChart("#bitrate-move-chart2");//Before dynamic Y-Axis nonzero_min used var bitChart = dc.lineChart('#bitrate-move-chart'); 
      var timeSlider = dc.barChart('#bitrate-timeSlider-chart'); 
      var bitCount = dc.dataCount('.dc-data-count'); 
      var bitrateTable = dc.dataTable('.dc-data-table'); 

      //Creating dynamic Y axis with min/max ticks' values depending on min/max of data - copied from http://jsfiddle.net/gordonwoodhull/7anae5c5/1/... 

      // 15 Min Interval - copied from https://github.com/mbostock/d3/blob/master/src/time/interval.js..... 

      // generalization of d3.time.minute copied from- https://github.com/mbostock/d3/blob/master/src/time/minute.js.... 

      //bitchart 
      var min15 = n_minutes_interval(15); 
      //bitchart_2 
      var min15_2 = n_minutes_interval(15); 
      //timeSlider 
      var min15_3 = n_minutes_interval(15); 

      //### Load data 
      //var data = d3.csv.parse(d3.select("pre#data").text()); 
      d3.csv('CHANNEL_CLUSTER_BITRATE_takeThis.csv', function (data) { 
       // Format CSV data 
       var dateFormat = d3.time.format('%Y/%m/%d/%H:%M'); 
       var numberFormat = d3.format('.2'); 
       data.forEach(function (d) { 
        d.bitdate = new Date(d.DATETIME); //d.DATETIME = dateFormat.parse(d.DATETIME); 
        d.hours = d3.time.hours(d.bitdate); 
        d.BITRATE = +d.BITRATE.match(/\d+/); //d.BITRATE = +d.BITRATE; 
       }); 

       //### Crossfilter Dimensions 
       var crossFilteredData = crossfilter(data); 
       var all = crossFilteredData.groupAll(); 
       // Dimension by full date 
       //bitChart 
       var dateDimension = crossFilteredData.dimension(function (d) { 
        return d.bitdate; 
       }); 
       //bitChart2 
       var dateDimension2 = crossFilteredData.dimension(function (d) { 
        return d.bitdate; 
       }); 
       //timeSlider 
       var dateDimension3 = crossFilteredData.dimension(function (d) { 
        return d.bitdate; 
       }); 
       //dropDown 
       var filterDimension = crossFilteredData.dimension(function (d) { 
        return d.bitdate; 
       }); 

       //### Crossfiltered Groups 
       //timeSlider 
       var minIntervalWeekBitrateGroup3 = dateDimension3.group(min15_3).reduceSum(function (d) { 
        return 10 // +d.BITRATE 
       }); 

       //Group bitrate per week, 15 minInterval - maintain running tallies 
       //bitChart 
       var bitrateWeekMinIntervalGroupMove = dateDimension.group(min15).reduce(
        /* callback for when data is added to the current filter results */ 
        function (p, v) { 
         ++p.count; 
         p.BITRATE = +v.BITRATE; 
         p.total += +v.BITRATE; 
         p.avg = p.count ? Math.round(p.total/p.count) : 0; 
         return p; 
        }, 
        /* callback for when data is removed from the current filter results */ 
        function (p, v) { 
         --p.count; 
         p.BITRATE = +v.BITRATE; 
         p.total -= +v.BITRATE; 
         p.avg = p.count ? Math.round(p.total/p.count) : 0; 
         return p; 
        }, 
        /* initialize p */ 
        function() { 
         return { 
          count: 0, 
          bitrate: 0, 
          total: 0, 
          avg: 0 
         }; 
        } 
       ); 

       //bitChart2 
       var bitrateWeekMinIntervalGroupMove2 = dateDimension2.group(min15_2).reduce(
        /* callback for when data is added to the current filter results */ 
        function (p, v) { 
         ++p.count; 
         p.BITRATE = +v.BITRATE; 
         p.total += +v.BITRATE; 
         p.avg = p.count ? Math.round(p.total/p.count) : 0; 
         return p; 
        }, 
        /* callback for when data is removed from the current filter results */ 
        function (p, v) { 
         --p.count; 
         p.BITRATE = +v.BITRATE; 
         p.total -= +v.BITRATE; 
         p.avg = p.count ? Math.round(p.total/p.count) : 0; 
         return p; 
        }, 
        /* initialize p */ 
        function() { 
         return { 
          count: 0, 
          bitrate: 0, 
          total: 0, 
          avg: 0 
         }; 
        } 
       ); 

       //domain limits 
       var minDate = dateDimension.bottom(1)[0].DATETIME; 
       var maxDate = dateDimension.top(1)[0].DATETIME; 
       var start = moment(new Date(minDate)); 
       var end = moment(new Date(maxDate)); 
       //max line 
       var maxbit = d3.max(data, function (d) { return 
       +d["BITRATE"]; }); 

       //dropdown/buttons copied from http://jsfiddle.net/gordonwoodhull/400wd2nd/16/ , http://jsfiddle.net/9yccpjbu/ 
       var btns = d3.select(".buttons-container").selectAll("button").data(["3 Hours", "6 Hours", "12 Hours", "24 Hours"]); 
        btns = btns.enter().append("button") 
        .attr("class", "btn btn-sm btn-success") 
        // fill the buttons with the year from the data assigned to them 
        btns.each(function (d) { 
         this.innerText = d; 
        }) 
        btns.on("click", drawBrush) 

       function drawBrush() { 
        if (this.innerText === "Brush Extent") { } 
        if (this.innerText === "3 Hours") { addHours(3); } 
        if (this.innerText === "6 Hours") { addHours(6); } 
        if (this.innerText === "12 Hours") { addHours(12); } 
        if (this.innerText === "24 Hours") { addHours(24); } 
        timeSlider.filter(null); 
        timeSlider.filter(dc.filters.RangedFilter(start, end); 
        // timeSlider.x.domain(brush.empty() ? 
        timeSlider.x.domain() : brush.extent()); 
        dc.redrawAll(); 
       } 

       function addHours(amountHours) { 

        filterDimension.filterRange([start, start.add('hours', amountHours).hours()]); 
        //filterDimension.filterRange([start.add('hours', amountHours).hours(), end]); 
        dc.redrawAll(); 
       } 

       function brushed() { 
        timeSlider.x.domain(brush.empty()) ?  
        timeSlider.x.domain() : brush.extent()); 
       } 
       function fixed_now() { 
        return new Date(minDate) 
       } 

       d3.select('#hoursDropDown').on('change', function() { 
        filterDimension.filterRange([start, start.add(this.value, 
        'hours').hours()]); 
        dc.redrawAll(); 
        timeSlider.filter(null);//filterAll() 
        timeSlider.filter(dc.filters.RangedFilter(new 
        Date(start), new Date(end))); 
        dc.redrawAll(); 

        // timeSlider.x.domain(brush.empty() ? 
        // timeSlider.x.domain() : brush.extent()); 

        //var start = moment(new Date(minDate)); 
        // var end = moment(new Date(maxDate)); 
        // filterDimension.filterRange([start, 
        //start.add(this.value, 'hours').hours()]); 
        // dc.redrawAll(); 

       }); 

       //###Graphs 
       bitChart /* dc.lineChart('#bitrate-move-chart', 'chartGroup') */ 
        .xUnits(min15.range) //.xUnits(d3.time.weeks)//.round(d3.time.week) //.round(d3.time.minute)//d3.time.month.round) 
        .x(d3.time.scale().domain([new Date(minDate), new Date(maxDate)])) 
        .yAxisPadding('5%')  
        .elasticY(true) 
        //Specify a "range chart" to link its brush extent with the zoom of the current "focus chart". 
        .rangeChart(timeSlider) 
        .width(450) 
        .height(200) 
        .transitionDuration(500) 
        .margins({ top: 30, right: 50, bottom: 25, left: 50, padding: 1 }) 
        .mouseZoomable(true) 
        .brushOn(false) 
        .renderHorizontalGridLines(true) 
        .legend(dc.legend().x(800).y(10).itemHeight(13).gap(5)) 
        //Render max bitrate horizontal line copied from bar-extra-line.html 
        .yAxisLabel("Total Bitrate per 15 minutes") 
        .renderlet(function (chart) { 
         chart.svg().selectAll('.chart-body').attr('clip-path', null) 
        }) 
        .on('renderlet', function (chart) { 
         var left_y = 10, right_y = 70; // use real statistics here! 
         var extra_data = [{ x: chart.x().range()[0], y: chart.y()(left_y) }, { x: chart.x().range()[1], y: chart.y()(right_y) }]; 
         var line = d3.svg.line() 
          .x(function (d) { return d.x; }) 
          .y(function (d) { return maxbit; }) 
          .interpolate('linear'); 
         var chartBody = chart.select('g.chart-body'); 
         var path = chartBody.selectAll('path.extra').data([extra_data]); 
         path.enter().append('path').attr({ 
          class: 'extra', 
          stroke: 'red', 
          id: 'extra-line' 
         }); 
         path.attr('d', line); 
         // Label the max line 
         var text = chartBody.selectAll('text.extra-label').data([0]); 
         text.enter().append('text') 
           .attr('text-anchor', 'middle') 
          .append('textPath').attr({ 
           class: 'extra-label', 
           'xlink:href': '#extra-line', 
           startOffset: '50%' 
          }) 
          .text('Total Bitrate Max Value');  
        }) 
        // .ordinalColors('red') 
        // Title can be called by any stack layer. 
        .title(function (d) { 
         var value = d.value.total ? d.value.total : d.value; 
         if (isNaN(value)) { 
          value = 0; 
         } 
         return dateFormat(d.key) + ' \n Total Bit:' + numberFormat(value) 
        }) 

        //Creating dynamic Y axis with min max ticks' values depending on min max of data - copied from http://jsfiddle.net/gordonwoodhull/7anae5c5/1/ 
       .compose([ 
        nonzero_min(dc.lineChart(bitChart) 
         .dimension(min15) 
         .colors('blue') 
         .group(bitrateWeekMinIntervalGroupMove, 'Bitrate Total') 

         .valueAccessor(function (d) { 
          return d.value.total; 
         }) 
        // .dashStyle([2,2]) 
        .interpolate('step-after') 
         .renderArea(false) 
         .brushOn(false) 
         .renderDataPoints(false)   
         .clipPadding(10)), 
       ]) 
       bitChart.render(); 

       //bitchart2 
       bitChart2 /* dc.lineChart('#bitrate-move-chart', 'chartGroup') */ 
        .xUnits(min15_2.range) //.xUnits(d3.time.weeks)//.round(d3.time.week) //.round(d3.time.minute)//d3.time.month.round) 
        .x(d3.time.scale().domain([new Date(minDate), new Date(maxDate)])) 
        .yAxisPadding('5%') 
        .elasticY(true) 
        //Specify a "range chart" to link its brush extent with the zoom of the current "focus chart". 
        .rangeChart(timeSlider) 
        .width(450) 
        .height(200) 
        .transitionDuration(500) 
        .margins({ top: 30, right: 50, bottom: 25, left: 50, padding: 1 }) 
        .mouseZoomable(true) 
        .brushOn(false) 
        .renderHorizontalGridLines(true) 
        .legend(dc.legend().x(800).y(10).itemHeight(13).gap(5)) 
        //Render max bitrate horizontal line copied from bar-extra-line.html 
        .yAxisLabel("Total Bitrate per 15 minutes") 
        .renderlet(function (chart) { 
         chart.svg().selectAll('.chart-body').attr('clip-path', null) 
        }) 
        .on('renderlet', function (chart) { 
         var left_y = 10, right_y = 70; // use real statistics here! 
         var extra_data = [{ x: chart.x().range()[0], y: chart.y()(left_y) }, { x: chart.x().range()[1], y: chart.y()(right_y) }]; 
         var line = d3.svg.line() 
          .x(function (d) { return d.x; }) 
          .y(function (d) { return maxbit; }) 
          .interpolate('linear'); 
         var chartBody = chart.select('g.chart-body'); 
         var path = chartBody.selectAll('path.extra').data([extra_data]); 
         path.enter().append('path').attr({ 
          class: 'extra', 
          stroke: 'red', 
          id: 'extra-line' 
         }); 
         path.attr('d', line); 
         // Label the max line 
         var text = chartBody.selectAll('text.extra-label').data([0]); 
         text.enter().append('text') 
         .attr('text-anchor', 'middle') 
         .append('textPath').attr({ 
           class: 'extra-label', 
           'xlink:href': '#extra-line', 
           startOffset: '50%' 
          }) 
          .text('Total Bitrate Max Value'); 
        }) 
        // .ordinalColors('red') 
        // Title can be called by any stack layer. 
        .title(function (d) { 
         var value = d.value.total ? d.value.total : d.value; 
         if (isNaN(value)) { 
          value = 0; 
         } 
         return dateFormat(d.key) + ' \n Total Bit:' + numberFormat(value) 
        }) 

       //Creating dynamic Y axis with min max ticks' values depending on min max of data - copied from http://jsfiddle.net/gordonwoodhull/7anae5c5/1/ 
       .compose([ 
       nonzero_min(dc.lineChart(bitChart2) 
        .dimension(min15_2) 
         .colors('blue') 
         .group(bitrateWeekMinIntervalGroupMove2, 'Bitrate Total') 
         .valueAccessor(function (d) { 
          return d.value.total; 
         }) 
        //.dashStyle([2,2]) 
        .interpolate('step-after') 
        .renderArea(false) 
        .brushOn(false) 
        .renderDataPoints(false) 
        .clipPadding(10)), 
       ]) 
       bitChart2.render(); 

       //#### Range Chart 
       // Since this bar chart is specified as "range chart" for the area chart, its brush extent will always match the zoom of the area chart. 
       timeSlider 
        .dimension(dateDimension3)//.dimension(min15)//.dimension(weekDim)// // 
        .group(minIntervalWeekBitrateGroup3) 
        // .x(d3.time.scale().range([0, brushContainer.select("rect").attr("width")]).domain([new Date(dateDimension3.bottom(1)[0].DATETIME), new Date(dateDimension3.top(1)[0].DATETIME)])) 
        .x(d3.time.scale().domain([new Date(dateDimension3.bottom(1)[0].DATETIME), new Date(dateDimension3.top(1)[0].DATETIME)])) 
        .round(dc.round.floor) //(d3.time.month.round) 
        .xUnits(min15_3.range)//.xUnits(d3.time.week) //.xUnits(d3.time.minute) //.xUnits(d3.time.months) 
        .width(990) /* dc.barChart('#bitrate-timeSlider-chart', 'chartGroup'); */ 
        .height(40) 
        .margins({ top: 0, right: 50, bottom: 20, left: 40 }) 
        // .centerBar(true) 
        .gap(1) 
        .mouseZoomable(true) 
       //#### Data Count dateformat.parse(d.time); 
       bitCount /* dc.dataCount('.dc-data-count', 'chartGroup'); */ 
        .dimension(crossFilteredData) 
        .group(all) 
        .html({ 
         some: '<strong>%filter-count</strong> records selected out of <strong>%total-count</strong> records' + 
          ' | <a href=\'javascript:dc.filterAll(); dc.renderAll();\'>Reset All</a>', 
         all: ' All records selected. Please click on the graph to apply filters.' 
        }); 
       //#### Data Table 
       bitrateTable /* dc.dataTable('.dc-data-table', 'chartGroup') */ 
        .dimension(dateDimension) // .dimension(dateDimension) 
        // Data table does not use crossfilter group but rather a closure as a grouping function 
        .group(function (d) { 
         var format = d3.format('02d'); 
         return d.bitdate.getFullYear() + '/' + format((d.bitdate.getMonth() + 1)); 
        }) 
        .sortBy(function (d) { return d.bitdate; }) 
        // (_optional_) max number of records to be shown, `default = 25` 
        .size(13) 
        .columns([ 
         'DATETIME', 
         'CHANNEL_ID', 
         'BITRATE' 
        ]) 
        // (_optional_) custom renderlet to post-process chart using [D3](http://d3js.org) 
        .on('renderlet', function (table) { 
         table.selectAll('.dc-table-group').classed('info', true); 
        }); 
       //#### Rendering 
       //Render all charts on the page 
       dc.renderAll(); 


       //#### Versions 
       //Determine the current version of dc with `dc.version` 
       d3.selectAll('#version').text(dc.version); 
       // Determine latest stable version in the repo via Github API 
       d3.json('https://api.github.com/repos/dc-js/dc.js/releases/latest', function (error, latestRelease) { 
        /*jshint camelcase: false */ 
        d3.selectAll('#latest').text(latestRelease.tag_name); /* jscs:disable */ 
       }); 

      }); 

      //d3.select('#myDropDown2').on('change', function() { 
      // var nd = new Date(minDate); 
      // nd.setDate(nd.getDate() + +this.value); 
      // var start1 = moment(new Date(d.key)); 
      //var nd = new Date(minDate); 
      //nd.setDate(nd.getDate()); 
      // filterDimension.filterRange([nd, nd.setDate(nd.getDate() + +this.value)]); 
      // dc.redrawAll(); 
      //}); 

      //var brushContainer = d3.select("svg"); 
      //alert(brushContainer.select("rect").attr("width")); 
      // start.max(new Date(minDate), new Date(maxDate)); 
      // moment.max(start, end); 
      //if ((start.add(this.value, 'hours').hours()).getTime()>= end) 
      //{ 
      // filterDimension.filterRange([start, end]); 
      //} 
      //else 
      //{ 
      //filterDimension.filterRange([start, start.add(this.value, 'hours').hours()]); 
      //} 
      // timeSlider.filter(null); 
      //d3.select("svg").select("rect").enter().append('rect').attr({ width: ''+ this.value +'' }); 
      // timeSlider.x.domain(brush.empty() ? timeSlider.x.domain() : brush.extent(0,this.value)); 
      // focus.select("timeSlider.area").attr("d", area); 
      // focus.select("timeSlider.x.axis").call(xAxis); 
      // } 

      // dc.renderAll(); 

すべてのヘルプは非常にいただければ幸いです!

+0

は(どちらか動作しませんでした)次のコード行を追加して変更することも試み:brush.extent ([新しい日付(開始)、新しい日付(終了)]); ブラシ(timeSlider.select( "。ブラシ")。遷移()。遅延(1000)); dateDimension3 = data.filter(function(d、i){ )var mon2 =瞬間(新しい日付(d.bitdate))。フォーマット(「YYYY-MM-DD」)。 if((mon2> = start)&&(mon2 <= end)){ return d.bitdate; } ... – Dani

答えて

1

ここに余分なコードがたくさんあります。何かがうまくいかない場合は、次のことを試す前に実際に削除する必要があります。 :)

だから、これは本当に簡単です。

最初に、クロスフィルターのディメンションに直接ではなく、グラフを使用してフィルターを設定する必要があります。 Crossfilterにはゲッターが用意されていないので、チャートにブラシを表示する場所を指定する必要があります。別のfilterDimensionは、時間フィルタを示すグラフがない場合にのみ必要となります。この余分なディメンションを設定すると、グラフがリセットされたときに余分なフィルタリングが行われているため、リセットは実行されません。

ボタンをドロップダウンと同じにするには、両方ともaddHoursを使用してください。また、.filter(null)を行うよりも少し速くなり、その後、別のフィルタを設定する必要のある、replaceFilterを使用することができます。

function drawBrush() { 
    if (this.innerText === "Brush Extent") { } 
    if (this.innerText === "3 Hours") { addHours(3); } 
    if (this.innerText === "6 Hours") { addHours(6); } 
    if (this.innerText === "12 Hours") { addHours(12); } 
    if (this.innerText === "24 Hours") { addHours(24); } 
} 

d3.select('#hoursDropDown').on('change', function() { 
    addHours(this.value); 
}); 

function addHours(amountHours) { 
    timeSlider.replaceFilter(...); 
    dc.redrawAll(); 
} 

...に何が起こるのか?私はこれがこれをとても混乱させていたもう一つの部分だと思って、それを理解するのにはしばらく時間がかかりました。 moment.jsは副作用のない機能的なスタイルを使用していますが、実際には毎回日付オブジェクトが変更されていると思います。したがって、電話すると

start.add(amountHours, 'hours') 

複数回、startに毎回追加されます。代わりに、我々はclone start before modifying it次のことが可能です。

moment(start).add(amountHours, 'hours') 

(注:現在は廃止インタフェース不満たので、私はまた、引数の順序を逆にしました)

ここでもう一つの問題は、あなたがいないということですmoment.hours()に電話したい場合は、時間、整数、および有効な日付オブジェクトをもうフェッチしません。すべて一緒にこれを置く

は、それだけだ:あなたのフィドルの

function addHours(amountHours) { 
    timeSlider.replaceFilter(dc.filters.RangedFilter(start, moment(start).add(amountHours, 'hours'))); 
    dc.redrawAll(); 
} 

フォーク:http://jsfiddle.net/gordonwoodhull/ewmrmu83/9/

+0

大きなおかげでゴードン - すべての時間、助けと説明のために。 mom.jsを使用していて、replaceFilterの機能を使用していない間は、クローニングについて認識していませんでした。これを大変感謝しています - Dani。 – Dani

関連する問題