简体   繁体   中英

Appending elements to d3 selection

In a d3 program, I have a many circle elements with data bound to them. In a callback to an event, I want to filter out most of them and place a larger red circle on top of those that are left. It looks something like this:

svg.selectAll("circle")
  .filter(/* filter function not important */)
  .append("circle")
  .attr("class", "extra")
  .attr("cx", function(){return d3.select(this).attr("cx")})
  .attr("cy", function(){return d3.select(this).attr("cy")})
  .attr("r", 5);

And the result is this (the first line is the original circle):

<circle cx="55.41208075590415" cy="279.3650793650794" r="1">
  <circle class="extra" r="5"></circle>
</circle>

So I have two problems. One, it's inserting as a child of the old element, rather than a sibling. Ideally it would be inserted as the last child of svg . Second, cx and cy aren't getting copied over. What magic do I have to utter to make this work?


If you are okay overwriting existing elements, see the answer below. To create new ones, here's how.

svg.selectAll("circle")
  .filter(/* filter function not important */)
  .each(function(d){
      svg.append("circle")
         .attr("class", "extra")
         .attr("cx", function() { return x(d.fop) })
         .attr("cy", function() { return y(d.bar) })
         .attr("r", 5);
   })

Notice two things. One, the inner functions do not take parameters, because there is no data bound to the extra circle. Use the d from the existing circle instead. Two, I couldn't figure out how to access the cx and cy of the existing circle, so I had to recompute them instead, which means the scales x and y must remain unchanged. I'll change the accepted answer if anyone can improve on this.

Instead of doing a .append on your selection you should simply use your filter function to modify the circles whose data have the criterion that pass your filter function. You can modify those circles, instead of appending a new element. So your code would look something like this.

svg.selectAll('circle')
    .filter(/** what you want**/)
    .attr('r', newRadiusSize)
    .attr('fill', 'red')

You could even add a nice transition to make the circles change to red instead of just snapping to the newer bigger circles.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM