d3.js折叠力布局,所有节点都已折叠

时间:2014-01-02 15:52:24

标签: javascript json d3.js treenode directed-graph

我一直在尝试使用我编写的json文件实现定向强制布局。在我尝试使所有节点崩溃之前,它正常工作。我已经为所有节点声明了一个名为“index”的属性,指示它们属于哪个级别的树(root的索引是0,它的子节点是1,等等) 我猜测节点的“索引”属性存在问题,因为当我第一次启动页面时,它们的值是正确的,但是当我崩溃并重新打开一个节点时,相关节点的索引值会发生变化,它会不再正确地绘制链接。

为什么每当我点击任何内容时它会不断更改从json获取的索引值的任何想法,或者您是否有任何我可能会考虑解决问题的参考项目?

谢谢,

这是我的脚本代码:

var indx = 0;

var width = 1260, height = 1220, root;

var force = d3.layout.force().linkDistance(80).charge(-300)
        .gravity(.05).size([ width, height ]).on("tick", tick);

var svg = d3.select("#chart").append("svg")
        .attr("width", width).attr("height", height);

var link = svg.selectAll(".link"), node = svg
        .selectAll(".node");

var text = svg.selectAll(".link");


d3.json("graph.json", function(error, json) {

    root = json;

    update();

});

function toggle(d) {

    indx = d.index;

    if (d.children) {
        d._children = d.children;
        d.children = null;
    } else {
        d.children = d._children;
        d._children = null;
    }
    update();
}

function prepareLinks(allNodes) {

    var newLinks = new Array();

    var allLinks = d3.layout.tree().links(allNodes);

    for ( var i = 0; allLinks.length > i; i++) {

        if (allLinks[i].source.index <= indx) {
            console.log("source : " + allLinks[i].source.index
                    + "-" + allLinks[i].source.name);
            newLinks.push(allLinks[i]);
        }
        console.log(allLinks[i].target.index + "-"
                + allLinks[i].target.name);

    }

    for ( var i = 0; newLinks.length > i; i++) {

            console.log("newLinks : " + newLinks[i].source.index
                    + "-" + newLinks[i].source.name);
        console.log(newLinks[i].target.index + "-"
                + newLinks[i].target.name);

    }

    return newLinks;

}

function update() {

    var nodes = flatten(root, indx);
    var links = prepareLinks(nodes);


    // Restart the force layout.
    force.nodes(nodes).links(links).start();

    // Update links.   
    link = link.data(links, function(d) {

        return d.target.id;

    });

    link.exit().remove();

    link.enter().insert("line", ".node").attr("class", "link");

    svg.selectAll("g.ltext").remove();

    text = svg.append("svg:g").selectAll("g").data(links);

    text.enter().append("svg:g").attr("class", "ltext");

    text.append("svg:text").attr("class", "linktext").attr(
            "dx", 5).attr("dy", ".35em").text(
            function(d) {

                return d.source.type;
            });

    // Update nodes.
    node = node.data(nodes, function(d) {
        return d.id;
    });

    node.exit().remove();

    var nodeEnter = node.enter().append("g").attr("class",
            "node").on("click", function(d) {
        toggle(d);
        update(d);
    }).call(force.drag);

    nodeEnter.append("circle").attr("r", function(d) {
        return Math.sqrt(d.size) / 10 || 10;
    });

    nodeEnter.append("text").attr("dy", ".35em").text(
            function(d) {
                return d.name;
            });

    node.select("circle").style("fill", color);

}

function tick() {

    link.attr("x1", function(d) {
        return d.target.x;
    }).attr("y1", function(d) {
        return d.target.y;
    }).attr("x2", function(d) {
        return d.source.x;
    }).attr("y2", function(d) {
        return d.source.y;
    });

    node.attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
    });

    text.attr("transform", function(d) {
        var sourcex = d.source.x;
        var sourcey = d.source.y;
        var targetx = d.target.x;
        var targety = d.target.y;

        return "translate(" + (sourcex + targetx) / 2 + ","
                + (sourcey + targety) / 2 + ")";
    });

}

function color(d) {
    return d._children ? "#BA8343" // collapsed package
    : d.children ? "#7C4C6B" // expanded package
    : "#6F704A"; // leaf node
}

// Toggle children on click.

function click(d) {
    if (d3.event.defaultPrevented)
        return; // ignore drag

    if (d.children) {
        d._children = d.children;
        d.children = null;
    } else {
        d.children = d._children;
        d._children = null;
    }

    update(d);
}

// Returns a list of all nodes under the root.
function flatten(root, indx) {

    var nodes = [], i = 0;

    function recurse(node) {
        console.log("flatten'da başta index: " + node.index
                + "ad " + node.name);
        if (node.children) {

            node.children.forEach(recurse);

        }
        if (!node.id)
            node.id = ++i;

        if (indx >= node.index || indx + 1 == node.index) {

            nodes.push(node);
            //                          console.log("flatten'da index: "+ node.index+ "ad "+ node.name);
        }
    }

    recurse(root);
    return nodes;
}

以下是我的json文件中的一个示例:

{
 "name": "Data Mining","type":"related","index":2,
 "children": [
  {
  "name": "Yapay Sinir Ağları", "size": 7074,"type":"related","index":3,
    "children": [
        {
        "name": "Compututional Intelligence","type":"narrower","index":4,
        "children":[
            {"name": "Genetik Algoritmalar", "size": 7074,"type":"related","index":5},
            {"name": "Bulanık Mantık", "size": 7074,"type":"related","index":5},
            {"name":"Soft Computing","type":"related","index":5,
                "children": [
                    {"name": "Esnek Hesaplama", "size": 7074,"type":"related","index":6}
                ]
             } 
         ]
        }
     ]
 }

1 个答案:

答案 0 :(得分:1)

问题很可能是index是d3强制布局中节点的保留属性,并且在更新nodes属性时会被覆盖。

  

<强> force.nodes([节点])

     

如果指定了节点,则将布局的关联节点设置为   指定的数组。如果未指定节点,则返回当前数组,   默认为空数组。每个节点都有以下内容   属性:

     

index - 节点数组中节点的从零开始的索引。

     

x - 当前节点位置的x坐标。

     

y - 当前节点位置的y坐标。

     

px - 前一个节点位置的x坐标。

     

py - 前一个节点位置的y坐标。

     

fixed - 一个布尔值,指示节点位置是否被锁定。

     

重量 - 节点重量;相关链接的数量。

     

在将节点传递给之前,不需要设置这些属性   布局;如果未设置,则将初始化合适的默认值   调用start时的布局。 但是,请注意,如果你是   在节点上存储其他数据时,您的数据属性不应该   与布局使用的上述属性冲突。

Documentation

要防止冲突,请将json中的index属性重命名为其他内容。在我自己的项目中,我指的是给定节点与根的距离,因为它是depth