D3树的初始数据无法正确可视化 [英] Initial Data for D3 Tree are not properly visualize

查看:80
本文介绍了D3树的初始数据无法正确可视化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我设法使用d3制作了一个自下而上的家谱,添加,删除都按原样进行,但是当我尝试加载嵌套子项比根子多于2或更多的初始数据时,可视化所述数据中断.

I managed to use d3 to make a bottom up family tree, the adding, deletion works fine as it is, but when i try to load initial data that have nested children to be more than 2 or more than the root, visualization of said data breaks.

  1. 如何获取初始化数据以可视化给定的多个嵌套 孩子们?我错过了什么才能使它正常工作?

  1. How do i get the initialize data to visualize given multiple nested children? What did i missed in getting it to work?

当节点超过3个级别时,如何计算和设置节点之间的间隔?

我已经按照自己的想法完成了输入,更新和退出操作,从而使其可以添加,删除. JSFiddle仅适用于根数据,以及添加和删除.

I've done the enter,update and exit as it should i think, resulting it to works in adding,deleting. JSFiddle for only root data, with adding and deleting.

当我初始化一个有多个孩子的数据时,可视化开始中断,而不是最初显示所有关系,而是仅显示一个关系. 上述问题的小提琴.因此:

When i initiliaze the data with more than 1 children, the visualization started to breaks, instead of initially showing all the relationships it only shows one relationship. The fiddle of said problem. As such:

当它最初加载嵌套子数据时,我想要实现的是嵌套关系的可视化,因为上面的情况应该是:

What i wanted to achieve when it initially load with nested children data are the visualization of the nested relationships, as situation above it should be:

数据:

{
     patient_name: "Adam Farish",
     reference_id: "199210291",
     relationship: "",
     pc_id: "121292",
     consanguineous_marriage: false,
     children: [{
           patient_name: "Adam Father",
            reference_id: "199210291",
            relationship: "",
            pc_id: "121292",
            consanguineous_marriage: false,
            children: [],
            problems: [{
              id: 0,
              name: "cleft lip",
              impact: "disease",
              remarks: "Need constant monitoring."
            },
            {
              id: 1,
              name: "cleft palate",
              impact: "carrier",
              remarks: "Need constant monitoring."
            }]
        },{
           patient_name: "Adam Mother",
            reference_id: "199210291",
            relationship: "",
            pc_id: "121292",
            consanguineous_marriage: false,
            children: [],
            problems: [{
              id: 0,
              name: "cleft lip",
              impact: "disease",
              remarks: "Need constant monitoring."
            },
            {
              id: 1,
              name: "cleft palate",
              impact: "carrier",
              remarks: "Need constant monitoring."
            }]
        }
 ],
     problems: [{
       id: 0,
     name: "cleft lip",
     impact: "disease",
     remarks: "Need constant monitoring."
     },
     {
       id: 1,
     name: "cleft palate",
     impact: "carrier",
     remarks: "Need constant monitoring."
     }]
    }

D3家族树的代码:

