Dc.js applying a range chart to multiple graphs

I have been working with dc.js for the past few weeks, but there is one problem that I just cannot understand.

I want to be able to change the scales of four different diagrams based on one diagram with a brush filter. Sort of:

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

However, this method does not work, since only the last chart that uses .rangeChart(priorityTotChart) is .rangeChart(priorityTotChart) .

I can get around this problem by making each chart depend on the range of the previous chart, i.e. priority1Chart has .rangeChart(priorityTotChart) , and priority2Chart has .rangeChart(priority1Chart) , etc., but this method is very slow. So, I was hoping there was a better way to achieve the same effect?

Thanks in advance!

+5
source share
2 answers

Another way to ask your question is: "How can I link multiple focus charts to one range chart?"

(At least if you only need to clear the range chart by scaling the focus charts, and not vice versa).

Given this new question, take a look at the implementation of the coordinates of GridMixin.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; }; 

All we need to do is make a new version of a function that uses several focus diagrams. Since this function does not have access to any internal data, we can “plan monkeys” with any coordinate grid to add functionality:

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

We also need to copy the rangeEqual hand function function from the GridMixin coordinate to get this working.

I created an example and added it to the dc.js examples:

http://dc-js.imtqy.com/dc.js/examples/multi-focus.html

Here you can see the source:

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

It would be great to support initially, including the inverse filter → filter, which requires changing the internal components of dc.js. I added a problem to track the idea: https://github.com/dc-js/dc.js/issues/820

+4
source

Range chart works with .x () - focus chart scale.

What you can do is define one scale on a global scale and use it for each graph, which should be controlled by a range chart. Only one of the focus diagrams should set the .rangeChart () property.

This is undefined behavior, which I think means that this may change in the future.

Pseudocode:

 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).[...]; 
+2
source

Source: https://habr.com/ru/post/1208889/


All Articles