有没有办法放大D3力布局图?

D3 在这里有一个强制定向布局。 有没有添加缩放到这个图表的方法? 目前,我能够捕捉鼠标滚轮事件,但是我不确定如何编写重绘function本身。 有什么build议么?

var vis = d3.select("#graph") .append("svg:svg") .call(d3.behavior.zoom().on("zoom", redraw)) // <-- redraw function .attr("width", w) .attr("height", h); 

更新6/4/14

另请参阅迈克·博斯托克(Mike Bostock)在这里对D3 v.3和相关例子的修改 。 我想这可能取代下面的答案。

更新2/18/2014

我认为@ ahaarnos的答案是可取的,如果你想整个SVG平移和缩放。 下面我的答案中嵌套的g元素只有在同一个SVG中没有缩放元素的情况下(而不是原始问题中的情况)才有必要。 如果您将行为应用于g元素,则需要使用背景rect或类似的元素来确保g接收指针事件。

原始答复

我得到这个基于zoom-pan-transform示例的工作 – 你可以在这里看到我的jsFiddle: http : //jsfiddle.net/nrabinowitz/QMKm3/

这比我希望的复杂一点 – 你必须嵌套几个g元素才能使它工作,将SVG的pointer-events属性设置为all ,然后附加一个背景矩形来接收指针事件(否则它只能工作当指针在节点或链接上时)。 redrawfunction比较简单,只需在最里面的g上设置一个变换:

 var vis = d3.select("#chart") .append("svg:svg") .attr("width", w) .attr("height", h) .attr("pointer-events", "all") .append('svg:g') .call(d3.behavior.zoom().on("zoom", redraw)) .append('svg:g'); vis.append('svg:rect') .attr('width', w) .attr('height', h) .attr('fill', 'white'); function redraw() { console.log("here", d3.event.translate, d3.event.scale); vis.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); } 

这有效地缩放了整个SVG,所以它也缩放了笔画宽度,就像放大图像一样。

还有一个例子说明了类似的技术。

为什么嵌套<g>的?

下面的代码适用于我(只有一个<g> ,没有随机的大白<rect>

 var svg = d3.select("body") .append("svg") .attr({ "width": "100%", "height": "100%" }) .attr("viewBox", "0 0 " + width + " " + height ) .attr("preserveAspectRatio", "xMidYMid meet") .attr("pointer-events", "all") .call(d3.behavior.zoom().on("zoom", redraw)); var vis = svg .append('svg:g'); function redraw() { vis.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); } 

你的svg中的所有元素都被添加到vis元素中。

提供的答案在D3 v2中工作,但不在v3中。 我已经综合了答案到一个干净的解决scheme,并解决了v3问题使用在这里提供的答案: 为什么d3js v3打破我的力量图时,实施缩放当v2不?

首先是主代码。 这是@ahaarnos'回答的清理版本:

  var svg = d3.select("body") .append("svg") .attr("width", width) .attr("height", height) .call(d3.behavior.zoom().on("zoom", redraw)) .append('g'); function redraw() { svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); } 

