d3.js force layout auto zoom/scale after loading

后端 未结 3 1093
梦毁少年i
梦毁少年i 2020-12-15 05:24

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

\"enter

3条回答
  •  别那么骄傲
    2020-12-15 06:11

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

提交回复
热议问题