【问题标题】:How to mix zoom and drag functions in a graph?如何在图表中混合缩放和拖动功能?
【发布时间】:2015-10-12 23:25:48
【问题描述】:

具有如下设置的图集力图,我想从绘图区域中的任何位置放大和缩小鼠标滚轮事件,但节点(圆圈)以允许拖动单个节点。

var svg = graph.append("svg")
    .attr("width", width)
    .attr("height", height)
    .attr("pointer-events", "all")
    .call(d3.behavior.zoom().on("zoom", redraw))
    .append('g');

var link = svg.selectAll(".link")
    .data(links)
    .enter().append("line")
    .attr("class", "link")

var node = svg.selectAll(".node")
    .data(nodes)
    .enter().append("svg:g")
    .attr("class", "node")
    .on("dblclick", dblclick)
    .call(force.drag);

node.append("circle")
    .attr("class", "circle");

function redraw() {
    svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
}

force.on("tick", function() {
    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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});

我对这段代码的问题是单击一个节点并拖动它会拖动整个图形,而当删除 call(... redraw) 部分时,它会让我拖动单个节点。

有没有办法混合这两种行为,或者在指针位于节点内时防止缩放,或者在全局 (svg) 事件中流行节点事件?

<!DOCTYPE html>
<html>
<head>
    <title>Fidlde</title>
    <script type="text/javascript" src="d3-master/d3.v3.min.js"></script>
    <style>
.circle {
fill: #F5F5F5;
stroke: #999999;
stroke-width: 3;
}

.node text {
pointer-events: none;
font: 10px sans-serif;
}

.link {
stroke: #999999;
stroke-opacity: .6;
stroke-width: 3;
}
    </style>
</head>
<body>
    <div id="graph">Hello!</div>
    <script>
// graph size
var width = 400;
var height = 400;

var nodes = [{name: 'A'}, {name: 'B'}, {name: 'C'}, {name: 'D'}];
var edges = [{source: 'A', target: 'B'}, {source: 'B', target: 'C'}, {source: 'C', target: 'A'}, {source: 'C', target: 'D'}];

var nodeMap = {};
nodes.forEach(function(x) { nodeMap[x.name] = x; });
var links = edges.map(function(x) {
  return { source: nodeMap[x.source], target: nodeMap[x.target], value: 1 };
});

var graph = d3.select("#graph");
var svg = graph.append("svg")
.attr("width", width)
.attr("height", height)
.attr("pointer-events", "all")
.call(d3.behavior.zoom().on("zoom", redraw))
.append('g');

var force = d3.layout.force()
.gravity(.25)
.distance(140)
.charge(-3500)
.size([width, height]);

/* Issue was here, the following code addresses it.
Thanks to Lars and Cool Blue - see comments
var drag = force.drag()
.on("dragstart", dragstart);
*/  

var stdDragStart = force.drag().on("dragstart.force");
force.drag()
.on("dragstart", function(d){
    //prevent dragging on the nodes from dragging the canvas
    d3.event.sourceEvent.stopPropagation();
    stdDragStart.call(this, d);
 });    

force
.nodes(nodes)
.links(links)
.friction(0.8)
.start();

var link = svg.selectAll(".link")
.data(links)
.enter().append("line")
.attr("class", "link");

var node = svg.selectAll(".node")
.data(nodes)
.enter().append("svg:g")
.attr("class", "node")
.on("dblclick", dblclick)
.call(force.drag);

node.append("circle")
.attr("class", "circle")
.attr("r", 10);

node.append("text")
.attr("dx", -4)
.attr("dy", ".35em")
.text(function(d) { return d.name; });

force.on("tick", function() {
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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});

// redraw after zooming
function redraw() {
    svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
}

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

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

    </script>
</body>
</html>

【问题讨论】:

  • 您是否尝试过在单个节点的拖动处理程序中停止事件传播?
  • 你读过this answer吗?
  • Jap 应该是@Cool Blue 关于我的主题的答案的混合体。请创建一个小提琴。在那里实现它应该非常容易和快速=)
  • @Cool Blue,感谢您指出这一点,但是我不确定发生了什么。我会尽快创建一个 Fiddle。
  • 功能小提琴在这里:jsfiddle.net/pducrot/omb470vw/2

标签: d3.js svg


【解决方案1】:

为了解决剩余的拖拽节点问题,我在代码中做了如下改动:

    node.enter()
        .append("svg:g")
        .attr("pointer-events", "all")
        .attr("id", function(d) { return '_'+d.name })
        .attr("class", "node")
        .on("click", nodeClick)
        .on("dblclick", nodeDoubleClick)
        .on("mouseover", nodeMouseOver)
        .on("mouseout", nodeMouseOut)
        .call(force.drag);

function nodeClick(d) {
    // fix the current node to its position
    d.fixed = true;
}

function nodeDoubleClick(d) {
    // release the current node
    d.fixed = false;
}

function nodeMouseOver(d) {
    // move the current node to front - some nodes are overlapping each others
    var sel = d3.select(this);
    sel.moveToFront();
    // stop the whole graph
    force.stop();
}

function nodeMouseOut(d) {
    // resume node motion
    force.start();
}

我还删除了以下 dragstart 函数,该函数保留在之前的代码中,并且可能在缩放时被调用。

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

现在一切正常。感谢大家的贡献。

【讨论】:

    【解决方案2】:

    试试这个 sn-p 的代码 :) 也可以

    var width=600;
    var height=600;
    
    var nodes=[{
      "name":"n1"
      },{
      "name":"n2"
     },{
      "name":"n3"
     },{
     "name":"n4"
     },{
      "name":"n5"
     }];
     var links=[{"source":0,"target":1},
      {"source":0,"target":2},
      {"source":0,"target":3},
      {"source":1,"target":4},
      {"source":2,"target":4},
      {"source":3,"target":2}];
    
     var svg = d3.select("body").append("svg")
     .attr("width", width)
     .attr("height", height)
     .attr("transform","translate(200,200)");
    
    
     svg.append("rect")
         .attr("width",width)
         .attr("height",height)
         .attr("fill","none")
         .attr("pointer-events","all")
         .call(d3.behavior.zoom().on("zoom", redraw));;
    
    
     var force=d3.layout.force().charge(-400).linkDistance(200);
    
    
     force.nodes(nodes).links(links).start();
     var link = svg.selectAll(".link")
      .data(links)
     .enter().append("line")
     .attr("class", "link")
    
     var node = svg.selectAll("circle")
     .data(nodes)
     .enter()
     .append("circle")
     .attr("class","circle")
     .call(force.drag);
    
    
    
      function redraw() {
         svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale("    + d3.event.scale + ")");
       }
    
    force.on("tick", function() {
       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("transform", function(d) { return "translate(" + d.x + "," + d.y   + ")"; });
    });
    

    【讨论】:

    • 您能解释一下错误是什么以及为什么您的 sn-p 工作正常吗?
    猜你喜欢
    • 2016-03-17
    • 2021-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    • 1970-01-01
    相关资源
    最近更新 更多