0
votes

I am using the dimple js library to draw a stacked area chart. I want to update the data based on user input.

I have a working example, that visually looks correct, however on each update, there are more elements being added to the svg, so that after a few updates of the chart the script visibly slows down.

Below is an example script illustrating the problem. It is adapted from an answer related to updating a dimple bar chart: Update dimple.js chart when select a new option

Example:

<div id="chartContainer"></div>      
<button id="btn">Click Me</button>    

<script type="text/javascript">

    var svg = dimple.newSvg("#chartContainer", 590, 400);
    var data = [
        { Animal: "Cats", Series: "1", Value: (Math.random() * 1000000) },
        { Animal: "Dogs", Series: "1", Value: (Math.random() * 1000000) },
        { Animal: "Mice", Series: "1", Value: (Math.random() * 1000000) },
        { Animal: "Cats", Series: "2", Value: (Math.random() * 1000000) },
        { Animal: "Dogs", Series: "2", Value: (Math.random() * 1000000) },
        { Animal: "Mice", Series: "2", Value: (Math.random() * 1000000) },
        { Animal: "Cats", Series: "3", Value: (Math.random() * 1000000) },
        { Animal: "Dogs", Series: "3", Value: (Math.random() * 1000000) },
        { Animal: "Mice", Series: "3", Value: (Math.random() * 1000000) }
    ];

    var myChart = new dimple.chart(svg, data);
    myChart.setBounds(60, 30, 510, 305)

    var x = myChart.addCategoryAxis("x", "Animal"); 
    x.addOrderRule(["Cats", "Dogs", "Mice"]);

    myChart.addMeasureAxis("y", "Value");
    myChart.addSeries("Series", dimple.plot.area);
    myChart.draw();

    d3.select("#btn").on("click", function() {
        myChart.data = [
            { Animal: "Cats", Series: "1", Value: (Math.random() * 1000000) },
            { Animal: "Dogs", Series: "1", Value: (Math.random() * 1000000) },
            { Animal: "Mice", Series: "1", Value: (Math.random() * 1000000) },
            { Animal: "Cats", Series: "2", Value: (Math.random() * 1000000) },
            { Animal: "Dogs", Series: "2", Value: (Math.random() * 1000000) },
            { Animal: "Mice", Series: "2", Value: (Math.random() * 1000000) },
            { Animal: "Cats", Series: "3", Value: (Math.random() * 1000000) },
            { Animal: "Dogs", Series: "3", Value: (Math.random() * 1000000) },
            { Animal: "Mice", Series: "3", Value: (Math.random() * 1000000) }
        ];
        myChart.draw(1000);
    });

</script>

How can I update an area chart like this cleanly, such that any previous data is removed? (I could destroy the svg and redraw, but this would lose the animated effect)

Thanks

UPDATE:

I have found a partial solution. Each time the chart is updated, a series of non-visible markers are added at each data point, but are not removed. You can manually remove them using

d3.selectAll(".dimple-custom-line-marker").remove();

This is placed before .draw():

d3.select("#btn").on("click", function() {
    myChart.data = [
        { Animal: "Cats", Series: "1", Value: (Math.random() * 1000000) },
        { Animal: "Dogs", Series: "1", Value: (Math.random() * 1000000) },
        { Animal: "Mice", Series: "1", Value: (Math.random() * 1000000) },
        { Animal: "Cats", Series: "2", Value: (Math.random() * 1000000) },
        { Animal: "Dogs", Series: "2", Value: (Math.random() * 1000000) },
        { Animal: "Mice", Series: "2", Value: (Math.random() * 1000000) },
        { Animal: "Cats", Series: "3", Value: (Math.random() * 1000000) },
        { Animal: "Dogs", Series: "3", Value: (Math.random() * 1000000) },
        { Animal: "Mice", Series: "3", Value: (Math.random() * 1000000) }
    ];

    d3.selectAll(".dimple-custom-line-marker").remove();

    myChart.draw(1000);
});

(NB: you might need ".dimple-marker" rather than ".dimple-custom-line-marker" if the area chart just has one series)

This works fine in Firefox, but sometimes in Chrome or safari the chart freezes. The error message in the console reads:

TypeError: Cannot read property 'key' of undefined
     at SVGCircleElement.<anonymous> (https://www.../js/dimple.v2.3.0.min.js:2:16003)
     ....
1

1 Answers

0
votes

Did not work well for me. I found this worked much better. Place it just before the myChart.draw(xxxx);. It is best to have a faster draw like 400ms for this to look clean.

svg.selectAll(".dimple-marker,.dimple-marker-back").remove();