d3.js可折叠力布局,所有节点折叠 [英] d3.js collapsible force layout with all the nodes collapsed

查看:131
本文介绍了d3.js可折叠力布局,所有节点折叠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试使用我编写的json文件实现定向力布局。之前,我试图让它开始所有节点崩溃,它工作正常。我已经为所有的节点声明了一个名为index的属性,指示它们所属的树的级别(根的索引是0,它的子节点是1,等等)
我猜想有一个问题与节点的索引属性,因为当我第一次启动我的页面的值是正确的,但当我崩溃和重新打开一个节点的相关节点的索引值改变,它不再正确绘制链接。 p>

任何想法,为什么它不断更改索引值,从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);


//重新启动强制布局。
force.nodes(nodes).links(links).start();

//更新链接。
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;
});

//更新节点。
node = node.data(nodes,function(d){
return d.id;
});

node.exit()。remove();

var nodeEnter = node.enter()。append(g)。attr(class,
node
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。 attr(x2,function(d)); attr(x2; function.x;
})。attr(y1,function(d){
return d.target.y;
} {
return d.source.x;
})。attr(y2,function(d){
return d.source.y;
});

node.attr(transform,function(d){
returntranslate(+ 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;

returntranslate(+(sourcex + targetx)/ 2 +,
+(sourcey + targety)/ 2 +);
});

}

函数color(d){
return d._children? #BA8343//折叠包
:d.children? #7C4C6B// expanded package
:#6F704A; //叶节点
}

//点击切换子节点。

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

//返回根下所有节点的列表。
function flatten(root,indx){

var nodes = [],i = 0;

function recurse(node){
console.log(flatten'dabaştaindex:+ 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);
返回节点;
}

这里是我的json文件的一个例子:

  {
name:Data Mining,type:related,index:2,
children:[
{
name:Yapay SinirAğları,size:7074,type:related,index:3,
children :[
{
name:Computational Intelligence,type:narrower,index:4,
children:[
{名称:Genetik Algoritmalar,size:7074,type:ated,index:5},
{name:BulanıkMantık,size:7074, type:ated,index:5},
{name:Soft Computing,type:ated,index:5,
children [
{name:Esnek Hesa​​plama,size:7074,type:related,index:6}
]
}
]
}
]
}


解决方案>

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


force.nodes([nodes])



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



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



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



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

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



py - 上一个节点位置的y坐标。 / p>

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





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


文档



为避免冲突,请将json中的 index 属性重命名为其他值。在我自己的项目中,我指的是给定节点与根之间的距离,因为它深度


I've been trying to implement a directed force layout using a json file that I've written. Before I tried to make it begin with all nodes collapsed, it was working properly. I've declared a property called "index" for all the nodes, indicating which level of the tree they belong (root's index is 0, it's children are 1, etc.) I'm guessing that there is a problem with "index" property of the nodes because when I first start my page their values are correct, but when I collapse and re-open one a node the index values of related nodes change and it does not draw the links properly anymore.

Any ideas on why it keeps changing the index values that are taken from json whenever I click anything, or do you have any reference projects I might look into to solve the problem?

Thanks,

Here is my script code:

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

And here is an example from my json file:

{
 "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}
                ]
             } 
         ]
        }
     ]
 }

解决方案

Most likely the problem is that index is a reserved property of nodes in d3's force layout, and it's getting overwritten when the nodes property is updated.

force.nodes([nodes])

If nodes is specified, sets the layout's associated nodes to the specified array. If nodes is not specified, returns the current array, which defaults to the empty array. Each node has the following attributes:

index - the zero-based index of the node within the nodes array.

x - the x-coordinate of the current node position.

y - the y-coordinate of the current node position.

px - the x-coordinate of the previous node position.

py - the y-coordinate of the previous node position.

fixed - a boolean indicating whether node position is locked.

weight - the node weight; the number of associated links.

These attributes do not need to be set before passing the nodes to the layout; if they are not set, suitable defaults will be initialized by the layout when start is called. However, be aware that if you are storing other data on your nodes, your data attributes should not conflict with the above properties used by the layout.

Documentation

To prevent the conflict, rename the index property in your json to something else. In my own project I'm referring to the distance of a given node from the root as it's depth.

这篇关于d3.js可折叠力布局,所有节点折叠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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