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

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

问题描述

我使用 :

  var root = //任何具有单个节点(如容器组)的svg.select(...) 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) 。事件);
}


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

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

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