D3.js 如何在图形中混合缩放和拖动功能?

D3.js 如何在图形中混合缩放和拖动功能?,d3.js,svg,D3.js,Svg,有了如下设置的atlas力图,我想从绘图区域中的任何位置放大和缩小鼠标滚轮事件,但不包括节点圆,以便允许拖动单个节点 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

有了如下设置的atlas力图,我想从绘图区域中的任何位置放大和缩小鼠标滚轮事件,但不包括节点圆,以便允许拖动单个节点

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 + ")"; });
});
我在这段代码中遇到的问题是,单击一个节点并拖动它会拖拽整个图形,而在删除调用时。。。重画部分,这样我可以拖动单个节点

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 + ")"; });
});
有没有一种方法可以混合这两种行为,或者在指针位于节点内部时防止缩放,或者在全局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>

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

    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);
}
*/

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

试试这段代码:也可以

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   + ")"; });
});

您是否尝试过在单个节点的拖动处理程序中停止事件的传播?您阅读了吗?Jap应该是我主题中@Cool Blue答案的混合体。请做一把小提琴。在那里,实现它应该是非常简单和快速的=@coolblue,谢谢你指出这一点,但是我不知道发生了什么。我将尽快创建一个Fiddle。函数Fiddle在这里:您能解释一下错误是什么,以及您的代码段为什么工作吗?