0
votes

Edit : JSBin dont work go to JS fiddle to see my code

I'm training my self with d3 and crossfilter and i face some difficulties.
I'm trying to make a chaining function to create bar chart. The idea is to not write all the code again and again for each bar chart i want to create.
I was inspired by the example Fast Multidimensional Filtering for Coordinated Views which is what i wanted to do (you can find code Here).

But I want to bring some personal touches in my generic barChart function.
I decided to do it with chaining function like in the example.
I understood how to create as many graphics as you wish, but i dont understand, (when brushes event appears), how to redraw all the bar depending on the filter.

If i wanted to do it outside a function i would define again the all the properties like x, y, axis etc. depending on the new data which is the filtered data like this:

var updateRange = function(filt){
    data = dimension.filter(filt) //assuming dimension is a crossfilter dimension
    // Scale the range of the data again 
x.domain([0, d3.max(data, function(d) { return d.key; })+1]);

// Select the section we want to apply our changes to

var chart = d3.select(".chart")
//Update all rects

chart.selectAll("rect.hidden")
   .data(data)
   .transition()
   .delay(function(d, i) {
        return i * 50;
    })
   .duration(500)
   .attr("y", function(d) {
        return y2(d.value);
   })
   .attr("height", function(d) {
        return height - y2(d.value);
});

I made a JSBin to discuss on how we can make the chart updated.
And this is the brush functions i use.

brush.on("brushstart", function() {
  var div = d3.select(this.parentNode.parentNode.parentNode);
  div.select(".title a").style("display", null);
});

brush.on("brush", function() {
  var g = d3.select(this.parentNode),
    extent = brush.extent();
  if (round) g.select(".brush")
    .call(brush.extent(extent = extent.map(round)))
    .selectAll(".resize")
    .style("display", null);
  g.select("#clip-" + id + " rect")
    .attr("x", x(extent[0]))
    .attr("width", x(extent[1]) - x(extent[0]));
  dimension.filter(extent);
});

brush.on("brushend", function() {
  if (brush.empty()) {
    var div = d3.select(this.parentNode.parentNode.parentNode);
    div.select(".title a").style("display", "none");
    div.select("#clip-" + id + " rect").attr("x", null).attr("width", width);
    dimension.filterAll();
  }
)};

waiting for your comments,
Chris.

Edit : some clarification

To be clearer, when i render the chart and use the brush the data are correctly filtered. (if i put some console.log i see the data filtered depending on the brush)
But the chart are not updated depending on the brush. I know the issue come from th way i used the brush event (brush.on().
I think i need to call the render function in some way but dont know how to do it with chaining function to be applied to all the charts.

Edit : Chart updated with external brush

The chart are now successfully updated when the brush is set externally (by clicking on the link).
Just adding this lines

if (brushDirty) {
  brushDirty = false;
  g.selectAll(".brush").call(brush);
  div.select(".title a").style("display", brush.empty() ? "none" : null);
  if (brush.empty()) {
    g.selectAll("#clip-" + id + " rect")
        .attr("x", 0)
        .attr("width", width);
  } else {
    var extent = brush.extent();
    g.selectAll("#clip-" + id + " rect")
        .attr("x", x(extent[0]))
        .attr("width", x(extent[1]) - x(extent[0]));
  }
}
2

2 Answers

1
votes

In order to update charts you can remove it and then redraw with new filters. Something like this :

 d3.selectAll(".chart").selectAll("svg").remove();

Or

 $('#chart'+chart_id+' svg').remove();

and then redraw it by calling again your drawing function with updated data.

Hope this will help you. Sorry If I misunderstood you. I need to train my english =P

EDIT :

I found these examples without remove. It might help you.

http://jsfiddle.net/sx9myywh/

https://bl.ocks.org/RandomEtc/cff3610e7dd47bef2d01

0
votes

I found where the problem was. And i feel stupid.

The brush.onevent was placed incide the function which generate the chart and have to be outside.

function my(div){

}
brush.on(...

I have updated the JS Fiddle with the correct answer.
I will create a github repository it will be cleaner.