var margin = {top: 140, right: 10, bottom: 140, left: 10};
    var height = 600;
    var width = 800;
    var rectW =  150;
    var rectH = 130;

    var tree = d3.layout.tree().size([width - 20, height - 60]);

    // var root = {};
    // get the tree layout
    var root = {
     patient_name: "Adam Farish",
     reference_id: "199210291",
     relationship: "",
     pc_id: "121292",
     consanguineous_marriage: false,
     children: [{
           patient_name: "Adam Father",
            reference_id: "199210291",
            relationship: "",
            pc_id: "121292",
            consanguineous_marriage: false,
            children: [],
            problems: [{
              id: 0,
              name: "cleft lip",
              impact: "disease",
              remarks: "Need constant monitoring."
            },
            {
              id: 1,
              name: "cleft palate",
              impact: "carrier",
              remarks: "Need constant monitoring."
            }]
        },{
           patient_name: "Adam Mother",
            reference_id: "199210291",
            relationship: "",
            pc_id: "121292",
            consanguineous_marriage: false,
            children: [],
            problems: [{
              id: 0,
              name: "cleft lip",
              impact: "disease",
              remarks: "Need constant monitoring."
            },
            {
              id: 1,
              name: "cleft palate",
              impact: "carrier",
              remarks: "Need constant monitoring."
            }]
        }
 ],
     problems: [{
       id: 0,
     name: "cleft lip",
     impact: "disease",
     remarks: "Need constant monitoring."
     },
     {
       id: 1,
     name: "cleft palate",
     impact: "carrier",
     remarks: "Need constant monitoring."
     }]
    };
    var nodes = tree(root);
    root.parent = root;
    root.px = root.x;
    root.py = root.y;
    root.id = 0;

    // make the diagonal link connection
    // var diagonal = d3.svg.diagonal();
    var diagonal = d3.svg.diagonal()
        // .source(function(d) { return {"x":d.source.x, "y":height - d.source.y + 12}; })            
        .target(function(d) { return {"x":d.target.x, "y": height - d.target.y - 12}; })
        .source(function(d) { return {"x":d.source.x, "y":height - d.source.y + 12}; })
        .projection(function (d) {
            return [d.x + rectW / 2, d.y + rectH /2];
    });

    var svg = d3.select("#viz").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom);

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

    function addNode(val,method,rel){
        if(method === 'add'){
          var n = {id: nodes.length,relationship:rel,problems:[]};
            if(val){
                console.log("got value");
                var p = val;
            }else{
                console.log("no value");
                var p = nodes[Math.random() * nodes.length | 0];
                console.log("First node insert",p);
            }

            if (p.children) p.children.push(n); else p.children = [n];
            nodes.push(n); 
        }else{
            if(val){
                val.parent.children.forEach(function(entry,i){
              if(entry.id === val.id){
                  val.parent.children.splice(i,1);
                  } 
                });
                nodes.forEach(function(e,n){
                    if(e.id === val.id){
                        nodes.splice(n,1);
                    }
                })
            }
        }
        console.log('ADD NODE RUN!');
    }

    function removeNode(v){
        console.log('remove node',v);
        if("parent" in v){
            for(var i = v.parent.children.length - 1; i >= 0; i--) {
                if(v.parent.children[i].id === v.id) {
                  v.parent.children.splice(i, 1);
                }
            }
            nodes.forEach(function(entry,i){
               if(entry.id === v.id){
                   nodes.splice(i,1);
               } 
            });
            console.log('value',v);
            console.log('nodes',nodes);
        }
    }

    var duration = 750
    // var timer = setInterval(update, duration);

    update();

    function update(v,method,rel) {
    //   if (nodes.length >= 2) return clearInterval(timer);
    //   if (nodes.length >= 1){ 
    //       clearInterval(timer);
    //   }

    console.log("UPDATE RUNS!");

      if(method === 'add'){
        addNode(v,'add',rel);  
      }
      if(method=='remove'){
        addNode(v,'remove'); 
      }

      // Add a new node to a random parent.
      // Recompute the layout and data join.
      node = node.data(tree.nodes(root), function(d) { return d.id; });
      link = link.data(tree.links(nodes), function(d) { return d.source.id + "-" + d.target.id; });

      console.log(tree.nodes(root));

      var nodeEnter = node.enter().append("g");  

       var foreignObject = nodeEnter.append("foreignObject")
            .attr("class", "htmlObject")
            .attr("height", rectH)
            .attr("width",rectW)
            .attr("x", function(d) { return d.parent.px; })
            .attr("y", function(d) { return height - d.parent.py + 30;  });

       var familyTreeNode = foreignObject.append("xhtml:div")
            .attr("class","ft-box ft-box-male ft-box-main clearfix");

            familyTreeNode.append("xhtml:div")
            .attr("class","ft-box-btn clearfix")
            .append("xhtml:div")
            .attr("class","ft-btn-menu")
            .append("xhtml:button")
            .attr("class","ft-btn-delete")
            .attr("title","Delete")
            .attr("dropdown-toggle","")
            .attr("aria-haspopup","")
            .attr("aria-expanded","false")
            .on("click",function(d){
                console.log("DELETE THIS NODE!",d);
                update(d,"remove");
            })
            .append("xhtml:em")
            .attr("class","fa fa-close");

    var dropdownButton = familyTreeNode.append("xhtml:div")
            // .attr("class","ft-btn-menu dropdown")
            // .attr("dropdown","dropdown");
            .attr("class","ft-btn-menu dropdown")
            // .attr("dropdown","dropdown");

            dropdownButton.append("xhtml:button")
            // .attr("class","btn btn-default dropdown-toggle")
            .attr("class","ft-btn-add")
            .attr("type","button")
            .attr("data-toggle","dropdown")
            // .attr("dropdown-toggle","")
            .attr("title","Add")
            .attr("aria-haspopup","true")
            .attr("aria-expanded","false")
            // .text("Action")
            .append("xhtml:em")
            .attr("class","fa fa-plus");


    var dropdownMenu = dropdownButton
            .append("xhtml:ul")
            // .attr("class","dropdown-menu");
            // .attr("role","menu")
            .attr("class","dropdown-menu ft-btn add animated fadeInDown");

        dropdownMenu.append("xhtml:div")
            .attr("class","arrow");


    var listDropdownFather = dropdownMenu.append("xhtml:li")
            .append("xhtml:a")
            .on("click",function(d){
               console.log("Add Father",d);
                 update(d,'add','father');
            });    

        listDropdownFather.append("xhtml:em")
            .attr("class","fa fa-plus-circle");


        listDropdownFather.append("xhtml:span")
            .attr("class","ft-label-add")
            .text("Add Daddy");




    var listDropdownMother = dropdownMenu
            .append("xhtml:li")
            .append("xhtml:a")
            .on("click",function(d){
               console.log("Add Mommy",d);
               if('children' in d){
                   if(d.children[0].rel !== 'mother' && d.children.length < 2){
                        console.log('has children but not mother',d.children[0]);
                        update(d,'add','mother');   
                   }
               }
               else{
                   console.log('no children, add Mother');
                   update(d,'add','mother');
               }
            });

        listDropdownMother.append("xhtml:em")
            .attr("class","fa fa-plus-circle");


        listDropdownMother.append("xhtml:span")
            .attr("class","ft-label-add")
            .text("Add Mother");


    familyTreeNode.append("xhtml:div")
            .attr("class","ft-person-icon clearfix")
            .append("xhtml:div")
            .attr("class","ft-male-icon")
            .attr("title","Info Details")
            .on("click", function(d){
                console.log("Open Modal Box",d);
                $scope.open({d: d});
            });


    var inputText = familyTreeNode.append("xhtml:input")
            .attr("class","ft-person-name ft-name clearfix")
            .attr("style","border:none;background: transparent;")
            .attr("id","patientname")
            .attr("value",function(d){
                return d.patient_name;
            })
            .on("blur",function(d){
                // console.log('Blur!',this);
               d.patient_name = this.value;
               inputText.attr("value",d.patient_name);
               console.log(this.value);
            });

    var footer = familyTreeNode.append("xhtml:div")
            .attr("class","ft-footer clearfix");

        footer.each(function(d, i) {
            var span = d3.select(this)
                  .selectAll('span')
                  .data(d.problems);

            span.enter()
              .append("xhtml:span")
              .attr("class",function(d,i){
                  var myStr = d.name.toLowerCase();
                  var matches = myStr.match(/\b(\w)/g);
                //   console.log('APPEND',matches);
                  return "ft-disease ft-"+matches.join('');
              })
              .text(function(prob){
                  console.log('APPEND',prob);
                  var myStr = prob.name.toUpperCase();
                  var matches = myStr.match(/\b(\w)/g);
                  return matches.join('');
              })

        });



      node.exit().remove();
      link.exit().remove();

      link.enter().insert("path", "g")
            .attr("class", "link")
            .attr("x", rectW / 2)
            .attr("y", rectH / 2)
            .attr("d", function (d) {
            var o = {
                x: d.source.px,
                y: height - d.source.py
            };
            return diagonal({
                source: o,
                target: o
            });
        });

        link.exit().transition()
            .duration(duration)
            .attr("d", function (d) {
            var o = {
                x: d.source.x,
                y: height - d.source.y
            };
            return diagonal({
                source: o,
                target: o
            });
        }).remove();

      var t = svg.transition()
          .duration(duration);

      t.selectAll(".link")
          .attr("d", diagonal);

      t.selectAll(".node")
          .attr("x", function(d) { return d.px = d.x; })
          .attr("y", function(d) { return d.py = height - d.y; });

      t.selectAll(".htmlObject")
          .attr("x", function(d) { return d.px = d.x; })
          .attr("y", function(d) { return d.py = height - d.y; });          
  }

