9

I have various SVG <g> objects, each with a <circle> child and a <text> child. I can use select() to find a particular <text> object, by the class attached to it, and then modify it:

d3.select('text.my-class')
    .classed("my-class",false).classed("new-class",true)
    .text("Next Stage!")
    ;

Now I need to modify it's circle sibling. The circle has no particular identifying class (hhmmm... perhaps giving it one would be the d3 way of doing this?), so my first try was jQuery-like:

d3.select('text.my-class').parent().select('circle')
    .attr('style','fill:#f00;')
    ;

That fails with "parent is not a function".

The answer to a similar question ( How to select parent element of current element in d3.js ) suggested this.parentNode, but either I'm using it wrong or it does not work here. I've tried both of these:

d3.select('text.my-class').select(parentNode).select('circle')
d3.select('text.my-class').select(this.parentNode).select('circle')
Community
  • 1
  • 1
Darren Cook
  • 27,837
  • 13
  • 117
  • 217

2 Answers2

13

D3 don't have a method to access parent nodes. You can access the DOM node of a selected element using the node() method. This element will have the parentNode attribute:

var textNode = d3.select('text.my-class').node(),  // DOM node
    parentNode = textNode.parentNode,              // Parent DOM node
    parentSelection = d3.select(parentNode),       // Selection containing the parent DOM node
    circle = parentSelection.select('circle');     // selection containing a circle under the parent selection

In a callback, you can use:

d3.select('text.my-class')
   .on('mouseover', function(d) {
      // The 'this' context is set to the DOM element, not the selection
      var circle = d3.select(this.parentNode).select('circle');
      circle.attr('fill', 'red');
   });

Regards,

Pablo Navarro
  • 8,244
  • 2
  • 43
  • 52
  • 1
    Thanks! I used `var textNode = d3.select('text.my-class');` and then `d3.select(textNode.node().parentNode).select('circle').attr('style','fill:#f00;')` and it appears to be working so far. :-) – Darren Cook Mar 25 '14 at 13:09
4

You can use:

selection.select(function() { return this.parentNode; });

You can also just add your own .parent() method to d3.selection.prototype:

d3.selection.prototype.parent = function() {
    return this.select(function() { return this.parentNode; });
};

// example!
d3.selectAll(".child").parent().each(function() {
  console.log(this.className);
});

demo on jsbin

gnarf
  • 105,192
  • 25
  • 127
  • 161