0

I'm binding data to a bunch of nodes using d3, and I would like to arrange it so that all of the nodes change dynamically when one of them is clicked on (or some other event). Based on my understanding of d3, I think it should work like this:

var nodes = svg.selectAll(".node")
    .data(someData)
    .enter()
    .append("circle") 
    .attr("r", 5)
    .attr("class", ".node")
    .style("fill", "blue")
    .on("click", function(d, i) {
        svg.selectAll(".node").style("fill", function(e, j) {
            if(someCondition(i, j))
                return "red";
            else
                return "green";
        });
    });

But nothing happens when I click. Even the simpler code:

var nodes = svg.selectAll(".node")
    .data(someData)
    .enter()
    .append("circle") 
    .attr("r", 5)
    .attr("class", ".node")
    .style("fill", "blue")
    .on("click", function(d, i) {
        svg.selectAll(".node").style("fill", "red");
    });

(which I expect would turn all of the nodes red when one of them is clicked on) does not work.

altocumulus
  • 21,179
  • 13
  • 61
  • 84
Paul Siegel
  • 1,401
  • 13
  • 36

2 Answers2

3

There is an error in the way you are setting the class names for your circles by calling

.attr("class", ".node")

Doing it this way would set the attribute to class=".node" which is certainly not what you want. Moreover, this would not be a valid class name. See this answer for an explanation of what characters are allowed to form a class name. To select this class name you would have to do a svg.selectAll("..node") having two dots in your selector string.

Having said that, change you code to leave out the dot to make it work:

.attr("class", "node")

Lessons learned:

  1. .attr() takes the attribute's value literally.

  2. When applying a CSS selector, you prefix it with a dot to select a class name.

Community
  • 1
  • 1
altocumulus
  • 21,179
  • 13
  • 61
  • 84
-1

You need specify the "cx" and "cy" properties of a circle, otherwise you wont see anything.

var nodes = svg.selectAll(".node")
    .data(someData)
    .enter()
    .append("circle") 
    .attr("r", 5)
    //add cx and cy here: 
    .attr("cx", function(d) {return d+10;/*just an example*/})
    .attr("cy", function(d) {return 2*d+10;/*just an example*/})
    .attr("class", "node")
    .style("fill", "blue")
    .on("click", function(d, i) {
        svg.selectAll(".node").style("fill", "red");
    });
derek
  • 9,358
  • 11
  • 53
  • 94
  • That's not correct. Both values will default to `0`, thus drawing a circle around the origin (0,0). I've done this myself to make calculations more easy and translate the circle later on. – altocumulus Oct 29 '15 at 17:35
  • I wrote my own code that work correctly. But I did not even notice it is actually caused by attribute "class". I should have post my code here instead simply copy your code. – derek Oct 29 '15 at 18:01
  • My question was not about how to properly display the nodes in the first place - that is dealt with elsewhere in my project anyway. I wanted to provide enough context for handling a "click" event to make sense without cluttering the question with irrelevant details. – Paul Siegel Oct 29 '15 at 18:01