Using D3 2.4.2, I create a number of path elements like so:
for (var i = 0; i < pathIndices.length; i++) {
graph.append("svg:path")
.style("stroke", colors[pathIndices[i]])
.style("stroke-width", "2.5px")
.style("fill", "none")
.attr("class", PATH_CLASS)
.attr("id", PATH_ID_PREFIX + pathIndices[i])
.attr("d", lineFunc(data))[0];
}
They all draw to the screen as expected. Later on, I want to bring one of them to the front when the user makes some input, so I have an event handler that does this:
var pathToHighlight = selectPath(pathIndex);
var paths = d3.selectAll("." + PATH_CLASS);
paths.sort(
function(a, b) {
if (a === pathToHighlight) {
return -1;
}
else if (b === pathToHighlight) {
return 1;
}
else {
return 0;
}
}
);
Setting breakpoints in Chrome indicates that my path selections here are successful (paths
is an array of SVGPathElements). But the code does nothing, and setting breakpoints inside the sort function shows that a
and b
are always undefined. Going up into the d3 code, I see that when the internal function d3_selection_sortComparator
calls my comparator with the appropriate arguments, except they're ANDed with their own undefined __data__
members, which causes undefined
to be passed in:
// a and b are correct, but a.__data__ and b.__data__ are undefined
return comparator(a && a.__data__, b && b.__data__);
What am I doing wrong here? My paths draw correctly to the screen, so it seems like they should have the correct data. Right?
Edit: Images:
You're using selection.sort
when it sounds like you're expecting Array.sort
. The selection.sort
method is used for sorting a selection based on the data bound to elements a
and b
. If your elements don't have data bound to them, then this won't work. If you want to sort a selection based on something else (like testing that one element reference is equal to another), you should grab the array of elements from the selection before calling .sort()
like so:
// `paths` is a Selection
var paths = d3.selectAll("." + PATH_CLASS);
// `pathElements` is an Array
var pathElements = paths[0];
pathElements.sort(function(a,b) {
// now `a` and `b` are Element references
// ...
})
Then you would have to take the extra step of matching the DOM order to the order of the resulting array.
That said, if you just want to bring pathToHighlight
to the front, a better way to approach this is just to re-append that single element to the DOM.
If pathToHighlight
is a selection you would do this:
var el = pathToHighlight.node();
el.parentNode.appendChild(el);
or, if it's already an Element reference, you can just do:
pathToHighlight.parentNode.appendChild(pathToHighlight);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With