Updating D3 chart resulting in duplicate charts

删除回忆录丶 提交于 2019-12-04 17:32:34

To handle creation and updates, you will have to reorganize how the draw function is written.

function draw(json) {

   // Initialization (few wasted CPU cycles)
   // ...

   // Update hook
   var svg = d3.select("#chartSet").data([data]);

   // Enter hook
   var svgEnter = svg.enter();

   // Enter cycle
   svgEnter.append("svg")
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // Update cycle
    svg
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom);

    // Exit cycle (not really needed here)
    svg.exit().remove();

    // Update hook
    var bar = svg.selectAll(".bar")
        .data(data)

    // Enter hook
    var barEnter = bar.enter();

    // Enter cycle
    var barG_Enter = barEnter
                        .append("g")
                        .attr("class", "bar")
    barG_Enter
        .append("rect")
        .attr("x", 1);

    barG_Enter
        .append("text")
        .attr("dy", ".75em")
        .attr("y", 6)
        .attr("text-anchor", "middle");

    // Update cycle
    bar.attr("transform", function(d) { 
        return "translate(" + x(d.x) + "," + y(d.y) + ")"; });

    bar.select("rect")
        .attr("width", x(data[0].dx) - 1)
        .attr("height", function(d) { return height - y(d.y); });

    bar.select("text")
        .attr("x", x(data[0].dx) / 2)
        .text(function(d) { return formatCount(d.y); });

    // Exit cycle
    bar.exit().remove();

    // Enter cycle
    svgEnter.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    // Update cycle
    svg.select('g.x.axis')
        .call(xAxis);
}

This classical enter-update-exit pattern is improved upon in this article on making reusable graphs. This answer draws heavily on that pattern.

With a slightly better implementation which uses closures, you will be able to save the few CPU cycles wasted on initialization each time.

You can either create the SVG outside the function that you call when the button is clicked, or check whether it exists and only add it if it does not exist. That is, something like

var svg = d3.select("svg");
if(svg.empty()) {
    // code for appending svg
}

The same thing applies to the block of code at the end of your function that appends the x axis. For the bars, all you need to do is handle the update and exit selections in addition to the enter selection, i.e. set the dimensions and potentially remove elements based on the new data.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!