Javascript 如何使 D3.js 中的力布局图响应屏幕/浏览器大小
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11942500/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make force layout graph in D3.js responsive to screen/browser size
提问by MLister
I have a graph using force layout, but it has a fixed width w
and height h
:
我有一个使用强制布局的图形,但它具有固定的宽度w
和高度h
:
var svg = d3.select("#viz").append("svg")
.attr("id", "playgraph")
.attr("width", w)
.attr("height", h)
var force = d3.layout.force()
.nodes(nodes)
.links(links)
.charge(-1600)
.linkDistance(45)
.size([w, h]);
which results in a svg graph that does not scale or down despite of changes in screen or browser window size. In order to make it responsive (i.e. automatically resizes itself), I tried using viewBox
and preserveAspectRatio
attributes:
尽管屏幕或浏览器窗口大小发生变化,这会导致 svg 图形不会缩放或缩小。为了使其具有响应性(即自动调整自身大小),我尝试使用viewBox
和preserveAspectRatio
属性:
var svg = d3.select("#viz").append("svg")
.attr("id", "playgraph")
.attr("width", w)
.attr("height", h)
.attr("viewBox", "0, 0, 600, 400")
.attr("preserveAspectRatio", "xMidYMid meet");
Unfortunately, this didn't work as nothing happens when I adjust the browser window size. I wonder if the .size([w, h])
of the force graph has anything to do with this.
不幸的是,这不起作用,因为当我调整浏览器窗口大小时没有任何反应。我想知道力图的 是否.size([w, h])
与此有关。
Please shed some light on how to use viewBox
and preserveAspectRatio
attributes with force layout graphs.
请阐明如何使用力布局图viewBox
和preserveAspectRatio
属性。
回答by methodofaction
The problem is not within .size()
, it's that you are stating the SVG dimensions in .attr("width", w) .attr("height", h)
. Remove these two attributes and you'll get it right...
问题不在于内.size()
,那就是你陈述SVG尺寸.attr("width", w) .attr("height", h)
。删除这两个属性,你会得到正确的......
var svg = d3.select("#viz").append("svg")
.attr("id", "playgraph")
//better to keep the viewBox dimensions with variables
.attr("viewBox", "0 0 " + w + " " + h )
.attr("preserveAspectRatio", "xMidYMid meet");
回答by Matt Jensen
The solution shown here: http://bl.ocks.org/mbostock/3355967worked well for me!
此处显示的解决方案:http: //bl.ocks.org/mbostock/3355967对我来说效果很好!
window.addEventListener('resize', resize);
function resize() {
var width = window.innerWidth, height = window.innerHeight;
svg.attr("width", width).attr("height", height);
force.size([width, height]).resume();
}
Make sure to run resize() after you have appended all your lines, nodes etc as well.
确保在附加所有行、节点等之后运行 resize()。
回答by aaaronic
Duopixel is very close to what I needed, except I don't know why he nested two <g>
elements and attached the event listeners to the outermost <g>
(also requiring an invisible rectangle behind everything to make the g react to events over its whole space).
Duopixel 非常接近我需要的东西,除了我不知道为什么他嵌套了两个<g>
元素并将事件侦听器附加到最外面<g>
(还需要在所有内容后面有一个不可见的矩形以使 g 对整个空间中的事件做出反应)。
It's easier to attach the listeners to the <svg>
itself and then you only need one internal <g>
.
将侦听器附加到它<svg>
本身会更容易,然后您只需要一个内部<g>
.
Here is my full-screen force-directed example:
这是我的全屏力导向示例:
var width = 1000,
height = 1000;
var color = d3.scale.category20();
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 + ")");
}
function draw_graph(graph) {
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.nodes(graph.nodes)
.links(graph.links)
.size([width, height])
.start();
var link = vis.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = vis.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function(d) { return color(d.group); })
.call(force.drag);
node.append("title")
.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("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
};
draw_graph(data);