I have some pretty standard code that creates a bunch of SVG:circles based on node data and SVG:lines based on link data.
I want to put some rollover code on the circles and lines such that rolling over a circle highlights that circle, the lines that connect to it, and any other circles at the end of those lines.
The challenge I'm having is getting a reference to the link data when I'm handling an event triggered by the circle, which only has node datum attached.
d3nodes = d3svg.selectAll( ".node" )
.data( nodes )
.enter().append( "circle" )
.attr( "class", "node" )
.attr( "r", NODE_RADIUS )
.attr( "cx", function( d ){ return d.x; } )
.attr( "cy", function( d ){ return d.y; } )
.on( "mouseover", function( d ){ console.log( d ); } ); // Node datum
d3links = d3svg.selectAll( ".link" )
.data( links )
.enter().append( "line" )
.attr( "class", "link" )
.attr( "x1", function( d ){ return nodes[d.source].x; } )
.attr( "y1", function( d ){ return nodes[d.source].y; } )
.attr( "x2", function( d ){ return nodes[d.target].x; } )
.attr( "y2", function( d ){ return nodes[d.target].y; } )
.on( "mouseover", function( d ){ console.log( d ); } ); // Link datum
Once I have a reference to links, I can use the following function to get a list of links where that node is either a source or a target:
/**
* Gets up to 4 nodes, that represent all the nodes linked to this node
* (either as targets or source).
*
* @param {Object} node Object from the "nodes" array (so, the data, not the d3nodes)
* @param {Object[]} links Array of links (again, the data that was passed to the force layout)
* @returns {Array} Matching node objects (again, not DOM elements)
*/
function getLinks( node, links ){
var nodes = [],
i = 0, l = links.length,
link;
for ( ; i < l; ++i ){
link = links[i];
if ( link.target === node ){
nodes.push( link.source );
continue;
}
if ( link.source === node ){
nodes.push( link.target );
}
}
return nodes;
}
But my function really needs a reference to the links array, and I'm not sure how to get it from within an event handler that only seems to get the node datum.
I'd like to avoid any kind of global variables, or a global lookup table, since I'm going to have any number of these graphs on a page, and they all need to stay separate.
In the past I've stored a reference to the nodes, links and force objects on the DOM element itself (using jQuery.data()), but is that really a best practice?
I feel like I'm missing an important conceptual point, and hope someone can shed some light.