javascript - Organization chart - tree, online, dynamic, collapsible, pictures - in D3 -


i noob in web-development. i'm trying create tree-like hierarchical company org chart. tried both google's visualization chart , mike bostock's d3 reingold tree.

i want these features :

  • tree structure : either top-down (google) or left-right (d3)
  • online/dynamic : viewable in browser , able read data json (both google & d3), not static visio or ppt diagram
  • collapsible : able hide subtrees (both)
  • space-adjusting : nodes should fill visible area, reduce scrolling (only d3)
  • attributes : display name, title & possibly picture (only google)

above i've marked tool allows features, afaik.
i prefer d3 version because looks cool.
can modify .json include additional fields (title, url photo etc.) - here sample

my question - how modify d3 code display employee's name, title in next line, , maybe picture ?

or if that's not feasible - how modify google code automatically adjust spacing, children of node close together, , don't have horizontally scroll ?

here's quick example. modifies example, add in first name, last name, title , picture.

<!doctype html>  <meta charset="utf-8">  <style>    .node {    cursor: pointer;  }    .node circle {    fill: #fff;    stroke: steelblue;    stroke-width: 1.5px;  }    .node text {    font: 10px sans-serif;  }    .link {    fill: none;    stroke: #ccc;    stroke-width: 1.5px;  }    </style>  <body>  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>  <script>    var margin = {top: 20, right: 120, bottom: 20, left: 120},      width = 960 - margin.right - margin.left,      height = 300 - margin.top - margin.bottom;    var = 0,      duration = 750,      root;    var tree = d3.layout.tree()      .size([height, width]);    var diagonal = d3.svg.diagonal()      .projection(function(d) { return [d.y, d.x]; });    var svg = d3.select("body").append("svg")      .attr("width", width + margin.right + margin.left)      .attr("height", height + margin.top + margin.bottom)    .append("g")      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");          var data = {    "fname": "rachel",    "lname": "rogers",    "title": "ceo",    "photo": "http://lorempixel.com/60/60/cats/1",    "children": [{          "fname": "bob",          "lname": "smith",          "title": "president",          "photo": "http://lorempixel.com/60/60/cats/2",          "children": [{                "fname": "mary",                "lname": "jane",                "title": "vice president",                "photo": "http://lorempixel.com/60/60/cats/3",                "children": [{                  "fname": "bill",                  "lname": "august",                  "title": "dock worker",                  "photo": "http://lorempixel.com/60/60/cats/4"                }, {                  "fname": "reginald",                  "lname": "yoyo",                  "title": "line assembly",                  "photo": "http://lorempixel.com/60/60/cats/5"                }]              }, {                "fname": "nathan",                "lname": "ringwald",                "title": "comptroller",                "photo": "http://lorempixel.com/60/60/cats/6"              }]    }]  }    root = data;  root.x0 = height / 2;  root.y0 = 0;    function collapse(d) {    if (d.children) {      d._children = d.children;      d._children.foreach(collapse);      d.children = null;    }  }    root.children.foreach(collapse);  update(root);    function update(source) {      // compute new tree layout.    var nodes = tree.nodes(root).reverse(),        links = tree.links(nodes);      // normalize fixed-depth.    nodes.foreach(function(d) { d.y = d.depth * 180; });      // update nodes…    var node = svg.selectall("g.node")        .data(nodes, function(d) { return d.id || (d.id = ++i); });      // enter new nodes @ parent's previous position.    var nodeenter = node.enter().append("g")        .attr("class", "node")        .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })        .on("click", click);      // add picture    nodeenter      .append('defs')      .append('pattern')      .attr('id', function(d,i){        return 'pic_' + d.fname + d.lname;      })      .attr('height',60)      .attr('width',60)      .attr('x',0)      .attr('y',0)      .append('image')      .attr('xlink:href',function(d,i){        return d.photo;      })      .attr('height',60)      .attr('width',60)      .attr('x',0)      .attr('y',0);      nodeenter.append("circle")        .attr("r", 1e-6)        .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });      var g = nodeenter.append("g");        g.append("text")        .attr("x", function(d) { return d.children || d._children ? -35 : 35; })        .attr("dy", "1.35em")        .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })        .text(function(d) { return d.fname + " " + d.lname; })        .style("fill-opacity", 1e-6);              g.append("text")        .attr("x", function(d) { return d.children || d._children ? -35 : 35; })        .attr("dy", "2.5em")        .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })        .text(function(d) { return d.title; })        .style("fill-opacity", 1e-6);      // transition nodes new position.    var nodeupdate = node.transition()        .duration(duration)        .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });      nodeupdate.select("circle")        .attr("r", 30)        .style("fill", function(d,i){          return 'url(#pic_' + d.fname + d.lname+')';        });      nodeupdate.selectall("text")        .style("fill-opacity", 1);      // transition exiting nodes parent's new position.    var nodeexit = node.exit().transition()        .duration(duration)        .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })        .remove();      nodeexit.select("circle")        .attr("r", 1e-6);      nodeexit.select("text")        .style("fill-opacity", 1e-6);      // update links…    var link = svg.selectall("path.link")        .data(links, function(d) { return d.target.id; });      // enter new links @ parent's previous position.    link.enter().insert("path", "g")        .attr("class", "link")        .attr("d", function(d) {          var o = {x: source.x0, y: source.y0};          return diagonal({source: o, target: o});        });      // transition links new position.    link.transition()        .duration(duration)        .attr("d", diagonal);      // transition exiting nodes parent's new position.    link.exit().transition()        .duration(duration)        .attr("d", function(d) {          var o = {x: source.x, y: source.y};          return diagonal({source: o, target: o});        })        .remove();      // stash old positions transition.    nodes.foreach(function(d) {      d.x0 = d.x;      d.y0 = 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(d);  }    </script>


reversed direction:

<!doctype html>  <meta charset="utf-8">  <style>    .node {    cursor: pointer;  }    .node circle {    fill: #fff;    stroke: steelblue;    stroke-width: 1.5px;  }    .node text {    font: 10px sans-serif;  }    .link {    fill: none;    stroke: #ccc;    stroke-width: 1.5px;  }    </style>  <body>  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>  <script>    var margin = {top: 20, right: 120, bottom: 20, left: 120},      width = 960 - margin.right - margin.left,      height = 300 - margin.top - margin.bottom;    var = 0,      duration = 750,      root;    var tree = d3.layout.tree()      .size([height, width]);    var diagonal = d3.svg.diagonal()      .projection(function(d) { return [d.x, d.y]; });    var svg = d3.select("body").append("svg")      .attr("width", width + margin.right + margin.left)      .attr("height", height + margin.top + margin.bottom)    .append("g")      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");          var data = {    "fname": "rachel",    "lname": "rogers",    "title": "ceo",    "photo": "http://lorempixel.com/60/60/cats/1",    "children": [{          "fname": "bob",          "lname": "smith",          "title": "president",          "photo": "http://lorempixel.com/60/60/cats/2",          "children": [{                "fname": "mary",                "lname": "jane",                "title": "vice president",                "photo": "http://lorempixel.com/60/60/cats/3",                "children": [{                  "fname": "bill",                  "lname": "august",                  "title": "dock worker",                  "photo": "http://lorempixel.com/60/60/cats/4"                }, {                  "fname": "reginald",                  "lname": "yoyo",                  "title": "line assembly",                  "photo": "http://lorempixel.com/60/60/cats/5"                }]              }, {                "fname": "nathan",                "lname": "ringwald",                "title": "comptroller",                "photo": "http://lorempixel.com/60/60/cats/6"              }]    }]  }    root = data;  root.x0 = height / 2;  root.y0 = 0;    function collapse(d) {    if (d.children) {      d._children = d.children;      d._children.foreach(collapse);      d.children = null;    }  }    root.children.foreach(collapse);  update(root);    function update(source) {      // compute new tree layout.    var nodes = tree.nodes(root).reverse(),        links = tree.links(nodes);      // normalize fixed-depth.    nodes.foreach(function(d) { d.y = d.depth * 180; });      // update nodes…    var node = svg.selectall("g.node")        .data(nodes, function(d) { return d.id || (d.id = ++i); });      // enter new nodes @ parent's previous position.    var nodeenter = node.enter().append("g")        .attr("class", "node")        .attr("transform", function(d) { return "translate(" + source.x0 + "," + source.y0 + ")"; })        .on("click", click);      // add picture    nodeenter      .append('defs')      .append('pattern')      .attr('id', function(d,i){        return 'pic_' + d.fname + d.lname;      })      .attr('height',60)      .attr('width',60)      .attr('x',0)      .attr('y',0)      .append('image')      .attr('xlink:href',function(d,i){        return d.photo;      })      .attr('height',60)      .attr('width',60)      .attr('x',0)      .attr('y',0);      nodeenter.append("circle")        .attr("r", 1e-6)        .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });      var g = nodeenter.append("g");        g.append("text")        .attr("x", function(d) { return d.children || d._children ? -35 : 35; })        .attr("dy", "1.35em")        .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })        .text(function(d) { return d.fname + " " + d.lname; })        .style("fill-opacity", 1e-6);              g.append("text")        .attr("x", function(d) { return d.children || d._children ? -35 : 35; })        .attr("dy", "2.5em")        .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })        .text(function(d) { return d.title; })        .style("fill-opacity", 1e-6);      // transition nodes new position.    var nodeupdate = node.transition()        .duration(duration)        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });      nodeupdate.select("circle")        .attr("r", 30)        .style("fill", function(d,i){          return 'url(#pic_' + d.fname + d.lname+')';        });      nodeupdate.selectall("text")        .style("fill-opacity", 1);      // transition exiting nodes parent's new position.    var nodeexit = node.exit().transition()        .duration(duration)        .attr("transform", function(d) { return "translate(" + source.x + "," + source.y + ")"; })        .remove();      nodeexit.select("circle")        .attr("r", 1e-6);      nodeexit.select("text")        .style("fill-opacity", 1e-6);      // update links…    var link = svg.selectall("path.link")        .data(links, function(d) { return d.target.id; });      // enter new links @ parent's previous position.    link.enter().insert("path", "g")        .attr("class", "link")        .attr("d", function(d) {          var o = {x: source.x0, y: source.y0};          return diagonal({source: o, target: o});        });      // transition links new position.    link.transition()        .duration(duration)        .attr("d", diagonal);      // transition exiting nodes parent's new position.    link.exit().transition()        .duration(duration)        .attr("d", function(d) {          var o = {x: source.x, y: source.y};          return diagonal({source: o, target: o});        })        .remove();      // stash old positions transition.    nodes.foreach(function(d) {      d.x0 = d.x;      d.y0 = 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(d);  }    </script>


Comments

Popular posts from this blog

PHP DOM loadHTML() method unusual warning -

python - How to create jsonb index using GIN on SQLAlchemy? -

c# - TransactionScope not rolling back although no complete() is called -