D3J使用呼叫更新错误的元素 [英] D3Js updating wrong elements using call

查看:142
本文介绍了D3J使用呼叫更新错误的元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是D3JS的新手,您可以在 http://jsfiddle.net/3n8wD/

I am new to D3JS and you can find the code at http://jsfiddle.net/3n8wD/

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

I am a facing an issue and any pointers would help

当我移动直线时,它会按预期分离,但是当我尝试将圆圈移开时,它会跳回到直线上.

When I move the line it separates as expected, but as soon as I try to move the circles away it jumps back to the line.

在检查数组时,好像圆数组在我移动链接时正在更新,不确定是什么原因引起的.

On inspecting the Array, looks like the circle array is updating as I am moving the link, not sure what is causing that.

对此将提供任何帮助,我们将不胜感激.以下是我在jsfiddle上拥有的代码

Any help on this would be highly appreciated. below is the code that i have on jsfiddle

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.sourced.target值只是指向浏览器内存中同一对象的指针(引用).您对该数据对象所做的一切都会在链接和节点中反映出来.这就是使节点拖动功能起作用的原因:直接更改数据对象,然后更新线和圆的位置以匹配它们已更改的数据值.

The reason that your nodes are "jumping" to the end of the line, even after the line has been moved away, is because the data object for the node is the same object as the source/target data object for the line. The d value for the node and the d.source or d.target value for the link are just pointers (references) to the same object in the browser's memory. Everything you do to that data object is reflected in both the link and the node. That's what makes the node-drag function work: you change the data object directly, and then you update the position of the line and the circle to match their already-changed data value.

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

So, even though you don't update the circle's cx and cy position at the time you move the line, the statements d.source.x = etc. in the line drag method are setting the d.x and d.y values for the nodes. Then in the node drag method, when you access these values to determine the new position, the movement is determined relative to the end of the line, not to the position of the circle on screen.

那么,如何将所需的行为与节点分开呢?开始拖动该行时,需要为该行的源和目标创建一个 new 数据对象,该数据对象不再引用节点的数据对象.在拖动开始时,您只需要执行一次,因此您可以使用

So how do you get the behaviour you want, to separate the line from the node? You need to create a new data object for the line's source and target when you start to drag it, one that no longer references the nodes' data objects. You only need to do this once, at the start of the drag, so you use the dragstart event of the drag behaviour object:

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

separateNodes方法将很短.我们要做的就是为链接的目标和源创建一个新的数据对象,该对象是现有目标/源对象的副本(但是可以独立于原始对象进行编辑). Javascript没有用于复制对象的默认方法(尽管各种扩展名都可以做到),但是如果所讨论的对象仅由x和y属性组成,则很容易做到.

The separateNodes method is going to be quite short. All we have to do is, for both the target and the source of the link, create a new data object that is a copy of the existing target/source object (but which can be edited independently of the original object). Javascript doesn't have any default methods for copying an object (although various extensions do), but if the object in question just consists of x and y attributes, it is easy to do.

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时,实际上是在获取该编号的新副本,可以对其进行更改而不会影响包含该编号的原始对象.

You could even skip the variable declarations and just merge it all into one line for source and one for target, but I find it easier to understand like this. I should mention, however, that this approach works because x and y are both just simple data types (numbers), not pointers to objects. So when it says x:d.source.x, you are actually getting a new copy of that number which you can change without having it affect the original object that contained that number.

但是,如果您的节点和链接还具有作为复杂数据对象的value属性,那么您必须确定当行与节点分离时要执行的操作:是否要创建副本整个值数据对象,还是保持与原始对象的链接,或者将其替换为空(空/未定义)对象?第一种情况很复杂,取决于值对象的数据结构.第二秒钟,您无需执行任何操作(除非记住您有多个指向同一对象的指针);对于最后一种情况,您只需在separateNodes函数的newSourcenewTarget对象定义中添加value:null,属性.

If, however, your nodes and links also have a value property that is a complex data object, then you have to decide what you want to do when the line separates from the node: do you want to create a copy of the entire value data object, or maintain the link to the original object, or replace it with a null (empty/undefined) object? The first case is complicated, and depends on the data structure of the value object; for the second you don't need to do anything (except remember that you've got multiple pointers to the same object); and for the last case you just add a value:null, attribute to the newSource and newTarget object definitions in your separateNodes function.

希望一切都有道理,
--ABR

Hope that all makes sense,
--ABR

这篇关于D3J使用呼叫更新错误的元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