ItayB
ItayB

Reputation: 11337

Get a node by its ID

I'm using d3.js to create graph with mNode as nodes and mLink as links. In the following code, otherLink has source & target fields which refers to the nodes connected to this link. otherLink.source is just an object with the node data, for example:

{"id": 1,
 "index: 0,
 ...
}

How do apply style on this node (look at the // DOESN'T WORK line below:

function Graph(elementId) {
  var svg;
  var simulation;
  var mNodesData = [];
  var mEdgesData = [];
  var mNode = null;
  var mLink = null;
  var elementId;
  var heightDelta = 100;
  var width = window.innerWidth;
  var height = window.innerHeight - heightDelta;

  return {
      init: function () {
          svg = d3.select('#' + elementId)
              .append("svg")
              .attr("width", width)
              .attr("height", height);

          simulation = d3.forceSimulation()
              .force(".edge", d3.forceLink())
              .force("charge", d3.forceManyBody().strength(-600))
              .force("center", d3.forceCenter(width / 2, height / 2));

          mLink = svg.selectAll(".edge")
              .attr("class", "edge")
              .style("stroke", LINK_DEFAULT_COLOR)
              .style("stroke-width", function (e) {
                  return 1
                  /* e.width*/
              });

          mNode = svg.selectAll(".node")
              .attr("class", "node");
      },
      draw: function () {
          mLink = svg.selectAll(".edge")
              .data(mEdgesData)
              .enter()
              .append("line")
              .attr("class", "edge")
              .style("stroke", LINK_DEFAULT_COLOR)
              .style("stroke-width", function (e) {
                  return 2
                  /* e.width*/
              }).merge(mLink).lower();

          mNode = svg.selectAll(".node")
              .data(mNodesData)
              .enter()
              .append("g")
              .attr("class", "node").merge(mNode);

          mNode.call(d3.drag()
              .on("start", dragstarted)
                  .on("drag", dragged)
                  .on("end", dragended));

          mNode.on('mouseover', function (currentNode) {
              mLink.filter(function (otherLink) {
                  if (currentNode !== otherLink.source) {
                      otherLink.source.style("opacity", BACKGROUND_OPACITY); // DOESN'T WORK
                  }
                  return (currentNode !== otherLink.source && currentNode !== otherLink.target);
              }).style("opacity", BACKGROUND_OPACITY);
              mLink.filter(function (otherLink) {
                  return (currentNode == otherLink.source || currentNode == otherLink.target);
              }).style("opacity", DEFAULT_OPACITY);
          });

          simulation.nodes(mNodesData);
          simulation.force(".edge").links(mEdgesData);
      }
  }
}

full code: here

Upvotes: 1

Views: 1001

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102194

First of all, currentNode and otherLink.source in your code are the data of those elements. Therefore, to get the IDs, you have to use their properties. For example, in your conditional:

if (currentNode.id !== otherLink.source.id)
//property here--^----------------------^

If I understand your question correctly, you want to get the ID of the node (or nodes) connected to a given node when you mouseover it, and then changing the style of that connected node (or any other change you want).

Here is a possible solution. First, on mouseover, we get the ID of the current node:

mNode.on('mouseover', function(currentNode) {
    var thisNodeID = currentNode.id;

Then, we use that ID to populate an array with the ID (or IDs, if more than one) of the connected node (or nodes):

var connectedNodes = mEdgesData.filter(function(d){
    return d.source.id === thisNodeID || d.target.id === thisNodeID
}).map(function(d){
    return d.source.id === thisNodeID ? d.target.id : d.source.id
});

Finally, we use indexOf to check what nodes are in that list:

mNode.filter(function(d){
  return connectedNodes.indexOf(d.id) > -1
}).style("opacity", DEFAULT_OPACITY);

All together, it would be:

mNode.on('mouseover', function(currentNode) {
    var thisNodeID = currentNode.id;
    var connectedNodes = mEdgesData.filter(function(d) {
        return d.source.id === thisNodeID || d.target.id === thisNodeID
    }).map(function(d) {
        return d.source.id === thisNodeID ? d.target.id : d.source.id
    });
    mNode.filter(function(d) {
        return connectedNodes.indexOf(d.id) > -1
    }).style("opacity", DEFAULT_OPACITY);
});

Since you didn't provide a running code, here is an example of that mouseover snippet based on a bl.ocks from Mike Bostock, where I'm changing the connected nodes to red: https://bl.ocks.org/anonymous/0db9b4307a1ff6724f89c932f55f6508/2a6cfa3a8bfb03cfa368033faa3804ae5601e403

Upvotes: 1

Related Questions