D3.js强迫有多个父母的图形孩子

时间:2018-02-06 09:04:01

标签: javascript d3.js

我是d3.js的新手,到目前为止我只用于小图,没有太复杂。现在我想为一些部门建立一个结构,到目前为止我找不到一个问题。我正在使用d3.js强制图,在某些情况下我希望有2个父节点用于相同的节点,这是否可以吗?

您可以在此处查看我的代码:

// rest of vars
var w = document.querySelector("#vis").clientWidth - 5,
    h = document.querySelector("#vis").clientHeight - 5,
    maxNodeSize = 100,
    x_browser = 0,
    y_browser = 0,
    root;
 
var vis;
var force = d3.layout.force(); 

vis = d3.select("#vis").append("svg").attr("width", w).attr("height", h);
    

    
var json = {
 "name": "lorem ipsum",
 "size": 1200000,
 "id": "Org",
 "children": [
       {
   "hero": "lorem ipsum",
   "name": "lorem ipsum",
   "id": "GNS-Main3",
   "x": 950,
   "y": 300,
   "fixed": true,
   "children": [
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-2",
      "link": "http://marvel.com/characters/54/spider-man",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-2",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum",
      "class": "gns-2",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum",
      "class": "gns-2",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "class": "gns-2",
      "name": "lorem ipsum", 
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    }
  ]
  },
  {
   "hero": "lorem ipsum",
   "name": "lorem ipsum",
   "id": "GNS-Main",
   "x": 1400,
   "y": 600,
   "fixed": true,
   "children": [
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-1",
      "link": "http://marvel.com/characters/54/spider-man",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-1",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum",
      "class": "gns-1",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum",
      "class": "gns-1",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "class": "gns-1",
      "name": "lorem ipsum", 
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-1",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    }
  ]
  },
       {
   "hero": "lorem ipsum",
   "name": "lorem ipsum",
   "id": "GNS-Main2",
   "x": 300,
   "y": 600,
   "fixed": true,
   "children": [
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-3",
      "link": "http://marvel.com/characters/54/spider-man",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-3",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum",
      "class": "gns-3",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum",
      "class": "gns-3",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "class": "gns-3",
      "name": "lorem ipsum", 
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-3",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-3",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-3",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-3",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    },
    {
      "hero": "lorem ipsum",
      "name": "lorem ipsum", 
      "class": "gns-3",
      "link": "http://marvel.com/characters/9/captain_marvel",
      "size": 40000
    }
  ]
  },      
 ],
   
}
/*d3.json("marvel.json", function(json) {*/
 
  root = json;
  root.fixed = true;
  root.x = w / 2;
  root.y = h / 1.5;
 
 
        // Build the path
  var defs = vis.insert("svg:defs")
      .data(["end"]);
 
 
  defs.enter().append("svg:path")
      .attr("d", "M0,-5L10,0L0,5");
 
     update();

  
    
function update() {
  var nodes = flatten(root),
      links = d3.layout.tree().links(nodes);
 
  // Restart the force layout.
  force.nodes(nodes)
        .links(links)
        .gravity(0.05)
    .charge(-1500)
    .linkDistance(230)
    .friction(0.7)
    .linkStrength(function(l, i) {return 1; })
    .size([w, h])
    .on("tick", tick)
        .start();
 
   var path = vis.selectAll("path.link")
      .data(links, function(d) { return d.target.id; });
 
    path.enter().insert("svg:path")
      .attr("class", "link")
     // .style("fill", "url(#gradient6)")
      // .attr("marker-end", "url(#end)")
      .style("stroke", "#eee");
 
 
  // Exit any old paths.
  path.exit().remove();
 
 
  // Update the nodes…
  var node = vis.selectAll("g.node")
      .data(nodes, function(d) { return d.id; });
    
    
   

    
    
  // Enter any new nodes.
  var nodeEnter = node.enter().append("svg:g")
      .attr("class", function(d) { return "node " + d.class })
      .attr("id", function(d) { return d.id }) // Custom id
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
      .on("click", click)
      .call(force.drag);
 
  // Append a circle
  nodeEnter.append("svg:circle")
      .attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
      .style("fill", "#eee");

   
  // Append images
  var images = nodeEnter.append("svg:image")
        .attr("xlink:href",  function(d) { return d.img;})
        .attr("x", function(d) { return -25;})
        .attr("y", function(d) { return -25;})
        .attr("height", 50)
        .attr("width", 50);
 

  // Append hero name on roll over next to the node as well
  nodeEnter.append("text")
      .attr("class", "nodetext")
      //.attr("x", x_browser - 45)
      //.attr("y", y_browser + 15)
      .attr("text-anchor", "middle")
      //.attr("fill", tcBlack)
      .text(function(d) { return d.hero; });
 
 
  // Exit any old nodes.
  //node.exit().remove();
 
 
  // Re-select for update.
  path = vis.selectAll("path.link");
  node = vis.selectAll("g.node");
 
function tick() {
 
 
    path.attr("d", function(d) {
 
     var dx = d.target.x - d.source.x,
           dy = d.target.y - d.source.y,
           dr = Math.sqrt(dx * dx + dy * dy);
           return   "M" + d.source.x + "," 
            + d.source.y 
            + "A" + dr + "," 
            + dr + " 0 0,1 " 
            + d.target.x + "," 
            + d.target.y;
  });
    node.attr("transform", nodeTransform);    
  }
}

 
/**
 * Gives the coordinates of the border for keeping the nodes inside a frame
 * http://bl.ocks.org/mbostock/1129492
 */ 