推荐答案

好吧,看来我只是未能为每个成员初始化id,因为生成节点的重要部分高度依赖于id(很好您可以将其更改为任何真正独特的内容.)

Okay, it seems that i just failed to initiate the id for each of the members, since the important part of generating the node is highly dependent on id(well u can change it to anything unique really).

node = node.data(tree.nodes(root), function(d) { return d.id; });   
link = link.data(tree.links(nodes), function(d) { return d.source.id + "-" + d.target.id; });

加载可视化所需的初始数据必须具有以下ID:

The initial data needed to load the visualization must have id as such:

{
           id:2,
           patient_name: "Adam Father",
            reference_id: "199210291",
            relationship: "",
            pc_id: "121292",
            consanguineous_marriage: false,
            children: [],
            problems: [{
              id: 0,
              name: "cleft lip",
              impact: "disease",
              remarks: "Need constant monitoring."
            },
            {
              id: 1,
              name: "cleft palate",
              impact: "carrier",
              remarks: "Need constant monitoring."
            }]
        },{
           id:3,
           patient_name: "Adam Mother",
            reference_id: "199210291",
            relationship: "",
            pc_id: "121292",
            consanguineous_marriage: false,
            children: [],
            problems: [{
              id: 0,
              name: "cleft lip",
              impact: "disease",
              remarks: "Need constant monitoring."
            },
            {
              id: 1,
              name: "cleft palate",
              impact: "carrier",
              remarks: "Need constant monitoring."
            }]
        }

工作 jsfiddle

这篇关于D3树的初始数据无法正确可视化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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