Javascript D3Js使用调用更新错误的元素

Javascript D3Js使用调用更新错误的元素,javascript,d3.js,Javascript,D3.js,我是D3JS新手,你可以在 我正面临一个问题,任何指点都会有帮助 当我移动直线时,它会像预期的那样分开,但当我尝试将圆移开时,它会跳回直线 在检查阵列时,当我移动链接时,圆形阵列似乎正在更新,不确定是什么原因导致了这种情况 在此方面的任何帮助都将不胜感激。下面是我在JSFIDLE上的代码 var width = 960, height = 500; graph1 = {"nodes":[{"x":444,"y":275},{"x":378,"y":324}],"links":[{"sou

我是D3JS新手,你可以在

我正面临一个问题,任何指点都会有帮助

当我移动直线时,它会像预期的那样分开,但当我尝试将圆移开时,它会跳回直线

在检查阵列时,当我移动链接时,圆形阵列似乎正在更新,不确定是什么原因导致了这种情况

在此方面的任何帮助都将不胜感激。下面是我在JSFIDLE上的代码

var width = 960,
    height = 500;
graph1 = {"nodes":[{"x":444,"y":275},{"x":378,"y":324}],"links":[{"source":1,"target":0}]}


var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);
var onDraggable = function(d1) {
          console.log(d1);

          d1.x = d3.event.x, d1.y = d3.event.y;
          d3.select(this).attr("cx", d1.x).attr("cy", d1.y);
          //console.log(d1);
          link.filter(function(l) { return l.source === d1; }).attr("x1", d3.event.x).attr("y1", d3.event.y);
          link.filter(function(l) { return l.target === d1; }).attr("x2", d3.event.x).attr("y2", d3.event.y);


        }
var drag = d3.behavior.drag()
      .origin(function(d) { return d; })
      .on("drag", onDraggable)




  var onDraggable1 = function(d) {
          //d.x1 = d3.event.x1, d.y1 = d3.event.y1, d.x2=d3.event.x2, y2=d3.event.y2;
          var mouseX = d3.mouse(this)[0];
          var mouseY = d3.mouse(this)[1];
          var relativeX = mouseX-d.source.x;
          var relativeY = mouseY-d.source.y;
          console.log(d);

          //console.log(d);
         // d3.select(this).attr("x1", d3.event.x).attr("y1", d3.event.y).attr("x2", d3.event.x).attr("y2", d3.event.y);
          d.source.x= d.source.x+relativeX;
          d.source.y = d.source.y+relativeY;
          d.target.x= d.target.x+relativeX;
          d.target.y = d.target.y+relativeY;

          d3.select(this).attr("x1", d.source.x).attr("y1", d.source.y);
          d3.select(this).attr("x2", d.target.x).attr("y2", d.target.y);

        }
var drag1 = d3.behavior.drag()
      .origin(function(d) { return d; })
      .on("drag", onDraggable1);

  graph1.links.forEach(function(d) {
    d.source = graph1.nodes[d.source];
    d.target = graph1.nodes[d.target];
  });




var node = svg.append("g").attr("class","node")
    .selectAll("circle")
      .data(graph1.nodes)
    .enter().append("circle")
      .attr("r", 4)
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; })
      .call(drag);

var link = svg.append("g").attr("class","link")
    .selectAll("line")
      .data(graph1.links)
    .enter().append("line")
      .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; })
      .attr("stroke-width", 2)
      .attr("stroke", "black")
      .call(drag1);

即使在移动线之后,节点也会“跳跃”到线的末端,这是因为节点的数据对象与线的源/目标数据对象是相同的。节点的
d
值和链接的
d.source
d.target
值只是指向浏览器内存中相同对象的指针(引用)。对该数据对象所做的一切都会反映在链接和节点中。这就是节点拖动功能的作用:直接更改数据对象,然后更新直线和圆的位置以匹配其已更改的数据值

因此,即使在移动直线时不更新圆的
cx
cy
位置,直线拖动方法中的语句
d.source.x=
等正在为节点设置
d.x
d.y
值。然后,在节点拖动方法中,当您访问这些值以确定新位置时,移动是相对于线的端点而不是屏幕上圆的位置确定的

那么,如何获得想要的行为,将线与节点分离?开始拖动线时,需要为线的源和目标创建一个新的数据对象,该对象不再引用节点的数据对象。只需在拖动开始时执行一次,因此可以使用拖动行为对象的:

var drag1 = d3.behavior.drag()
      .origin(function(d) { return d; })
      .on("dragstart", separateNodes);
      .on("drag", onDraggable1);
separateNodes
方法将非常简短。我们所要做的就是,对于链接的目标和源,创建一个新的数据对象,它是现有目标/源对象的副本(但可以独立于原始对象进行编辑)。Javascript没有任何用于复制对象的默认方法(尽管如此),但是如果所讨论的对象只是由x和y属性组成,那么很容易做到

var separateNodes = function(d) {
    //create new data objects that are copies of d.source and d.target
    var newSource = {x:d.source.x, y:d.source.y};
    var newTarget = {x:d.target.x, y:d.target.y};

    //set the new objects as the target/source of this link
    d.source = newSource; 
    d.target = newTarget;
}
您甚至可以跳过变量声明,只需将它们合并成一行作为源代码,一行作为目标代码,但我发现这样更容易理解。然而,我应该提到,这种方法是有效的,因为x和y都只是简单的数据类型(数字),而不是指向对象的指针。因此,当它说
x:d.source.x
时,实际上您得到了该编号的新副本,您可以更改该副本,而不会影响包含该编号的原始对象

但是,如果您的节点和链接也有一个
属性,该属性是一个复杂的数据对象,那么您必须决定当该行从节点分离时要执行的操作:是要创建整个值数据对象的副本,还是要维护到原始对象的链接,还是用null(空/未定义)替换它对象第一种情况比较复杂,取决于值对象的数据结构;第二,你不需要做任何事情(除了记住你有多个指向同一个对象的指针);对于最后一种情况,只需在
separateNodes
函数中的
newSource
newTarget
对象定义中添加
值:null、
属性

希望一切都有意义,

--ABR

你能澄清你想要的行为是什么吗?您希望直线和圆一起移动,还是希望它们完全独立?单击圆并拖动时,直线将展开,但同时单击直线并拖动时,直线应移动。这两种方法都有效。问题是,线与圆分离后,如果尝试将圆移开,它将返回并连接到线。因此,当移动线时,它应该与节点分离(并保持分离,以便不再连接到该节点)?另一种可能是您希望将线和节点一起移动,而不是像移动节点时那样拉伸/扭曲。正确的想法是将节点和线分开,并能够独立移动节点。感谢您的澄清;请看下面的答案。谢谢,这就完成了我想要的。我是D3JS的新手,接下来的问题是,你们怎么知道他们在浏览器中引用的是同一个对象?有没有什么工具和调试方法可以用来解决这些问题呢?还有一个问题,如果我想将节点连接回测线,那么当我拖动节点时,测线会展开……类似于我们开始时的情况。实现这一点的最佳方法是什么?或者换句话说,我如何在特定条件下将它们重新关联到同一个对象?我是如何发现的?我查看了其他拖动方法的代码,以了解它们是如何工作的。但这是一个标准特性(如果很容易忘记的话)——所有引用对象和数组的变量都只是指针。这是将指针连接在一起的行吗?d.source=graph1.nodes[d.source];d、 target=graph1.nodes[d.target];