如何使 D3.js 中的强制布局图响应屏幕/浏览器大小
Posted
技术标签:
【中文标题】如何使 D3.js 中的强制布局图响应屏幕/浏览器大小【英文标题】:How to make force layout graph in D3.js responsive to screen/browser size 【发布时间】:2012-08-10 03:59:18 【问题描述】:我有一个使用强制布局的图表,但它有一个固定的宽度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]);
尽管屏幕或浏览器窗口大小发生变化,但这会导致 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");
不幸的是,这不起作用,因为当我调整浏览器窗口大小时没有任何反应。不知道力图的.size([w, h])
跟这个有没有关系。
请阐明如何将viewBox
和preserveAspectRatio
属性与强制布局图一起使用。
【问题讨论】:
您可能还想将重绘功能附加到window.onresize
这个问题已经相当老了,但对于那些觉得它有用的人,您可能还需要考虑将节点限制在有界框内。调整大小时,节点将保留在屏幕上。示例:bl.ocks.org/mbostock/1129492
【参考方案1】:
此处显示的解决方案: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();
确保在添加所有行、节点等后运行 resize()。
【讨论】:
【参考方案2】:Duopixel 非常接近我所需要的,除了我不知道他为什么嵌套了两个 <g>
元素并将事件侦听器附加到最外面的 <g>
(还需要一个不可见的矩形来让 g 反应到整个空间的事件)。
将侦听器附加到<svg>
本身更容易,然后您只需要一个内部<g>
。
这是我的全屏强制导向示例:
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);
【讨论】:
【参考方案3】:问题不在.size()
内,而是您在.attr("width", w) .attr("height", h)
中说明了SVG 尺寸。去掉这两个属性就行了……
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");
http://jsfiddle.net/aaSjd/
【讨论】:
谢谢!所以现在 svg 图像调整大小。但是,如果不设置attr("width", ...)
和attr("height", ...)
,图像的宽度/高度似乎是当前浏览器窗口的宽度/高度。有什么办法可以在其他地方设置svg
元素的这两个维度,而不影响viewBox
和preserveAspectRatio
属性?
<style type="text/css">svg display: block; width: 80%; margin: 0 auto;</style>
应该可以帮助您入门。
只是一个警告; viewBox
属性区分大小写!注意它应该是camelCase
。使用属性viewbox
将不起作用。还交叉链接其他类似的问题/答案:***.com/questions/9400615/…***.com/questions/44833788/…以上是关于如何使 D3.js 中的强制布局图响应屏幕/浏览器大小的主要内容,如果未能解决你的问题,请参考以下文章