2016-02-25 66 views
0

我设法使用d3来创建一个自下而上的家族树,添加,删除工作正常,但是当我尝试加载嵌套的孩子的初始数据更多比根部大2或更多,所述数据的可视化中断。D3树的初始数据没有被正确显示

  1. 我该如何初始化数据可视化赋予多重嵌套 孩子?我错过了什么让它工作?

  2. 如何计算并设置节点之间的距离,当它获得3个以上的级别?

我已经做了输入,更新和退出,因为它,我应该想,这导致对作品的添加,删除。 JSFiddle for only root data, with adding and deletingOnly Root Initilize, Works Fine

当我用一个以上的孩子启动数据时,可视化开始打破,而不是最初显示所有关系,它只显示一个关系。 The fiddle of said problem。因此: Only one relationships shows

什么,我想实现当它最初使用嵌套子数据是嵌套关系的可视化加载,如上面的情况应该是: The correct Relationship that it should show

数据:

{ 
    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; });   
    } 
+0

类似的帖子可能会帮助(http://stackoverflow.com/questions/31245751/如何做,你创建一个家庭树在D3 - JS) –

+0

@JustinWilson,同时创建我的家庭树我看看,也许我错过了一些东西,我不能完全掌握缺少的部分。 – diehell

回答

0

好吧,我似乎没有为每个成员发起id,因为生成节点的重要部分高度依赖于id(以及你可以将它改为任何真正独特的东西)。

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为这样的:

{ 
      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