带有画布网络的工具提示

时间:2016-07-08 16:34:02

标签: javascript html5 canvas d3.js

我使用D3.v4和画布进行了大型力布局。因为我不能真正使用SVG。

如何为画布上的元素制作工具提示?

至少,如何识别鼠标在画布上的位置?

我尝试使用this问题的答案作为灵感,检查鼠标光标在画布上的位置,然后使用simulation.find(x,y,radius)识别附近的节点。但是,这会导致很多误报,我感觉HTML事件和simulation.find()的工作方式不同和/或使用不同的坐标标准。

有没有人对此有任何想法或解决方案?

修改:建议您查看this问题。我试图这样做,它有点工作。现在的问题是,正如所怀疑的,simulation.find(..)似乎没有使用这些画布坐标来查找网络中的节点。

对于好奇,这是我用来查找光标和附近节点的当前函数:

canvas = d3.select('canvas')
function getPos(e) {
    rect = canvas.node().getBoundingClientRect();
    scaleX = width / rect.width;
    scaleY = height / rect.height;
    x = (e.clientX - rect.left);
    y = (e.clientY - rect.top);
    node = simulation.find(x,y, 3);
    return {
        x : x,
        y : y,
        node : node
    };
}

1 个答案:

答案 0 :(得分:1)

您应该使用内置的d3.mouse来确定画布中的位置:

d3.select("canvas").on("mousemove", function(d){
  var p = d3.mouse(this);
  var node = simulation.find(p[0], p[1]);
});

这是一个快速示例,它突出显示最靠近鼠标位置的节点:



<!DOCTYPE html>
<meta charset="utf-8">
<canvas width="960" height="600"></canvas>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
  var canvas = document.querySelector("canvas"),
    context = canvas.getContext("2d"),
    width = canvas.width,
    height = canvas.height;

  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));


  var graph = {};
  graph.nodes = d3.range(100).map(function(d) {
    return {
      id: d
    }
  });
  graph.links = d3.range(200).map(function(d) {
    return {
      source: Math.floor(Math.random() * 100),
      target: Math.floor(Math.random() * 100)
    };
  });

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

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

  function ticked() {
    context.clearRect(0, 0, width, height);

    context.beginPath();
    graph.links.forEach(drawLink);
    context.strokeStyle = "#aaa";
    context.stroke();

    context.beginPath();
    graph.nodes.forEach(drawNode);
    context.fill();
    context.strokeStyle = "#fff";
    context.stroke();
    
    if (closeNode) {
      context.beginPath();
      drawNode(closeNode)
      context.fill();
      context.strokeStyle = "#ff0000";
      context.stroke();
    }
  }
  
  var closeNode;
  d3.select("canvas").on("mousemove", function(d){
    var p = d3.mouse(this);
    closeNode = simulation.find(p[0], p[1]);
    ticked();
  })

  function drawLink(d) {
    context.moveTo(d.source.x, d.source.y);
    context.lineTo(d.target.x, d.target.y);
  }

  function drawNode(d) {
    context.moveTo(d.x + 3, d.y);
    context.arc(d.x, d.y, 3, 0, 2 * Math.PI);
  }
</script>
&#13;
&#13;
&#13;