2014-12-12 4 views
4

Я работаю с dc.js в течение последних нескольких недель, но есть одна проблема, которую я просто не могу понять.Dc.js Применение диапазона Диаграмма к нескольким графикам

Я хочу, чтобы иметь возможность изменять шкалы четырех разных диаграмм на основе одной диаграммы с помощью фильтра кисти. Что-то вдоль линий:

priorityTotChart 
    .width(2*w/3).height(h/3) 
    .margins({top: 10, right: 50, bottom: 20, left: 40}) 
    .dimension(dateDim) 
    .group(priorityTotal) 
    .centerBar(true) 
    .gap(1) 
    .x(d3.time.scale().domain([minDate,maxDate])) 
    .elasticY(true) 
    .brushOn(true); 

var translate = 3; 

priority1Chart.width(w/3) 
    .height(h/6) 
    .transitionDuration(300) 
    .margins({top: 10, right: 50, bottom: 25, left: 40}) 
    .dimension(dateDim) 
    .group(priority1) 
    .mouseZoomable(false) 
    .x(d3.time.scale().domain([minDate,maxDate])) 
    .xUnits(d3.time.months) 
    .elasticY(true) 
    .brushOn(false) 
    .ordinalColors(["red"]) 
    .rangeChart(priorityTotChart) 
    .yAxisLabel("Hits per day") 
    .renderArea(true) 
    .renderlet(function (chart) { 
    chart.selectAll("g._1").attr("transform", "translate(" + translate + ", 0)"); 
}); 

priority2Chart.width(w/3) 
    .height(h/6) 
    .transitionDuration(300) 
    .margins({top: 10, right: 50, bottom: 25, left: 40}) 
    .dimension(dateDim) 
    .group(priority2) 
    .mouseZoomable(false) 
    .x(d3.time.scale().domain([minDate,maxDate])) 
    .xUnits(d3.time.months) 
    .elasticY(true) 
    .brushOn(false) 
    .ordinalColors(["orange"]) 
    .rangeChart(priorityTotChart) 
    .yAxisLabel("Hits per day") 
    .renderArea(true) 
    .renderlet(function (chart) { 
    chart.selectAll("g._1").attr("transform", "translate(" + translate + ", 0)"); 
}); 

priority3Chart.width(w/3) 
    .height(h/6) 
    .transitionDuration(300) 
    .margins({top: 10, right: 50, bottom: 25, left: 40}) 
    .dimension(dateDim) 
    .group(priority3) 
    .mouseZoomable(false) 
    .x(d3.time.scale().domain([minDate,maxDate])) 
    .xUnits(d3.time.months) 
    .elasticY(true) 
    .brushOn(false) 
    .ordinalColors(["blue"]) 
    .rangeChart(priorityTotChart) 
    .yAxisLabel("Hits per day") 
    .renderArea(true) 
    .renderlet(function (chart) { 
    chart.selectAll("g._1").attr("transform", "translate(" + translate + ", 0)"); 
}); 

priority4Chart.width(w/3) 
    .height(h/6) 
    .transitionDuration(300) 
    .margins({top: 10, right: 50, bottom: 25, left: 40}) 
    .dimension(dateDim) 
    .group(priority4) 
    .mouseZoomable(false) 
    .x(d3.time.scale().domain([minDate,maxDate])) 
    .xUnits(d3.time.months) 
    .elasticY(true) 
    .brushOn(false) 
    .ordinalColors(["green"]) 
    .rangeChart(priorityTotChart) 
    .yAxisLabel("Hits per day") 
    .renderArea(true) 
    .renderlet(function (chart) { 
    chart.selectAll("g._1").attr("transform", "translate(" + translate + ", 0)"); 
}); 

Однако этот метод не похоже на работу, как только последний график, который использует .rangeChart(priorityTotChart) будет обновляться.

я могу обойти эту проблему, сделав каждый график в зависимости от диапазона предыдущего графика т.е. priority1Chart имеет .rangeChart(priorityTotChart) и priority2Chart имеет .rangeChart(priority1Chart) и т.д., но этот метод является очень медленным. Итак, я надеялся, что есть лучший способ добиться такого же эффекта?

Заранее благодарен!

ответ

4

Другой способ задать свой вопрос: «Как я могу привязать несколько диаграмм фокуса к одной диаграмме диапазона?»

(По крайней мере, если вы заботитесь только о чистке диапазон диаграммы масштабирования фокусные диаграммы, а не наоборот.)

Учитывая этот новый вопрос, посмотрим на реализацию coordinateGridMixin.focusChart:

_chart.focusChart = function (c) { 
    if (!arguments.length) { 
     return _focusChart; 
    } 
    _focusChart = c; 
    _chart.on('filtered', function (chart) { 
     if (!chart.filter()) { 
      dc.events.trigger(function() { 
       _focusChart.x().domain(_focusChart.xOriginalDomain()); 
      }); 
     } else if (!rangesEqual(chart.filter(), _focusChart.filter())) { 
      dc.events.trigger(function() { 
       _focusChart.focus(chart.filter()); 
      }); 
     } 
    }); 
    return _chart; 
}; 

Все, что нам нужно сделать, это сделать новую версию функции, которая принимает несколько диаграмм фокусировки. Поскольку эта функция не имеет доступа к внутренним данным, мы можем «обезьяна патч» любой координатной сетки диаграммы, чтобы добавить функциональность:

chart1.focusCharts = function (chartlist) { 
    if (!arguments.length) { 
     return this._focusCharts; 
    } 
    this._focusCharts = chartlist; // only needed to support the getter above 
    this.on('filtered', function (range_chart) { 
     if (!range_chart.filter()) { 
      dc.events.trigger(function() { 
       chartlist.forEach(function(focus_chart) { 
        focus_chart.x().domain(focus_chart.xOriginalDomain()); 
       }); 
      }); 
     } else chartlist.forEach(function(focus_chart) { 
      if (!rangesEqual(range_chart.filter(), focus_chart.filter())) { 
       dc.events.trigger(function() { 
        focus_chart.focus(range_chart.filter()); 
       }); 
      } 
     }); 
    }); 
    return this; 
}; 

Нам также необходимо скопировать функцию rangesEqual помощника из coordinateGridMixin для того, чтобы получить это за работой.

Я создал пример и добавить его к dc.js примеров:

http://dc-js.github.io/dc.js/examples/multi-focus.html

Вы можете увидеть источник здесь:

https://github.com/dc-js/dc.js/blob/master/web/examples/multi-focus.html

Это было бы неплохо, чтобы поддержать родной , в том числе с обратным фильтром zoom ->, который требует изменения внутренних компонентов dc.js. Я добавил вопрос, чтобы проследить идею: https://github.com/dc-js/dc.js/issues/820

2

Диаграмма диапазона работает с .x() - шкалой диаграммы фокусировки.

Что вы можете сделать, так это определить один масштаб по всему миру и использовать его для каждого графика, который должен контролироваться диаграммой дальности. Только одна из диаграмм фокусировки должна установить свойство .rangeChart().

Это неопределенное поведение, я думаю, что это может измениться в будущем.

псевдокод:

var xScale = d3.scale.linear(); 
var xScaleRange = d3.scale.linear(); 

var rangeChart = dc.lineChart('#R').x(xScaleRange).[...]; 

var focusChartA = dc.barChart('#A').x(xScale).rangeChart(rangeChart).[...]; 
var focusChartB = dc.barChart('#B').x(xScale).[...]; 
+0

Это интересное решение. Не совсем безопасно, как мое решение ниже, но оно должно работать в большинстве случаев. – Gordon