4

I am creating a div container which I then fill with a svg

var someContainer = d3.select("#abc")
        .append("div")
        .classed("svg-container", true)
        .append("svg")
        .attr("preserveAspectRatio", "xMinYMin meet")
        .attr("viewBox","0 0 400 100")
        .classed("svg-content-responsive", true) 
        .selectAll("circle")
        .data(someScale.range());

I then append my data to it

someContainer.remove();

someContainer.enter()
        .append("circle")
        .attr("x", function (d, i) { 
            return i * 2;
        })
        .attr("y", 5)
        .attr("height", 15)
        ....;

However, whenever I update the content of the svg, i.e. append new circles, a completely new div-container and svg-container gets created. That leaves me with the old data visually staying in its place and right on the bottom (meaning, 100px further down) there is the new data. Its basically a visual copy, but with the new data... Whenever I udpate my data, a new coy gets replaced under the old one, leaving me with n graphics.

Here is the css that styles the relative container and makes sure, it scales when the window size is changed. Source: Resize svg when window is resized in d3.js */

.svg-container {
    display: inline-block;
    position: relative;
    width: 100%;
    padding-bottom: 50%; /* aspect ratio */
    vertical-align: top;
    overflow: hidden;
}

.svg-content-responsive {
    display: inline-block;
    position: absolute;
    top: 10px;
    left: 0;
}

Any ideas what I am doing wrong?

Community
  • 1
  • 1
four-eyes
  • 10,740
  • 29
  • 111
  • 220

2 Answers2

2

If you just need to delete all the old circles you can do it as follows:

someContainer.selectAll("circle").remove()

And then add new circles by data -> enter -> append sequence.

 someContainer.selectAll("circle")
        .data(new_circle_data)
        .enter()
        .append("circle")
        .attr("x", function (d, i) { 
            return i * 2;
        })
        .attr("y", 5)
        .attr("height", 15)
        ....;

If you only want to delete some of the existing circles and keep the others you can use the general update pattern. You need to do something like this:

var circleUpdate = someContainer.selectAll("circle")
   .data(new_circle_data)

circleUpdate.enter().append("circle")
    .attr("x", function (d, i) { 
            return i * 2;
        })
    .attr("y", 5)
    .attr("height", 15)
    ....;

circleUpdate.exit().remove()
Tormi Reinson
  • 555
  • 3
  • 11
  • Nope, that does not do the trick. The stuff still gets duplicated. I think the problem is that every time a new **div** is created... When I use the element Inspector I can see that there is a new div container every time I update the data.. – four-eyes Aug 23 '16 at 07:38
  • Create SVG only once when you initialize the plot. Call an update function when you interact with the plot to change it. This update function can contain only the code blocks that I provided, it should be enough to update the circles. – Tormi Reinson Aug 23 '16 at 08:02
2

The problem is that each time the data gets updated, a new div gets created.

var someContainer = d3.select("#abc")
    .append("div")
    .classed("svg-container", true)
    ...

In order to update the data, the div needs to be replaced instead of creating a new div each time the data changes. That can be done by adding this line

d3.select(".svg-container").remove();

above the var someContainer = d3.select...

four-eyes
  • 10,740
  • 29
  • 111
  • 220