2013-04-26 241 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