在d3js中显示力导向图链接上的工具提示

时间:2015-10-16 07:54:34

标签: javascript d3.js force-layout

我正在研究This链接中给出的简单的力导向图。它工作得很好,但我想在边缘上显示工具提示,因为它在节点上显示。每当我在边缘上移动鼠标时,它都会在链接上显示一些工具提示(可以从JSON文件中检索数据)。 是否有内置方法或者我必须在鼠标悬停时显示div(在这种情况下如何获取鼠标的位置,div将显示在哪里)

2 个答案:

答案 0 :(得分:1)

  1. 是否有内置方法?
  2. 答案:是的。有内置的方式。大多数HTML元素都支持title属性。当您将鼠标指针移动到该元素上时,会显示一个小工具提示一段时间或直到您离开该元素。

    <强>演示:

    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. 或者我必须在鼠标悬停时显示div?如何获得鼠标的位置? div会显示在哪里?
    2. 答案

      如果您想显示带有html内容的工具提示,可以在鼠标悬停时显示div。您可以使用d3.mouse方法获取鼠标位置。

      <强>演示:

      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>

答案 1 :(得分:0)

您可以将<title>元素用于line元素,方法与链接演示对circle元素的操作方式相同。例如,

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

会在演示链接中创建此类工具提示。请注意,according to the spec,您应确保title元素是父元素的第一个子元素。

另请注意,这可能不是与用户沟通的有效方式;悬停在一条线上相当困难,特别是在移动的图形中。一个可能的解决方案是将每一行包装在一个较大的组中,并使用较大宽度的不可见行,并将标题添加为该组的第一个子项,因为title元素也适用于<g>元素。< / p>