Skip to content Skip to sidebar Skip to footer

D3 Mouse-over Of Links In Node-link Diagram, Increase 'accepted' Range

Sometimes I need to display edges in node-link diagrams with a very small stroke-width (< 3px). This makes it very hard for the user to hover over them. I'm using the .on('mouse

Solution 1:

Is there an easy way to increase the radius that would trigger the mouseover event?

No, the event handler is added to the element, and if a narrow element has a stroke width of 3px the function will only run when the mouse is over those pixels.

Is there maybe a way to set the color of the edge to something like [...] it actually has a size of 5px, but only 1px is visible?

That's possible using a path and combining a coloured fill with a transparent stroke. However, a way easier approach is just duplicating the selection, with exactly the same attributes, and making the top paths or lines (by "top" I mean the selection that comes later in the code) transparent and with a larger stroke-width.

In this demo, for instance, there are 20px-wide transparent lines, which capture the mousemove event, over the visible narrow lines:

//these lines are painted firstvar links = svg.selectAll("foo")
    .data(edges)
    .enter()
    .append("line")
    .style("stroke", "#ccc")
    .style("stroke-width", 1);

//these transparent lines are painted on top, and they capture the mousemovevar linksTransparent = svg.selectAll("foo")
    .data(edges)
    .enter()
    .append("line")
    .style("stroke", "none")
    .attr("pointer-events", "all")
    .style("stroke-width", 20)
    .on("mousemove", d => {
        console.log("source: " + d.source.id + ", target: " + d.target.id)
    });

var width = 400;
var height = 200;

var svg = d3.select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height);

var nodes = [{
  "id": "One"
}, {
  "id": "Two"
}, {
  "id": "Three"
}, {
  "id": "Four"
}];

var edges = [{
  "source": 0,
  "target": 1
}, {
  "source": 0,
  "target": 2
}, {
  "source": 0,
  "target": 3
}];

var simulation = d3.forceSimulation()
  .force("link", d3.forceLink().distance(60))
  .force("charge", d3.forceManyBody().strength(-200))
  .force("center", d3.forceCenter(width / 2, height / 2));

var links = svg.selectAll("foo")
  .data(edges)
  .enter()
  .append("line")
  .style("stroke", "#ccc")
  .style("stroke-width", 1);

var links2 = svg.selectAll("foo")
  .data(edges)
  .enter()
  .append("line")
  .style("stroke", "none")
  .attr("pointer-events", "all")
  .style("stroke-width", 20)
  .on("mousemove", d => {
    console.log("source: " + d.source.id + ", target: " + d.target.id)
  });

var color = d3.scaleOrdinal(d3.schemeCategory20);

var node = svg.selectAll("foo")
  .data(nodes)
  .enter()
  .append("g")
  .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended));

var nodeCircle = node.append("circle")
  .attr("r", 10)
  .attr("stroke", "gray")
  .attr("fill", (d, i) =>color(i));

var texts = node.append("text")
  .style("fill", "black")
  .attr("dx", 20)
  .attr("dy", 8)
  .text(function(d) {
    return d.id;
  });

simulation.nodes(nodes);
simulation.force("link")
  .links(edges);

simulation.on("tick", function() {
  links.attr("x1", function(d) {
      return d.source.x;
    })
    .attr("y1", function(d) {
      return d.source.y;
    })
    .attr("x2", function(d) {
      return d.target.x;
    })
    .attr("y2", function(d) {
      return d.target.y;
    });

  links2.attr("x1", function(d) {
      return d.source.x;
    })
    .attr("y1", function(d) {
      return d.source.y;
    })
    .attr("x2", function(d) {
      return d.target.x;
    })
    .attr("y2", function(d) {
      return d.target.y;
    });

  node.attr("transform", (d) =>"translate(" + d.x + "," + d.y + ")")

});

functiondragstarted(d) {
  if (!d3.event.active) simulation.alphaTarget(0.3).restart();
  d.fx = d.x;
  d.fy = d.y;
}

functiondragged(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;
}

functiondragended(d) {
  if (!d3.event.active) simulation.alphaTarget(0);
  d.fx = null;
  d.fy = null;
}
<scriptsrc="https://d3js.org/d3.v4.min.js"></script>

Post a Comment for "D3 Mouse-over Of Links In Node-link Diagram, Increase 'accepted' Range"