d3.js 加载后强制布局自动缩放/缩放 [英] d3.js force layout auto zoom/scale after loading

查看:43
本文介绍了d3.js 加载后强制布局自动缩放/缩放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用:

var root =//任何具有单个节点的 svg.select(...),如 #id 的容器组函数 lapsedZoomFit(ticks, transitionDuration) {for (var i = ticks || 100; i > 0; --i) force.tick();强制停止();zoomFit(transitionDuration);}功能 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,高度 = bounds.height;var midX = bounds.x + width/2,midY = bounds.y + height/2;if (width == 0 || height == 0) 返回;//没有合适的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);根.过渡().duration(transitionDuration || 0)//毫秒.call(zoom.translate(translate).scale(scale).event);}

以上适用于 D3 v3.缩放在 D3 v4 和 v5 中发生了变化,因此您必须对最后一部分(console.trace 下方的代码)进行一些小的更改:

 var transform = d3.zoomIdentity.translate(translate[0], translate[1]).规模(规模);根.过渡().duration(transitionDuration || 0)//毫秒.call(zoom.transform, 变换);

I'm using this nice force layout from Flowingdata.com to create a network diagram.

My diagram currently shows between 5 and 750 nodes with their relations. It works great with some custom changes to fit my needs. However one thing I can't get to work. I have a viewBox with preserveAspectRatio to auto fit the container it is in. But depending on the amount of nodes there are always some nodes around the edges (mainly top and buttom) that get cut off. And if there are very little nodes, it shows them in the middle with huge empty space around it (it's a big container it's in).

Is there any way to auto zoom or scale the layout to auto fit? So that a big layout gets somewhat zoomed out and a small layout zoomed in. I have a zoom event setup so scrolling and panning works like a charm. But can it automatically do that to fit the contents?

The d3.js startup code:

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

解决方案

All the other answers to date require access to data, and iterates through it so the complexity is at least O(nodes). I kept looking and found a way that is solely based on already rendered visual size, getBBox() which is hopefully O(1). It doesn't matter what's in it or how it's laid out, just its size and the parent container's size. I managed to whip up this based on 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);
}

EDIT: The above works in D3 v3. Zoom is changed in D3 v4 and v5, so you have to make some minor changes to the last portion (the code below console.trace):

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

    root
        .transition()
        .duration(transitionDuration || 0) // milliseconds
        .call(zoom.transform, transform);

这篇关于d3.js 加载后强制布局自动缩放/缩放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