I have a vertical stacked bar chart and want to dynamically remove rect
elements. To do this I followed the basic enter/update/exit procedure. What happens though is, that the bars seem to be added even if their width = 0;
var drawBars = function(data) { var margin = {top: 5, right: 20, bottom: 5, left: 170}, width = 1020 - margin.left - margin.right, height = 1820 - margin.top - margin.bottom, scope = this; var x = d3.scale.linear() .rangeRound([0, width-150]); var y = d3.scale.ordinal() .rangeBands([0,height], .2, 3); var color = d3.scale.category20c(); var xAxis = d3.svg.axis() .scale(x) .orient("top") .tickSize(0) .tickFormat(d3.format("s")); var yAxis = d3.svg.axis() .scale(y) .tickSize(0) .orient("left"); var svg = d3.select('#barchart svg') .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var createData = function(filter) { var data = d3.nest() .key(function(d) { return d.org; }) .key(function(d){ return d.taskforce_id }) .rollup(function(v){ return v.length }) .entries(scope.rawData['participants']); _.each(data, d => { _.extend(d, _.object(_.map(d.values, c => { if (typeof filter !== 'undefined') { if (c.key == filter) { return [c.key, c.values]; } return [c.key, 0]; } return [c.key, c.values]; }))); delete d.values; }); data.forEach(function(d) { var y0 = 0; d.orgs = ["A", "B", "C"].map(function(org) { if (d[org] === undefined) { return {name: org, y0: 0, y1: 0}; } else { return {name: org, y0: y0, y1: y0 += +d[org]}; } }); d.total = d3.max(d.orgs, d => { return d.y1; }); }); data.sort(function(x, y){ return d3.descending(x.total, y.total); }); return data; }; var redrawChart = function(filter) { var data = createData(filter); console.log(data); x.domain([0, d3.max(data, function(d) { return d.total; })]); y.domain(data.map(function(d) { return d.key; })); color.domain(d3.keys(data[0]).filter(function(key) { return key !== "key"; })); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + 15 + ")") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end"); ///////// //ENTER// ///////// var chartRow = svg.selectAll("g.chartRow") .data(data); var newRow = chartRow .enter() .append("g") .attr("class", "chartRow") .attr("transform", function(d) { return "translate(0, " + y(d.key) + ")"; }); var rectRow = newRow.selectAll(".bar") .data(function(d) { return d.orgs; }); rectRow .enter() .append("rect") .attr("class", function(d) { return "bar t_"+ d.name; } ) .attr("height", y.rangeBand()) .on('click', function(d){ redrawChart(d.name); }) .style("fill", function(d) { return color(d.name); }); ////////// //UPDATE// ////////// chartRow.selectAll('rect').transition() .duration(300) .attr("width", function(d) { return x(d.y1) - x(d.y0); }) .attr("x", function(d) { return x(d.y0); }) .attr("opacity",1); //////// //EXIT// //////// chartRow.exit().selectAll("rect.bar").transition() .style("opacity","0") .attr("transform", "translate(0," + (height + margin.top + margin.bottom) + ")") .remove(); }; redrawChart(); var legend = svg.selectAll(".legend") .data(color.domain().slice().reverse()); var legends = legend.enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 25 + ")"; }); legend.exit().remove(); legends.append("rect") .attr("x", width - 28) .attr("width", 18) .attr("height", 18) .style("fill", color); legends.append("text") .attr("x", width - 34) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return d; }); legends.append("text") .attr("x", width + 14) .attr("y", 9) .attr("class", "numbers") .attr("dy", ".35em") .style("text-anchor", "end"); };
When I console.log
the data
everything seems ok, so the filtering works. However, the widths of the rect
elements seem to use the OLD data set. Equally, the legends and axis are being duplicated
Fiddle here: https://jsfiddle.net/4nm44fgt/
Any insights?
1 Answers
Answers 1
Your second data bind should not use only the entering nodes, as after filtering this selection will be empty:
var rectRow = chartRow.selectAll(".bar").data(function(d) { return d.orgs; });
instead of newRow.selectAll(".bar")...
0 comments:
Post a Comment