Show tool-tip on links of force directed graph in d3js

感情迁移 提交于 2019-12-13 02:07:56

问题


I am working on a simple force directed graph as given in This link. It works well but I want to show tool-tip on edges also as it shows on nodes. Whenever I move the mouse on an edge, it shows some tool-tip on the link (data may be retrieved from JSON file). Is there a builtin method or I have to show the div on mouse-over (in this case how to get the position of mouse, where the div would be shown)


回答1:


  1. Is there a builtin method?

Ans: Yes. There is a built in way. Most HTML elements support the title attribute. When you move the mouse pointer over that element, a little tool-tip is shown for a certain amount of time or until you leave that element.

Demo:

var w = 500,
  h = 200

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

var graph = {
  nodes: [{
    name: 'A'
  }, {
    name: 'B'
  }],
  links: [{
    source: 0,
    target: 1
  }]
};

var force = d3.layout.force()
  .nodes(graph.nodes)
  .links(graph.links)
  .gravity(.05)
  .distance(100)
  .charge(-100)
  .size([w, h])
  .start();

var link = vis.selectAll("line.link")
  .data(graph.links)
  .enter().append("svg:line")
  .attr("class", "link");
link.append("title").text(function(d) {
  return d.source.name + " -> " + d.target.name
});

var node = vis.selectAll("g.node")
  .data(graph.nodes)
  .enter().append("svg:g")
  .attr("class", "node")
  .call(force.drag);
node.append("circle").attr("r", 5);
node.append("title").text(function(d) {
  return d.name
});


force.on("tick", function() {
  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("transform", function(d) {
    return "translate(" + d.x + "," + d.y + ")";
  });
});
line {
  stroke: red;
  stroke-width: 3;
}
cicrle {
  fill: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
  1. or I have to show the div on mouse-over? How to get the position of mouse? Where the div would be shown?

Ans:

If you would like to show a tooltip with html content, you can show a div on mouse-over. You can get the mouse position using d3.mouse method.

Demo:

var width = 960;
var height = 500;
var margin = 20;
var pad = margin / 2;

var color = d3.scale.category20();


var graph = {
  "nodes": [{
    "name": "Myriel",
    "group": 1
  }, {
    "name": "Napoleon",
    "group": 1
  }, {
    "name": "Mlle.Baptistine",
    "group": 1
  }, {
    "name": "Mme.Magloire",
    "group": 1
  }, {
    "name": "CountessdeLo",
    "group": 1
  }, {
    "name": "Geborand",
    "group": 1
  }, {
    "name": "Champtercier",
    "group": 1
  }, {
    "name": "Cravatte",
    "group": 1
  }, {
    "name": "Count",
    "group": 1
  }, {
    "name": "OldMan",
    "group": 1
  }, {
    "name": "Labarre",
    "group": 2
  }, {
    "name": "Valjean",
    "group": 2
  }, {
    "name": "Marguerite",
    "group": 3
  }, {
    "name": "Mme.deR",
    "group": 2
  }, {
    "name": "Isabeau",
    "group": 2
  }, {
    "name": "Gervais",
    "group": 2
  }, {
    "name": "Tholomyes",
    "group": 3
  }, {
    "name": "Listolier",
    "group": 3
  }, {
    "name": "Fameuil",
    "group": 3
  }, {
    "name": "Blacheville",
    "group": 3
  }, {
    "name": "Favourite",
    "group": 3
  }, {
    "name": "Dahlia",
    "group": 3
  }, {
    "name": "Zephine",
    "group": 3
  }, {
    "name": "Fantine",
    "group": 3
  }, {
    "name": "Mme.Thenardier",
    "group": 4
  }, {
    "name": "Thenardier",
    "group": 4
  }, ],
  "links": [{
    "source": 1,
    "target": 0,
    "value": 1
  }, {
    "source": 2,
    "target": 0,
    "value": 8
  }, {
    "source": 3,
    "target": 0,
    "value": 10
  }, {
    "source": 3,
    "target": 2,
    "value": 6
  }, {
    "source": 4,
    "target": 0,
    "value": 1
  }, {
    "source": 5,
    "target": 0,
    "value": 1
  }, {
    "source": 6,
    "target": 0,
    "value": 1
  }]
};
drawGraph(graph);

function drawGraph(graph) {
  var svg = d3.select("#force").append("svg")
    .attr("width", width)
    .attr("height", height);

  // draw plot background
  svg.append("rect")
    .attr("width", width)
    .attr("height", height)
    .style("fill", "#eeeeee");

  // create an area within svg for plotting graph
  var plot = svg.append("g")
    .attr("id", "plot")
    .attr("transform", "translate(" + pad + ", " + pad + ")");

  // https://github.com/mbostock/d3/wiki/Force-Layout#wiki-force
  var layout = d3.layout.force()
    .size([width - margin, height - margin])
    .charge(-120)
    .linkDistance(function(d, i) {
      return (d.source.group == d.target.group) ? 50 : 100;
    })
    .nodes(graph.nodes)
    .links(graph.links)
    .start();

  drawLinks(graph.links);
  drawNodes(graph.nodes);

  // add ability to drag and update layout
  // https://github.com/mbostock/d3/wiki/Force-Layout#wiki-drag
  d3.selectAll(".node").call(layout.drag);

  // https://github.com/mbostock/d3/wiki/Force-Layout#wiki-on
  layout.on("tick", function() {
    d3.selectAll(".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;
      });

    d3.selectAll(".node")
      .attr("cx", function(d) {
        return d.x;
      })
      .attr("cy", function(d) {
        return d.y;
      });
  });
}

