如何模拟D3中的鼠标移动,以便在拖动节点时其他节点自动移动?

那一个人

我有一个粘滞力布局:http : //jsfiddle.net/smqsusdw/

我有将此功能拖到一个位置的节点:

function positionnodes(){

     force.stop();
     node.each(function(d, i){
         if(i===1){      

         d.fixed = true;
         d.x = 100;
         d.y = 100;
         }
     }).transition().duration(1000).attr("cx", function(d){ return d.x }).attr("cy", function(d){ return d.y });

    link.transition().duration(1000)
                      .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力的物理作用,相关节点也随之移动。有没有办法模拟这种运动

高积云

要选择正确的方法,重要的是要知道在D3的力布局中,计算与任何元素的实际渲染是分离的。d3.layout.force()将根据指定的参数来计算运动和位置。渲染将由在中注册的处理程序完成.force("tick", renderingHandler)此功能将在每个刻度上被强制布局调用,并根据计算出的位置渲染元素。

考虑到这一点,很明显,您的解决方案将无法按预期工作。在图形元素上使用过渡将仅在不更新数据且不涉及力布局的情况下移动节点。为了获得所需的行为,您需要坚持将计算和渲染分离。这将使您摆脱实现鼠标事件模拟的需要。

这可以通过使用来完成d3.timer(),它将重复调用将移动节点的位置设置为其起点和终点之间的插值的函数。设置完这些值之后,该函数将激活强制布局以对其余节点进行工作,并调用渲染处理程序.tick(),该处理程序将更新整个布局。

function positionnodes(){

    var move = graph.nodes[1],  // the node to move around
        duration = 1000,        // duration of the movement
        finalPos = { x: 100, y: 100 },
        interpolateX = d3.interpolateNumber(move.x, finalPos.x),
        interpolateY = d3.interpolateNumber(move.y, finalPos.y);

    // We don't want the force layout to mess with our node.
    move.fixed = true;  

    // Move the node by repeatedly determining its position.
    d3.timer(function(elapsed) {

        // Because the node should remain fixed, the previous position (.px, .py)
        // needs to be set to the same value as the new position (.x, .y). This way
        // the node will not have any inherent movement.
        move.x = move.px = interpolateX(elapsed / duration); 
        move.y = move.py = interpolateY(elapsed / duration); 

        // Re-calculate the force layout. This will also invoke tick()
        // which will take care of the rendering.
        force.start();

        // Terminate the timer when the desired duration has elapsed.
        return elapsed >= duration;
    });

}

请查看以下代码片段或更新的JSFiddle,以使您的代码适应工作。

var graph  ={
  "nodes": [
    {"x": 469, "y": 410},
    {"x": 493, "y": 364},
    {"x": 442, "y": 365},
    {"x": 467, "y": 314},
    {"x": 477, "y": 248},
    {"x": 425, "y": 207},
    {"x": 402, "y": 155},
    {"x": 369, "y": 196},
    {"x": 350, "y": 148},
    {"x": 539, "y": 222},
    {"x": 594, "y": 235},
    {"x": 582, "y": 185},
    {"x": 633, "y": 200}
  ],
  "links": [
    {"source":  0, "target":  1},
    {"source":  1, "target":  2},
    {"source":  2, "target":  0},
    {"source":  1, "target":  3},
    {"source":  3, "target":  2},
    {"source":  3, "target":  4},
    {"source":  4, "target":  5},
    {"source":  5, "target":  6},
    {"source":  5, "target":  7},
    {"source":  6, "target":  7},
    {"source":  6, "target":  8},
    {"source":  7, "target":  8},
    {"source":  9, "target":  4},
    {"source":  9, "target": 11},
    {"source":  9, "target": 10},
    {"source": 10, "target": 11},
    {"source": 11, "target": 12},
    {"source": 12, "target": 10}
  ]
}





var width = 960,
    height = 500;

var force = d3.layout.force()
    .size([width, height])
    .charge(-400)
    .linkDistance(40)
    .on("tick", tick);

var drag = force.drag()
    .on("dragstart", dragstart);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

var link = svg.selectAll(".link"),
    node = svg.selectAll(".node");

//d3.json("graph.json", function(error, graph) {
 // if (error) throw error;

  force
      .nodes(graph.nodes)
      .links(graph.links)
      .start();

  link = link.data(graph.links)
    .enter().append("line")
      .attr("class", "link");

  node = node.data(graph.nodes)
    .enter().append("circle")
      .attr("class", "node")
      .attr("r", 12)
      .on("dblclick", dblclick)
      .call(drag);
//});

function tick() {
  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("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; });
}

function dblclick(d) {
  d3.select(this).classed("fixed", d.fixed = false);
}

function dragstart(d) {
  d3.select(this).classed("fixed", d.fixed = true);
}


function positionnodes(){
    
    var move = graph.nodes[1],  // the node to move around
        duration = 1000,        // duration of the movement
        finalPos = { x: 100, y: 100 },
        interpolateX = d3.interpolateNumber(move.x, finalPos.x),
        interpolateY = d3.interpolateNumber(move.y, finalPos.y);
    
    // We don't want the force layout to mess with our node.
    move.fixed = true;  
    
    // Move the node by repeatedly determining its position.
    d3.timer(function(elapsed) {
        
        // Because the node should remain fixed, the previous position (.px, .py)
        // needs to be set to the same value as the new position (.x, .y). This way
        // the node will not have any inherent movement.
        move.x = move.px = interpolateX(elapsed / duration); 
        move.y = move.py = interpolateY(elapsed / duration); 
        
        // Re-calculate the force layout. This will also invoke tick()
        // which will take care of the rendering.
        force.start();
        
        // Terminate the timer when the desired duration has elapsed.
        return elapsed >= duration;
    });
	
}
.link {
  stroke: #000;
  stroke-width: 1.5px;
}

.node {
  cursor: move;
  fill: #ccc;
  stroke: #000;
  stroke-width: 1.5px;
}

.node.fixed {
   fill: #f00;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<button onclick = 'positionnodes()'> click me</button>

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

d3单节点移动并用光标排斥其他节点

如何在D3中粘贴拖动的节点

d3.js - 强制模拟拖动不随鼠标移动

d3在鼠标移动上创建节点的上下文中插入与追加

如何在Excel中动态链接文件,以便在移动文件时链接也会自动更新?

在d3中将鼠标悬停在节点上时,如何突出显示节点,它们连接的节点以及它们的连接?

Konvajs:如何单击一个节点,开始移动鼠标,但拖动另一个节点?

限制D3有向图的边界中的节点移动

D3强制布局,使树中的分支而不是节点移动

如何将XML注释节点转换并移动到其他位置的元素节点

在D3 v6中,鼠标悬停时无法获取节点基准

D3力向图:拖动时节点不停留在鼠标位置

d3拖动时拖动拖动到其他位置-原点?

根据数据中的其他列更改d3 Sankey图中的节点颜色

如何在D3中的节点上绘制的饼图上添加鼠标悬停属性?

d3树-缩放时如何自动调整节点间距

如何在按下按钮时检测鼠标在节点上的移动?

当我单击并拖动鼠标时如何使Jframe移动

拖动D3节点时防止单击动作

如何通过更改代码中而不是鼠标的位置来移动JUNG节点(顶点)?

将鼠标悬停在强制布局d3中的节点上时连接的链接线动画

在一个模拟器中停止节点的移动

在移动专利诉讼D3的节点上两行打印文本

D3力布局:根据节点半径沿链接移动箭头

如何将参数传递给类,以便在构造函数中传递参数时,JFrame会移动?

鼠标拖动时水平自动滚动在Firefox的D3树中不起作用

拖动setOnMouseDragged上的移动节点仅在父节点上触发

带有可拖动节点的 D3 布局

当鼠标在img上移动时如何在其他元素的顶部制作按钮?