提示覆盖树布局以在d3.js中创建经典的OrgChart布局

时间:2016-03-15 22:33:27

标签: d3.js

我正在创建一个基于树状布局的动态(交互式点击展开/折叠)组织结构图,但是我已经明确定义了自己的节点布局和链接例程,以允许自上而下和弯头路径链接。 我现在需要添加一个功能来支持混合模式布局,将一些节点垂直放置在它们的父节点下,而不是在较低的Y偏移上和相同的X平面上(水平地)显示它们。

我刚刚创建了一个原型,以最底层的深度工作,并觉得这是很好理解和功能。获取最大深度并与当前进行比较已经完成了这个,并且计算动态间距函数的技巧非常棘手。

有谁可以解释这种偏移如何与分离功能一起工作?我发现我需要将最底部的节点设置为0,因为任何其他值将导致宽度指数增长,因为更多节点被添加为子节点,即父节点被进一步推开。为了解决这个问题,我还为父母设置了静态间距值。

我尚未开始研究的另一件事是将混合布局结合起来如何管理高度。所以我想知道......我是否应该使用间距/分离功能,或者只是在我的更新中手工制作放置并输入数据事件。

这是我接受它的地方,对最初的结果感到满意 enter image description here

如果有人可以分享一些关于推出自定义布局的想法或经验,那就太好了。

非常感谢! 如果有人感兴趣,则使用以下代码来实现混合布局。

分离功能

    .separation(function (a, b) {

        var separation = a.parent == b.parent ? 1.2 : 2;
        //return separation;

        //-- SKIPPING THIS CODE 
        var nodeDepth = a.depth,
            maxDepth = getMaxDepth(ancestorRoot) - 1;

        if (maxDepth !== 0) {
            var aX = Number(a.x || 0).toFixed(2),
            aY = Number(a.y || 0).toFixed(2),
            bX = Number(b.x || 0).toFixed(2),
            bY = Number(b.y || 0).toFixed(2);

            if (nodeDepth === maxDepth) {
                if ((a.parent.ID !== b.parent.ID) && (a.parent.depth === b.parent.depth)) {
                    //--Parents are at the same depth so we can adjust accordingly.
                    var parentIndex = "";
                    console.error("\tDifferent parents, but both parents are at the same depth so the separation should be marginly adjusted.");
                    separation = .1;
                }
                else if ((a.parent.ID === b.parent.ID)) {
                    console.error("\tSame parents, no separation needed.");
                    console.warn("#Separation - " + separation + " For:\n\t" + a.Props.DisplayName + " [" + aX + "," + aY + "]" + " and " + b.Props.DisplayName + " [" + bX + "," + bY + "]");
                    separation = 0;
                }
            }
            else if (nodeDepth === (maxDepth - 1)) {
                separation = 1.5;
                console.warn("#Separation - " + separation + " For:\n\t" + a.Props.DisplayName + " [" + aX + "," + aY + "]" + " and " + b.Props.DisplayName + " [" + bX + "," + bY + "]");
            }
        }
        return separation;
        //return 100;
    });

NODE PLACEMENT

function nodeTransformEnd(d, depth, i) {
    //console.info("End node transform for " + d.Props.DisplayName);
    var x0 = d.px = d.x = (((width / 2) + d.x) - boxWidth / 2);
    var y0 = d.py = d.y = (((height / 2) + d.y) - boxHeight / 2);

    var nodeDepth = d.depth,
        maxDepth = getMaxDepth(ancestorRoot) - 1;

    if (maxDepth === 0) maxDepth = -1;

    if (nodeDepth === maxDepth) {
        var index = d.parent.children.indexOf(d);
        console.log(d.Props.DisplayName +  " -> " + d.parent.Props.DisplayName + " (Depth=" + d.parent.depth + ")");
        console.log("\t Current depth: " + d.depth + ", Max depth: " + maxDepth +  ", Sibling index: " + index);
        //console.log("\t " + d.Props.DisplayName + " is index of " + index);
        //return "translate(" + x0 + "," + y0 + ")";
        x0 = d.px = d.x = (d.parent.x - ((boxWidth / 2) + 50));
        y0 = d.py = d.y = (y0 + (index * (50 + 80)));
    }


    return "translate(" + x0 + "," + y0 + ")";

} // end: util- nodeTransformEnd

LINK PATH

function drawElbowLineEnd(d, depth, i) {
    var nodeLinks = calculateNodeLinkPoints(d, depth, i),
        s = nodeLinks.source,
        t = nodeLinks.target;

    var path = [];

    var nodeDepth = d.target.depth,
        maxDepth = getMaxDepth(ancestorRoot) - 1;

    if (maxDepth === 0) maxDepth = -1;

    if (nodeDepth === maxDepth) {
        //-- Start at middle of parent node
        path.push("M", s.x, ",", s.y);
        //-- Vertical to middle of target node
        path.push("V", (t.y + (boxHeight / 2)));
        //-- Meet to the side of the child node
        path.push("H", (t.x - boxWidth / 2));

        //console.log(path.join(" "));
    }
    else {
        //-- Normal horizontal layout - elbow
        path.push("M", s.x, ",", s.y,
           "V", ((s.y + t.y) / 2),
           "H", t.x,
           "V", t.y);
    }

    return path.join("");
} // end: util- drawElbowLineEnd

获得最大深度

    var getMaxDepth = function getMaxDepth(startNode){
        startNode = startNode || ancestorRoot;
        var depth=0;
        if(startNode.children){
            startNode.children.forEach(function(child){
                var maxDepthForCurrentTree = getMaxDepth(child);
                if(maxDepthForCurrentTree > depth){
                    depth = maxDepthForCurrentTree;
                }
            });
        }
        return depth+1; 
    };

0 个答案:

没有答案