我正在使用Flowingdata.com的this nice force layout来创建网络图。



我的图表当前显示了5到750个节点及其关系。它与一些自定义更改很好,以满足我的需求。然而,有一件事我不能去做。我有一个带有preserveAspectRatio的viewBox,可以自动适应它所在的容器。但是,根据节点的数量,总是会有一些节点在边缘(主要是顶部和底部)被截断。如果有很少的节点,它会在中间显示它们,周围有巨大的空白空间(这是一个很大的容器)。
有没有办法自动缩放或缩放布局,使其自动适应?所以一个大的布局会被放大,一个小的布局会被放大。我有一个缩放事件设置,所以滚动和平移的工作就像一个护身符。但它能自动执行此操作以适应内容吗?
d3.js启动代码:
vis = d3.select(selection)
.append("svg")
.attr("viewBox", "0 0 " + width + " " + height )
.attr("preserveAspectRatio", "xMidYMid meet")
.attr("pointer-events", "all")
.call(d3.behavior.zoom().scaleExtent([.1, 3])
.on("zoom", redraw)).append('g');发布于 2015-07-06 08:13:15
到目前为止,所有其他答案都需要访问数据,并对其进行迭代,因此复杂性至少为O(nodes)。我继续寻找,找到了一种完全基于已经渲染的视觉大小的方法,希望是O(1)的getBBox()。它里面有什么或者它是如何布局的并不重要,只关心它的大小和父容器的大小。我设法在http://bl.ocks.org/mbostock/9656675的基础上写出了这个
var root = // any svg.select(...) that has a single node like a container group by #id
function lapsedZoomFit(ticks, transitionDuration) {
for (var i = ticks || 100; i > 0; --i) force.tick();
force.stop();
zoomFit(transitionDuration);
}
function zoomFit(transitionDuration) {
var bounds = root.node().getBBox();
var parent = root.node().parentElement;
var fullWidth = parent.clientWidth || parent.parentNode.clientWidth,
fullHeight = parent.clientHeight || parent.parentNode.clientHeight;
var width = bounds.width,
height = bounds.height;
var midX = bounds.x + width / 2,
midY = bounds.y + height / 2;
if (width == 0 || height == 0) return; // nothing to fit
var scale = 0.85 / Math.max(width / fullWidth, height / fullHeight);
var translate = [fullWidth / 2 - scale * midX, fullHeight / 2 - scale * midY];
console.trace("zoomFit", translate, scale);
root
.transition()
.duration(transitionDuration || 0) // milliseconds
.call(zoom.translate(translate).scale(scale).event);
}编辑:以上内容适用于D3 v3。
var transform = d3.zoomIdentity
.translate(translate[0], translate[1])
.scale(scale);
root
.transition()
.duration(transitionDuration || 0) // milliseconds
.call(zoom.transform, transform);发布于 2015-01-05 19:51:52
您的代码应该与以下代码类似
vis = d3.select(selection)
.append("svg")
.attr("viewBox", "0 0 " + width + " " + height )
.attr("preserveAspectRatio", "xMidYMid meet")
.attr("pointer-events", "all")
.call(zoomListener)
.on("zoom", redraw));
var mainGroup = vis.append('g');
function zoom() {
mainGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
var zoomListener = d3.behavior.zoom().on("zoom", zoom);
var xArray = YOUR_NODES.map(function(d) { //YOUR_NODES is something like json.nodes after forse.end()
return d.x
});
var minX = d3.min(xArray);
var maxX = d3.max(xArray);
var scaleMin = Math.abs(width / (maxX - minX));
var startX = (minX) / scaleMin;
var startY = 50 / scaleMin;
// Same as in the zoom function
mainGroup.attr("transform", "translate(" + [startX, startY] + ")scale(" + scaleMin + ")");
// Initialization start param of zoomListener
zoomListener.translate([startX, startY]);
zoomListener.scale(scaleMin);
zoomListener.scaleExtent([scaleMin, 1])
vis.call(zoomListener);此代码仅适用于xAxis。因为“环球圈”svg RX === RY。如果它不适合您,那么您可以为yAxis var startY添加相同的逻辑。此外,您还需要考虑圆形节点的cr来调整初始坐标。
发布于 2013-04-26 21:33:05
您可以遍历节点;获得所有节点的最大和最小x和y值,并计算所需的缩放和平移,以覆盖SVG大小内的所有viz。
我有一段代码,它将图形集中到给定的节点;这可能会帮助您获得一个想法。
zs = zoom.scale()
zt = zoom.translate();
dx = (w/2.0/zs) - d.x;
dy = (h/2.0/zs) - d.y;
zoom.translate([dx, dy]);
zoom.scale(zs);其中w,h是我的SVG画布的宽度和高度,d是我想要居中的节点。
不是以d.x,d.y为中心,而是计算x和y的平均值,并计算缩放比例,使图形的宽度(和高度)适合SVG的宽度(和大小),选择两者中较大的缩放比例。
https://stackoverflow.com/questions/16236600
复制相似问题