【问题标题】:D3 Force Layout with Image as Node but Wrong Images are AppendedD3 以图像为节点的强制布局但附加了错误的图像
【发布时间】:2015-10-15 17:29:01
【问题描述】:

我正在尝试创建一个将图像作为节点的强制布局,可以根据用户输入(通过几个复选框)进行修改。但是,当用户更改他/她的输入并重新绘制布局时,一些图像会显示在错误节点的顶部,我不明白为什么。

我构建代码的方式:

  1. 我从 csv 中提取数据
  2. 我创建了一个“更新”函数,它根据用户输入创建/修改数据数组
  3. 我创建了一个“draw”函数,每次用户更改他/她的输入时(即每次调用“update”函数时)都会绘制强制布局

我的代码的第一部分似乎工作正常。数据数组是从 csv 创建并正确动态更新的。

但是当重新绘制图表时,一些图像出现在错误的节点上(即使工具提示中显示的图像是正确的..)。

下面是我的“绘图”功能,我认为这就是问题所在。

function draw(nodes) {

      var force = d3.layout.force()
        .nodes(nodes)
        .size([width, height])
        .on("tick", tick)
        .charge(-0.01)
        .gravity(0)
        .start();

    function tick(e) {

      // Set initial positions
    nodes.forEach(function(d) {
        d.radius = radius;
      });


      var node = svg.selectAll(".node")
                    .data(nodes);

      var newNode = node.enter().append("g")
                .attr("class", "node")
                .on("click", function(d) {
                                   div.transition().duration(300).style("opacity", 1);
                                   div.html("<img src=img_med/" + d.name + ".png >")
                                   .style("left", (d3.event.pageX) + "px")
                                   .style("top", (d3.event.pageY-10) + "px");
                                })
                .on("mouseout", function (d) { div.transition().delay(1500).duration(300).style("opacity", 0);});

          newNode.append("image")
             .attr("xlink:href", function(d) { return "img_med/" + d.name + ".png"; })
             .attr("x", -8)
             .attr("y", -8)
             .attr("width", 30)
             .attr("height", 30)
             .style("cursor", "pointer")
             .call(force.drag);

      node.exit().remove();

      node.each(moveTowardDataPosition(e.alpha));
      node.each(collide(e.alpha));
      node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

    }

    function moveTowardDataPosition(alpha) {
      return function(d) {
        d.x += (x(d[xVar]) - d.x) * 0.1 * alpha;
        d.y += (y(d[yVar]) - d.y) * 0.1 * alpha;
      };
    }

    // Resolve collisions between nodes.
    function collide(alpha) {
      var quadtree = d3.geom.quadtree(nodes);
      return function(d) {
        var r = d.radius + radius + padding,
            nx1 = d.x - r,
            nx2 = d.x + r,
            ny1 = d.y - r,
            ny2 = d.y + r;
        quadtree.visit(function(quad, x1, y1, x2, y2) {
          if (quad.point && (quad.point !== d)) {
            var x = d.x - quad.point.x,
                y = d.y - quad.point.y,
                l = Math.sqrt(x * x + y * y),
                r = d.radius + quad.point.radius + padding;
            if (l < r) {
              l = (l - r) / l * alpha;
              d.x -= x *= l;
              d.y -= y *= l;
              quad.point.x += x;
              quad.point.y += y;
            }
          }
          return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
        });
      };
    }
}

任何帮助/建议/指针帮助我理解为什么错误的图像显示在这些节点的顶部将不胜感激!

如果有什么不清楚的地方请告诉我。

非常感谢!

【问题讨论】:

  • 您可能需要一个关键函数(.data() 的第二个参数)告诉 D3 如何匹配现有节点和数据。默认是按索引,这可能不是你想要的。
  • @LarsKotthoff 感谢您的评论,我仍在学习关键功能,但如果我写类似: var node = svg.selectAll(".node") .data(nodes, function( d) {return d.name;});应该可以吧?
  • 从你的代码看来应该是的,是的。
  • @LarsKotthoff 谢谢它的工作!

标签: javascript image d3.js svg force-layout


【解决方案1】:

好吧,我只是缺少一个关键函数来告诉 D3 如何匹配现有节点和数据。

我换了

 var node = svg.selectAll(".node")
               .data(nodes);

通过

 var node = svg.selectAll(".node")
               .data(nodes, function(d) {return d.name;});

它奏效了。 谢谢拉斯!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-01
    • 2012-10-04
    相关资源
    最近更新 更多