d3.js加载后强制布局自动缩放/缩放

DaF*_*enk 19 javascript d3.js force-layout

我正在使用Flowingdata.com的这个很好的力布局来创建网络图.

在此输入图像描述

在此输入图像描述

在此输入图像描述

我的图表当前显示了5到750个节点及其关系.它适用于一些自定义更改,以满足我的需求.但有一点我无法开展工作.我有一个viewBox具有preserveAspectRatio自动适应容器它.但是这取决于节点的数量总是有围绕得到切断边缘(主要是顶部和BUTTOM)一些节点.如果节点很少,它会在中间显示它们周围有一个巨大的空白区域(它是一个很大的容器).

有没有办法自动缩放或缩放布局以自动适应?这样一个大的布局会有所缩小,一个小的布局会放大.我有一个缩放事件设置,所以滚动和平移就像一个魅力.但它可以自动执行此操作以适应内容吗?

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');
Run Code Online (Sandbox Code Playgroud)

TWi*_*Rob 19

迄今为止所有其他答案都需要访问数据,并通过它进行迭代,因此复杂性至少是如此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);
}
Run Code Online (Sandbox Code Playgroud)

编辑:以上工作在D3 v3.在D3 v4和v5中更改了缩放,因此您必须对最后一部分(下面的代码console.trace)进行一些小的更改:

    var transform = d3.zoomIdentity
        .translate(translate[0], translate[1])
        .scale(scale);

    root
        .transition()
        .duration(transitionDuration || 0) // milliseconds
        .call(zoom.transform, transform);
Run Code Online (Sandbox Code Playgroud)

  • @TWiStErRob在旁注中,Firefox有一种非常讨厌的行为,拒绝返回内联SVG的准确客户端维度.[一个小修改](http://stackoverflow.com/questions/13122790/how-to-get-svg-element-dimensions-in-firefox)使你的脚本也在Firefox中工作;)例如`fullWidth = parent.clientWidth || parent.parentNode.clientWidth`而不仅仅是`fullWidth = parent.clientWidth`. (3认同)
  • 要调整 D3.js 版本 6 的代码,只需将最后一行替换为 `.attr("transform", transform);` (3认同)

Mar*_*cek -1

您可以迭代节点;获取所有节点的最大和最小 x 和 y 值,并计算所需的缩放和平移以覆盖 SVG 大小内的所有可视化。

我有一段代码将图集中到给定的节点;这可能会帮助你得到一个想法。

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);
Run Code Online (Sandbox Code Playgroud)

其中 w、h 是我的 SVG 画布的宽度和高度,d 是我想要居中的节点。

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

  • 听起来是一个很好的开始方式。然而,你从哪里得到缩放对象呢?我尝试了 d3.behavior.zoom 和 d3.event 但第一个没有方法 scale() ,后者说不能调用 null 的方法“scale”。 (4认同)