D3 Tree的初始数据无法正确显示

时间:2016-02-25 03:03:21

标签: javascript d3.js

我设法使用d3制作一个自下而上的家谱,添加,删除工作正常,但是当我尝试加载嵌套子项的初始数据超过2或者超过根时,可视化所述数据中断。

  1. 如何在给定多个嵌套的情况下获取初始化数据以进行可视化 孩子?我让它错过了什么?

  2. 当节点达到3级以上时,如何计算和设置节点之间的分隔?

  3. 我已经完成了输入,更新和退出,因为它应该我认为,这使得它可以添加,删除。 JSFiddle for only root data, with adding and deletingOnly Root Initilize, Works Fine

    当我用超过1个孩子初始化数据时,可视化开始中断,而不是最初显示所有关系,它只显示一个关系。 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; });          
      }
    

1 个答案:

答案 0 :(得分: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: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