2013-04-26 328 views
11

我使用Flowingdata.com的this nice force layout创建网络图。d3.js强制布局在加载后自动缩放/缩放

enter image description here

enter image description here

enter image description here

我图目前显示与他们的关系,5和750之间的节点。它适用于一些自定义更改以适应我的需求。但有一件事我无法去工作。我有一个viewBoxpreserveAspectRatio自动适合它所在的容器。但取决于节点的数量总是有一些节点围绕边缘(主要是顶部和底部)被切断。如果节点非常少,则会在中间显示它们,周围有巨大的空间(这是一个很大的容器)。

是否有任何方法可以自动缩放或缩放布局以自动适应?因此,一个大布局有点缩小,一个小布局放大。我有一个缩放事件设置,所以滚动和平移就像一个魅力。但它可以自动做到这一点,以适应内容?

的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'); 

回答

1

您可以在节点迭代;获取所有节点的最大和最小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画布的宽度和hieight,和d我想中心的节点。

而不是集中在d.x,d.y,你应该计算平均值x和y。并计算缩放比例,以使图形的宽度(和高度)适合SVG的宽度(和大小)选择两者中较大的缩放比例。

+2

听起来像是一种很好的开始方式。但是,您是从哪里获得缩放对象的?我试过d3.behavior.zoom和d3.event,但第一个没有scale()方法,后者说不能调用null的方法'scale'。 – DaFrenk 2013-04-26 14:15:55

1

你的代码应与此类似

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); 

只为X轴此代码工作。因为“全球圈”RX === RY。如果不适合你,那么你可以为yAxis添加相同的逻辑var startY。此外,您还需要考虑圆节点的cr来调整初始坐标。

8

迄今为止所有其他答案都需要访问数据,并对其进行迭代,因此复杂度至少为O(nodes)。我一直在寻找并找到一种完全基于已经渲染的视觉尺寸的方式,getBBox()希望是O(1)。它的内容或布局方式无关紧要,只是它的大小和父容器的大小。我设法此基础上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); 
} 
+0

我并不是想打扰你,但我一直在尝试使用你的解决方案过去两天。问题是,从getBBox()我得到的svg g对象的实际大小是30x70px,而不是什么不显示哪些将是大约2000x1700px – Higeath 2016-07-08 17:10:05

+0

@Higeath查看完整的示例活在http://bl.ocks.org/ TWiStErRob/b1c62730e01fe33baa2dea0d0aa29359 – TWiStErRob 2016-07-09 12:03:31

+0

我知道这个评论有点晚了,但你的答案是一个总的救命。谢谢@TWiStErRob! – Terry 2016-10-03 15:34:10

1

这里有两个例子:

力布局,支持自动变焦(画布):

https://vida.io/documents/pT3RDxrjKHLQ8CQxi

力布局,支持自动变焦( SVG)

https://vida.io/documents/9q6B62xQgnZcYYen2

对SVG执行缩放和绘制的函数:

function scaleAndDraw() { 
    var xExtent = d3.extent(d3.values(nodes), function(n) { return n.x; }), 
     yExtent = d3.extent(d3.values(nodes), function(n) { return n.y; }); 

    if ((xExtent[1] - xExtent[0]) > config.width) { 
    scaleX = (xExtent[1] - xExtent[0])/config.width; 
    scaleY = (yExtent[1] - yExtent[0])/config.height; 

    scale = 1/Math.max(scaleX, scaleY); 

    translateX = Math.abs(xExtent[0]) * scale; 
    translateY = Math.abs(yExtent[0]) * scale, 
    svg.attr("transform", "translate(" + 
     translateX + "," + translateY + ")" + 
     " scale(" + scale + ")"); 
    } 

    draw(); 
} 
+0

这是唯一可行的解​​决方案。你救了我的论文先生:) – Rosiana 2016-12-15 13:55:20