d3.js reusable pie chart with dynamic updates

2020-06-24 05:16发布

问题:

I'm trying to create a reusable pie chart with dynamic transitions as a learning task. I'm working off of the d3.js resuable components e-book by Chris Viau. The problem I'm having is basically its not updating, but creating multiple pie charts. I'm wondering if I'm not understanding how d3.dispatch works or whether I've messed something up in the way the pie char should work. It creates multiple circles instead of dynamically updating a single pie chart with random values.

here is my jsfiddle.

http://jsfiddle.net/seoulbrother/Upcr5/

thanks!

js code below:

d3.edge = {};

d3.edge.donut = function module() {

    var width = 460,
        height = 300,
        radius = Math.min(width, height) / 2;

    var color = d3.scale.category20();


   var dispatch = d3.dispatch("customHover");
   function graph(_selection) {
       _selection.each(function(_data) {    
            var pie = d3.layout.pie()
                .value(function(_data) { return _data; })
                .sort(null);

            var arc = d3.svg.arc()
                .innerRadius(radius - 100)
                .outerRadius(radius - 50);

            if (!svg){
                var svg = d3.select(this).append("svg")
                    .attr("width", width)
                    .attr("height", height)
                    .append("g")
                    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
            }
            var path = svg.selectAll("path")
                .data(pie)
              .enter().append("path")
                .attr("fill", function(d, i) { return color(i); })
                .attr("d", arc)
                .each(function(d) {this._current = d;} );

            path.transition()
                  .ease("elastic")
                  .duration(750)
                  .attrTween("d", arcTween);              

            function arcTween(a) {
              var i = d3.interpolate(this._current, a);
              this._current = i(0);
              return function(t) {
                return arc(i(t));
              };
            }
        });

    }
    d3.rebind(graph, dispatch, "on");
    return graph;
}

donut = d3.edge.donut();
var data = [1, 2, 3, 4];
var container = d3.select("#viz").datum(data).call(donut);

function update(_data) {
    data = d3.range(~~(Math.random() * 20)).map(function(d, i) {
        return ~~(Math.random() * 100);
    });
    container.datum(data).transition().ease("linear").call(donut);
}

update();
setTimeout( update, 1000);

回答1:

The main reason for multiple SVGs appearing is that you're not checking if there is one already correctly. You're relying on the variable svg being defined, but define it only after checking whether it is defined.

The better way is to select the element you're looking for and check whether that selection is empty:

var svg = d3.select(this).select("svg > g");
if (svg.empty()){ // etc

In addition, you need to handle the update and exit selections in your code in addition to the enter selection. Complete jsfiddle here.



标签: d3.js