force directed graph change color of all connected node on mouseover

江枫思渺然 提交于 2021-02-08 07:28:29

问题


I have a force directed graph with different nodes, I want to change the color of the selected node and all the connected (neighbour) nodes when user does mouseover to it.

I am trying to do this..

function onMouseover(d){
  node.style("fill", function(o){
    var color = isConnected(d, o) ? 'red' : 'blue';
    return color;
  })
  force.resume();
}

function isConnected(d, o){
  return o.index === d,index || 
         (d.children && d.children.indexOf(o.index) !== -1) ||
         (o.children && o.children.indexOf(d.index) !== -1) ||
         (o.parents && o.parents.indexOf(d.index) !== -1) ||
         (d.parents && d.parents.indexOf(o.index) !== -1);
}

Can any one please help me here, or point me to some similar d3 graph.


回答1:


Here is a demo based on Mike Bostock’s Force-Directed Graph which changes the color of the hovered node and its direct connected nodes:

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

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

var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d) { return d.id; }))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2));

d3.json("https://gist.githubusercontent.com/mbostock/4062045/raw/5916d145c8c048a6e3086915a6be464467391c62/miserables.json", function(error, graph) {
  if (error) throw error;

  var link = svg.append("g")
      .attr("class", "links")
    .selectAll("line")
    .data(graph.links)
    .enter().append("line")
      .attr("stroke-width", function(d) { return Math.sqrt(d.value); });

  var node = svg.append("g")
      .attr("class", "nodes")
    .selectAll("circle")
    .data(graph.nodes)
    .enter().append("circle")
      .attr("r", 5)
      .attr("fill", function(d) { return color(d.group); })
      .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended));

  node.append("title")
      .text(function(d) { return d.id; });

  node.on("mouseover", function(d) {

    var connectedNodeIds = graph
      .links
      .filter(x => x.source.id == d.id || x.target.id == d.id)
      .map(x => x.source.id == d.id ? x.target.id : x.source.id);

    d3.select(".nodes")
      .selectAll("circle")
      .attr("fill", function(c) {
        if (connectedNodeIds.indexOf(c.id) > -1 || c.id == d.id) return "red";
        else return color(c.group);
      });
  });

  node.on("mouseout", function(d) {
    d3.select(".nodes")
      .selectAll("circle")
      .attr("fill", function(c) { return color(c.group); });
  });

  simulation
      .nodes(graph.nodes)
      .on("tick", ticked);

  simulation.force("link")
      .links(graph.links);

  function ticked() {
    link
        .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("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
  }
});

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

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

function dragended(d) {
  if (!d3.event.active) simulation.alphaTarget(0);
  d.fx = null;
  d.fy = null;
}
.links line {
  stroke: #999;
  stroke-opacity: 0.6;
}

.nodes circle {
  stroke: #fff;
  stroke-width: 1.5px;
}
<svg width="500" height="350"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>

During the mouseover, the idea is to:

  1. Retrieve the id of the hovered node,
  2. From all links, get the ones whose either the source or the target is the id of this hovered node,
  3. From these matching links, retrieve the associated node id connected to the hovered node,
  4. Go through all nodes and change the color of those matching the previously found nodes.

this way:

node.on("mouseover", function(d) {

  var connectedNodeIds = graph
    .links
    .filter(x => x.source.id == d.id || x.target.id == d.id)
    .map(x => x.source.id == d.id ? x.target.id : x.source.id);

  d3.select(".nodes")
    .selectAll("circle")
    .attr("fill", function(c) {
      if (connectedNodeIds.indexOf(c.id) > -1 || c.id == d.id) return "red";
      else return color(c.group);
    });
});

During the mouseout, we go through all nodes and set back the original color:

node.on("mouseout", function(d) {
  d3.select(".nodes")
    .selectAll("circle")
    .attr("fill", function(c) { return color(c.group); });
});


来源:https://stackoverflow.com/questions/50175871/force-directed-graph-change-color-of-all-connected-node-on-mouseover

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!