I want to remove the bar that is clicked, but for some reason it is always removing the last bar instead. I think the answer may be in the following article (http://pothibo.com/2013/09/d3-js-how-to-handle-dynamic-json-data/), but I'm not sure if manually assigning a key to each element is necessary. I have spent hours trying to get this to work, so I'm hoping someone can point me in the right direction. Thanks in advance.
<html>
<head>
<title>Interactive Div-based Bar Chart</title>
<style type="text/css">
.chart rect {
fill: teal;
}
.chart text {
fill: white;
font: 30px sans-serif;
text-anchor: end;
}
</style>
<script src="Scripts/d3.min.js"></script>
</head>
<body>
<div id="data-field"></div>
<button id="add-btn">Add Data</button>
<p>Click on a bar to remove it</p>
<script>
var barHeight = 75, margin = 3, padding = 3;
var chartData = [6,12,15,21,29,41];
var chart = d3.select("body").append("svg").attr("class","chart");
drawChart();
function drawChart() {
var selection = chart.selectAll("g")
.data(chartData);
// Remove extra bars
selection.exit()
.remove();
// Add more bars
var groups = selection.enter()
.append("g");
var bars = groups
.append("rect");
var labels = groups
.append("text");
// Update existing bars
groups
.attr("transform", function (d, i) { return "translate(0," + i * (barHeight + margin) + ")"; })
.on("click", function (d, i) { chartData.splice(i, 1); drawChart(); });
bars
.attr("width", function (d) { return d * 10 + "px"; })
.attr("height", barHeight);
labels
.attr("x", function (d) { return d * 10 - padding + "px"; })
.attr("y", barHeight / 3 + padding + "px")
.text(function (d) { return d; });
// update list of numbers
d3.select("#data-field").text("numbers: [" + chartData.join(", ") + "]");
}
// add more data
d3.select("#add-btn")
.on("click", function(d) { chartData.push(Math.round(Math.random() * 100)); drawChart(); });
</script>
</body>
</html>
Here are the changes you need to make, with comments:
And here is the FIDDLE.
IMPORTANT EDIT:
After @loucatsfan asked me why not simply getting rid of
selection.exit().remove();
since it made no difference, I realized the importance of making my answer more idiomatic. So, I created an updated fiddle that leverages theexit
selection and removes the need to manually delete the DOM element.Also, and just as important, there are some subtle differences between handling updates for grouped vs. non-grouped elements (use of
select
vs.selectAll
). So, I revised the code to more appropriately handle grouped elements.You can find more info on the proper handling of grouped elements here and here. But here is the promised improvement:
UPDATED FIDDLE.
Check my solution here: http://fiddle.jshell.net/sydvpsfp/
Major problem was that you were not deleting all the old bars at the begining of drawChart function. I had added this: