D3.js : Removing dynamically added Pie Chart slice

2020-07-27 18:58发布

问题:

I am able to generate pie chart and add data to it dynamically, based on user interaction.

Here is the fiddle http://jsfiddle.net/L5Q8r/

The problem I am facing is during the data removal from pie-chart. When the checkbox is unchecked, I am deleting the data from "dataset" and updating the chart.

The chart is getting updated but the previous "slice of pie" is still visible to user.

I tried adding the ".exit().remove()" but no success. Here is what I did:

var updateChart = function (dataset) {
        arcs.data(pie(dataset))
            .enter()
                .append("path")
                .attr("stroke", "white")
                .attr("stroke-width", 0.8)
                .attr("fill", function (d, i) {
                    return color(i);
                })
                .attr("d", arc);

            arcs.data(pie(dataset)).exit().remove(); // Executing but not working

        arcs.transition()
            .duration(duration)
            .attrTween("d", arcTween);          

        sliceLabel.data(pie(dataset));

        sliceLabel.transition()
            .duration(duration)
            .attr("transform", function (d) {
                return "translate(" + (arc.centroid(d)) + ")";
            })
            .style("fill-opacity", function (d) {
                if (d.value === 0) {
                    return 1e-6;
                } else {
                    return 1;
                }
            });

        sliceLabel.data(pie(dataset))
            .enter()
                .append("text")
                .attr("class", "arcLabel")
                .attr("transform", function (d) {
                    return "translate(" + (arc.centroid(d)) + ")";
                })
                .attr("text-anchor", "middle")
                .style("fill-opacity", function (d) {
                    if (d.value === 0) {
                        return 1e-6;
                    } else {
                        return 1;
                    }
                })
                .text(function (d) {
                    return d.data.Population;
                });
        sliceLabel.data(pie(dataset)).exit().remove();//executing but not working       
    };

Any help would be appreciated. TIA.

回答1:

There are two things here. First, you are binding the data twice:

arcs.data(pie(dataset))
// ...
arcs.data(pie(dataset)).exit()...

This second time will pick up the arcs you've just added before, which is not what you want. Do the data binding once and save the result in a variable:

var sel = arcs.data(pie(dataset));
sel.enter()...
sel.exit()...

Which brings me to the second thing. You weren't saving the updated selections anywhere, resulting in problems later on. Calling .data() on a selection does modify the underlying data, but does not update the selection. That is, arcs refers to the same elements both before and after calling .data(), regardless of what you do with .enter() etc.

I've fixed both of these issues here. For the latter, I'm explicitly reselecting the elements that the data should be bound to (e.g. arc_grp.selectAll("path")). There are other ways of doing this, but this one makes explicit what you're working with.