I am working on
this force graph in D3 v4.
When a user click on a nodes, only the nodes connected to it become visible. Moreover, the edges connecting those nodes become thicker and users can hover on the so see more information (the tooltip that appears on the right).
This is how I highlight the connected nodes after a click
//Highlight on click
function highlighting () {
//Toggle stores whether the highlighting is on
var node = d3.selectAll('circle');
var link = d3.selectAll('line');
var toggle = 0;
//Create an array logging what is connected to what
var linkedByIndex = {};
for (i = 0; i < dataset.nodes.length; i++) {
linkedByIndex[i + "," + i] = 1;
};
d3.selectAll('line').each(function (d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
//This function looks up whether a pair are neighbours
function neighboring(a, b) {
return linkedByIndex[a.index + "," + b.index];
}
function connectedNodes() {
if (toggle == 0) {
//Reduce the opacity of all but the neighbouring nodes
d = d3.select(this).node().__data__;
node.style("opacity", function (o) {
return neighboring(d, o) | neighboring(o, d) ? 1 : 0.0;
});
link.style("opacity", function (o) {
return d.index==o.source.index | d.index==o.target.index ? 1 : 0.0;
});
link.attr('stroke-width' , 4);
toggle = 1;
interactivityHighlight();
//Change navigation div
d3.select('#click01').classed('hidden', true);
d3.select('#click02').classed('hidden', false);
} else {
//Put them back to starting opacity
node.style("opacity", 1);
link.style("opacity", function (d) {return edgeOpacityScale(d.collaborations);});
link.attr('stroke-width', 1);
link.attr('class', null);
toggle = 0;
//Change navigation
d3.select('#click01').classed('hidden', false);
d3.select('#click02').classed('hidden', true);
}
}
node.on('click', connectedNodes);
}
And this is the function I call after the click
function interactivityHighlight () {
graph.selectAll('line').on('mouseover', function (d) {
if (d3.select(this).style('opacity') == 1) {
d3.select(this)
.attr('stroke', 'red')
.attr('stroke-width', 6);
d3.select('#tooltip')
.classed('hidden', false);
d3.select('#tooltip')
.append('p')
.attr('id', 'org_names')
.text('Collaborations between ' + d.source.name + ' and ' + d.target.name);
d3.select('#tooltip')
.append('p')
.attr('id', 'collaborations')
.text('Worked together on ' + d.collaborations + ' projects');
d3.select('#tooltip')
.append('p')
.attr('id', 'collBudget')
.text('Total budget: '+ commafy(d.collBudget));
}})
graph.selectAll('line').on('mouseout', function (d) {
if (d3.select(this).style('opacity') == 1) {
d3.select(this)
.attr('stroke', 'black')
.attr('stroke-width', 4);
d3.select('#tooltip')
.selectAll('p')
.remove();
d3.select('#tooltip')
.classed('hidden', true);
}})
}
Basically all non-connected nodes get `opacity=0` and thus become invisible. However, they are still present on the graph: hovering over a line may not trigger `interactivityHighlight()` because the mouse is actually hovering over an invisible edge.
Is there a way I can make the invisible edges really disappear, or make the visible ones "get on top" of all the others?