现在,您可以进行平移和缩放,但是您将无法拖动节点,因为平移function将覆盖拖动function。 所以我们需要这样做:

 var drag = force.stop().drag() .on("dragstart", function(d) { d3.event.sourceEvent.stopPropagation(); // to prevent pan functionality from //overriding node drag functionality. // put any other 'dragstart' actions here }); 

这里是@nrabinowitz小提琴修改使用这个更干净的缩放实现,但说明D3v3如何打破节点拖动: http : //jsfiddle.net/QMKm3/718/

这里是修改与D3v3相同的小提琴: http : //jsfiddle.net/QMKm3/719/

我没有第二个“svg:g”追加了我的图表工作。

 [...].attr("pointer-events", "all") .attr("width", width2) .attr("height", height2) .append('svg:g') .call(d3.behavior.zoom().on("zoom", redraw)); 

其余的是一样的。

我有一个解决schemeD3强制有向图与缩放选项。

  var m = [40, 240, 40, 240], width = 960, height = 700, root; var svg = d3.select("body").append("svg") .attr("class", "svg_container") .attr("width", width) .attr("height", height) .style("overflow", "scroll") .style("background-color", "#EEEEEE") .append("svg:g") .attr("class", "drawarea") .append("svg:g") .attr("transform", "translate(" + m[3] + "," + m[0] + ")"); //applying zoom in&out for svg d3.select("svg") .call(d3.behavior.zoom() .scaleExtent([0.5, 5]) .on("zoom", zoom)); //zooming function zoom() { //zoom in&out function var scale = d3.event.scale, translation = d3.event.translate, tbound = -height * scale, bbound = height * scale, lbound = (-width + m[1]) * scale, rbound = (width - m[3]) * scale; // limit translation to thresholds translation = [ Math.max(Math.min(translation[0], rbound), lbound), Math.max(Math.min(translation[1], bbound), tbound) ]; d3.select(".drawarea") .attr("transform", "translate(" + translation + ")" + " scale(" + scale + ")"); } 

如果要在不更改节点大小的情况下缩放和平移力布局,请在下面尝试。 您也可以拖动节点而不发抖。 这个代码是基于原始的力布局的例子。 至于节点和链接数据,请参考原始样本数据。 http://bl.ocks.org/mbostock/4062045

注意variablesxScale和yScale,函数dragstarted(),dragged()和dragended()。 函数tick()也被改变了。

您可以在http://steelblue.tistory.com/9查看结果。网站上的语言是韩语。; 但是,您可以在页面上的第三个示例中轻松find结果。

 var graph = { "nodes": [ { "name": "Myriel", "group": 1 }, { "name": "Napoleon", "group": 1 }, // ...... { "name": "Mme.Hucheloup", "group": 8 } ], "links": [ { "source": 1, "target": 0, "value": 1 }, { "source": 2, "target": 0, "value": 8 }, // ....... { "source": 76, "target": 58, "value": 1 } ] }; var width = 640, height = 400; var color = d3.scale.category20(); var xScale = d3.scale.linear() .domain([0, width]) .range([0, width]); var yScale = d3.scale.linear() .domain([0, height]) .range([0, height]); var zoomer = d3.behavior.zoom().x(xScale).y(yScale).scaleExtent([0.1, 8]).on("zoom", zoom); function zoom() { tick(); }; var drag = d3.behavior.drag() .origin(function (d) { return d; }) .on("dragstart", dragstarted) .on("drag", dragged) .on("dragend", dragended); function dragstarted(d) { d3.event.sourceEvent.stopPropagation(); d.fixed |= 2; } function dragged(d) { var mouse = d3.mouse(svg.node()); dx = xScale.invert(mouse[0]); dy = yScale.invert(mouse[1]); d.px = dx; d.py = dy; force.resume(); } function dragended(d) { d.fixed &= ~6; } var force = d3.layout.force() .charge(-120) .linkDistance(30) .size([width, height]); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); svg.call(zoomer); force .nodes(graph.nodes) .links(graph.links) .start(); var link = svg.selectAll(".link") .data(graph.links) .enter().append("line") .attr("class", "link") .style("stroke-width", function (d) { return Math.sqrt(d.value); }); var node = svg.selectAll(".node") .data(graph.nodes) .enter().append("circle") .attr("class", "node") .attr("r", 5) .style("fill", function (d) { return color(d.group); }) .call(drag); node.append("title") .text(function (d) { return d.name; }); force.on("tick",tick); function tick(){ link.attr("x1", function (d) { return xScale(d.source.x); }) .attr("y1", function (d) { return yScale(d.source.y); }) .attr("x2", function (d) { return xScale(d.target.x); }) .attr("y2", function (d) { return yScale(d.target.y); }); node.attr("transform", function (d) { return "translate(" + xScale(dx) + "," + yScale(dy) + ")"; }); };