function nodeTransform(d) {
  d.x =  Math.max(maxNodeSize, Math.min(w - (d.imgwidth/2 || 16), d.x));
    d.y =  Math.max(maxNodeSize, Math.min(h - (d.imgheight/2 || 16), d.y));
    return "translate(" + d.x + "," + d.y + ")";
   }
 
/**
 * Toggle children on click.
 */ 
function click(d) {
  if (d.children) {
    d._children = d.children;
    d.children = null;
  } else {
    d.children = d._children;
    d._children = null;
  }
  //update(); -- this genrates issues with paths
}
 
/**
 * Returns a list of all nodes under the root.
 */ 
function flatten(root) {
  var nodes = []; 
  var i = 0;
 
  function recurse(node) {
    if (node.children) 
      node.children.forEach(recurse);
    if (!node.id) 
      node.id = ++i;
    nodes.push(node);
  }
 
  recurse(root);
  return nodes;
}  
      @import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900');
      html{height: 100%;}
      body {font-family: 'Roboto', sans-serif; line-height: 1; font-size: 14px;  margin: 0;background: #eee;height: 100%; }
      path.link {
        fill: none;
        stroke-width: 2px;
      }
        #vis{width: 100%;height: 100%;}
      section svg{background-color:#fff;}    
      h1 { font-size: 36px; margin: 10px 0; text-transform: uppercase; font-weight: normal;}
      h2, h3 { font-size: 18px; margin: 5px 0 ; font-weight: normal;}
      header {padding: 20px; position: absolute; top: 0; left: 0;}
      a:link { color: #EE3124; text-decoration: none;}
      a:visited { color: #EE3124; }
      a:hover { color: #A4CD39; text-decoration: underline;}
      a:active { color: #EE3124; }

        
        
.nodetext{ font-size: 18px; font-weight: 100;}        
#Org image{width: 220px;height: 220px;x: -110;y: -110;}
#GNS-Main circle{r:30;fill:#37556f !important;stroke-width: 4;stroke: #2e4c66;}
.gns-1 .nodetext{ font-size: 18px;font-weight: 100;transform: translateY(40px);}        
#GNS-Main2 circle{r:30;fill:#ff6600 !important;stroke-width: 4;stroke: #eb5e00;}
.gns-2 .nodetext{ font-size: 18px;font-weight: 100;transform: translateY(40px);}  
#GNS-Main3 circle{r:30;fill:#e7e7e7 !important;stroke-width: 4;stroke: #dadada;}
.gns-3 .nodetext{ font-size: 18px;font-weight: 100;transform: translateY(40px);}
#GNS-Main .nodetext,#GNS-Main2 .nodetext,#GNS-Main3 .nodetext{ font-size: 34px;font-weight: 800;transform: translateY(65px);}
.gns-1 circle{fill:#37556f !important;stroke-width: 4;stroke: #2e4c66;} 
.gns-2 circle{fill:#e7e7e7 !important;stroke-width: 4;stroke: #dadada;}          
.gns-3 circle{fill:#ff6600 !important;stroke-width: 4;stroke: #eb5e00;}
.node circle{transition: all 0.2s ease-in;}            
.node:hover circle{r:25;} 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Marvel Characters | Force layout with images</title>
    

    <style>
       
    </style>
</head>
    

<body>
<!--    <header>
      <h1>Marvel Characters</h1>
      <h2>Click to view their identity</h2>
      <h3>And link to their web page!</h3>
    </header>-->
    <!-- container for force layout visualisation  -->
    <section id="vis"></section> 
<script>
    

</script>

</body>
</html>

感谢。

1 个答案:

答案 0 :(得分:0)

实现这一目标的可能性是改变json的结构,如下所述:https://bl.ocks.org/mbostock/4062045

首先,您将描述所有节点,然后使用source(child)和target(parent)定义所有链接。

这是一个小例子:

JSON结构

{
    "nodes": [ 
        { "id":64, "first_name":"Archived", "type":"L" } ,
        { "id":65, "first_name":"Archived 2", "type":"L" } ,
        { "id":84, "first_name":"Paymentoffice 2", "type":"P" } ,
        { "id":21, "first_name":"Contact 0", "type":"C" } ,
        { "id":41, "first_name":"Paymentoffice 1", "type":"P" } ,
        { "id":61, "first_name":"Contact 1", "type":"C" } ,
        { "id":62, "first_name":"Contact 2", "type":"C" } ,
        { "id":63, "first_name":"Contact 3", "type":"C" } ,
        { "id":1, "first_name":"Licensees", "type":"L" } ,
        { "id":94, "first_name":"Noch eins", "type":"P" } 
    ], 
    "links": [ 
        { "source":84, "target":1 } ,
        { "source":65, "target":1 } ,
        { "source":21, "target":1 } ,
        { "source":63, "target":62 } ,
        { "source":41, "target":21 } ,
        { "source":84, "target":21 } ,
        { "source":64, "target":1 } ,
        { "source":62, "target":61 } ,
        { "source":94, "target":61 } ,
        { "source":61, "target":1 } ,
        { "source":61, "target":94 } 
    ]
}

图表如下所示:

Force-graph

Paymentoffice 2节点(id:84)有两个父节点,即被许可方节点(id:1)和Contact 0节点(id:21)

希望这会对你有所帮助。