// Draws nodes on plot
function drawNodes(nodes) {
  // used to assign nodes color by group
  var color = d3.scale.category20();

  // https://github.com/mbostock/d3/wiki/Force-Layout#wiki-nodes
  d3.select("#plot").selectAll(".node")
    .data(nodes)
    .enter()
    .append("circle")
    .attr("class", "node")
    .attr("id", function(d, i) {
      return d.name;
    })
    .attr("cx", function(d, i) {
      return d.x;
    })
    .attr("cy", function(d, i) {
      return d.y;
    })
    .attr("r", function(d, i) {
      return 4;
    })
    .style("fill", function(d, i) {
      return color(d.group);
    })
    .on("mouseover", function(d, i) {

      var x = d3.mouse(this)[0];
      var y = d3.mouse(this)[1];
      var tooltip = d3.select("#plot")
        .append("text")
        .text(d.name)
        .attr("x", x)
        .attr("y", y)
        //.attr("dy", -r * 2)
        .attr("id", "tooltip");

    })
    .on("mouseout", function(d, i) {
      d3.select("#tooltip").remove();
    });
}

// Draws edges between nodes
function drawLinks(links) {
  var scale = d3.scale.linear()
    .domain(d3.extent(links, function(d, i) {
      return d.value;
    }))
    .range([1, 6]);

  // https://github.com/mbostock/d3/wiki/Force-Layout#wiki-links
  d3.select("#plot").selectAll(".link")
    .data(links)
    .enter()
    .append("line")
    .attr("class", "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;
    })
    .style("stroke-width", function(d, i) {
      return scale(d.value) + "px";
    })
    .style("stroke-dasharray", function(d, i) {
      return (d.value <= 1) ? "2, 2" : "none";
    }).on("mouseover", function(d, i) {

      var x = d3.mouse(this)[0];
      var y = d3.mouse(this)[1];
      var tooltip = d3.select("#plot")
        .append("text")
        .text(d.source.name + " -> " + d.target.name)
        .attr("x", x)
        .attr("y", y)
        //.attr("dy", -r * 2)
        .attr("id", "tooltip");
    })
    .on("mouseout", function(d, i) {
      d3.select("#tooltip").remove();
    });

}
body {
  font-family: 'Source Sans Pro', sans-serif;
  font-weight: 300;
}
b {
  font-weight: 900;
}
.outline {
  fill: none;
  stroke: #888888;
  stroke-width: 1px;
}
#tooltip {
  font-size: 10pt;
  font-weight: 900;
  fill: #000000;
  stroke: #ffffff;
  stroke-width: 0.25px;
}
.node {
  stroke: #ffffff;
  stroke-weight: 1px;
}
.link {
  fill: none;
  stroke: #888888;
  stroke-weight: 1px;
  stroke-opacity: 0.5;
}
.highlight {
  stroke: red;
  stroke-weight: 4px;
  stroke-opacity: 1.0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div align="center" id="force"></div>



回答2:


You can use the <title> element for line elements in the same way the linked demo does for circle elements. For instance,

link.append("title")
  .text(function(d) { return "This is my title"; });

would create such tooltips in the demo linked. Note that, according to the spec, you should ensure the title element is the first child of the parent.

Also note that this may not be an effective way to communicate with the user; hovering over a line is rather difficult, especially in a moving graph. One potential solution would be to wrap each line in a larger group with an invisible line of larger width, and add the title as the first child of the group, as the title element also works just fine with <g> elements.



来源:https://stackoverflow.com/questions/33165265/show-tool-tip-on-links-of-force-directed-graph-in-d3js

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