Tom MacInnes
Tom MacInnes

Reputation: 81

Selecting SVGs in D3

I've got a little visualisation going where I have pairs of rectangles. Each pair shares the same id attribute. So currently, I've set it up so that if I hover over either one, both change colour. That's great, but, as I've done it, I need a new select("svg #whatever) command for each different pair. That can't be right.

So what I was thinking was setting up a variable, which would be the id of the element I was mousing over, then putting that inthe selct command, something like this

    svg.selectAll("rect")
.on("mouseover", function(d) {

var thisid = d3.select(this).attr("id")

     svg.selectAll("svg #"+thisid+)             
    .attr("fill", "red")

Except that doesn't work. Is it just the syntax - ie I've got the + + wrong - or am I making a fundamental mistake here?

Upvotes: 0

Views: 560

Answers (1)

AmeliaBR
AmeliaBR

Reputation: 27544

Your idea is good, but as Robert Longson pointed out, you can't use id to link two related objects, since id has to be unique for the entire webpage.

You can, however, add any attribute you want to your data element (other than id) and preferably with an attribute name that starts "data-", and then use a CSS attribute selector to find other elements with the same attribute. Like this:

//when you create the rectangles:
rect.attr("data-id", function(d) { 
                   return d.id;/* or however you figure out this id */
           });


//Your event handler
svg.selectAll("rect")
  .on("mouseover", function(d) {

      var thisid = d3.select(this).attr("data-id")

      svg.selectAll("svg rect[data-id='" + thisid + "']")
                 //note the single quotes inside double quotes 
                 //the final selector should look like "svg rect[data-id='23']" 
            .attr("fill", "red");

     });

The only downside it that browsers don't index all attributes for fast access like they do with classnames and ids, so it could be slow if you had a large number of rectangles and mouse-over them rapidly. Using a class would make selection faster, but adds a complication if you have multiple classes -- you can't just access the one class value you're interested in by calling .attr("class"). You could, however, re-access whichever data variable you are using to define data-id in the first place. Like this:

//when you create the rectangles:
rect.attr("data-id", function(d) { 
                   return "data-rectangle " + /* any other classes you are adding, + */
                        "data-id-" + d.id;/* or however you figure out this id */
           });


//Your event handler
svg.selectAll("rect")
  .on("mouseover", function(d) {

      var thisid = d.id; /* or however you figure out this id */
         //d3 automatically passed the element's data object to your event handler

      svg.selectAll("svg rect.data-id-" + thisid)
                 //the final selector should look like "svg rect.data-id-23" 
            .attr("fill", "red");

     });

Upvotes: 1

Related Questions