'How can I select :last-child in d3.js?
I need to manipulate the text
elements of the first and last tick of an axis to bring them more towards the center.
I am trying to select them, one at the time, with something like svg.select('.tick:last-child text')
but it doesn't work. I'd then apply .transform('translate(4,0)')
...
Am I doing something wrong? How can I achieve this?
Solution 1:[1]
One thing you could do is to create custom sub-selections by adding methods to d3.selection.prototype
. You could create a selection.first()
method that selects the first item in a selection, and a selection.last()
method that selects the last item. For instance:
d3.selection.prototype.first = function() {
return d3.select(this[0][0]);
};
d3.selection.prototype.last = function() {
var last = this.size() - 1;
return d3.select(this[0][last]);
};
This would let you do the following:
var tickLabels = svg.selectAll('.tick text');
tickLabels.first()
.attr('transform','translate(4,0)');
tickLabels.last()
.attr('transform','translate(-4,0)');
Of course, you need to make sure that you only have one axis if you do it that way. Otherwise, specify the axis in your initial selection:
var tickLabels = svg.selectAll('.axis.x .tick text');
HERE is an example.
Solution 2:[2]
Here's the cleanest method I've found:
g.selectAll(".tick:first-of-type text").remove();
g.selectAll(".tick:last-of-type text").remove();
Solution 3:[3]
As google brought me here, I also want to add a cleaner method to what Adam Grey wrote. Sometimes you just want to do it without taking a reference of selectAll .
svg.selectAll('.gridlines').filter(function(d, i,list) {
return i === list.length - 1;
}).attr('display', 'none');
the 3rd parameter of the filter function gives you the selected List of elements.
Solution 4:[4]
They don't exist in d3 specifically, but you can use the .firstChild
and .lastChild
methods on a node.
You can first select all of the parents of the node, and then operate within the scope of a .each()
method, like so:
d3.selectAll('.myParentElements').each(function(d,i){
var firstChild = this.firstChild,
lastChild = this.lastChild;
//Do stuff with first and last child
});
Within the scope of .each()
, this
refers to the individual node, which is not wrapped by a d3 selection, so all of the standard methods on a node are available.
Solution 5:[5]
Using .filter()
with a function also works selection.filter(filter) :
var gridlines;
gridlines = svg.selectAll('.gridlines');
gridlines.filter(function(d, i) {
return i === gridlines.size() - 1;
}).attr('display', 'none');
Solution 6:[6]
It's for D3.js v4
d3.selection.prototype.first = function() {
return d3.select(
this.nodes()[0]
);
};
d3.selection.prototype.last = function() {
return d3.select(
this.nodes()[this.size() - 1]
);
};
Example:
var lines = svg.selectAll('line');
lines.first()
.attr('transform','translate(4,0)');
lines.last()
.attr('transform','translate(-4,0)');
Solution 7:[7]
Here is another, even though I used Fered's solution for a problem I met.
d3.select(d3.selectAll('*').nodes().reverse()[0])
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | jshanley |
Solution 2 | emilyinamillion |
Solution 3 | Fered |
Solution 4 | ckersch |
Solution 5 | Adam Grey |
Solution 6 | vampire |
Solution 7 | Anton vBR |