javascript - d3 force layout initial structure -
is possible give d3 force layout kind of structure? wanting show relationship between staff , users, staff can have many users.
however initial layout while correct incomprehensible.
the nodes red outlines staff, , blue outlines users, ideally nice have users below staff, in force hierarchy layout if exist?
var width = document.queryselector('.visualisation').clientwidth, height = 500; var svg = d3.select(".visualisation").append("svg") .attr("width", width) .attr("height", height); var force = d3.layout.force() .gravity(.05) .linkdistance(100) .charge(-300) .size([width, height]); var sw = [], su = [], workbase = [], links = [], edges = [], simplified = []; d3.json("test_example.json", function(error, json) { if (error) throw error; console.log(json); var users = []; json.foreach(function(data){ if(data.workbase == "cherry tree lodge") { data.weight = 1; links.push({ target : data.user_id, source : data.staff_id, }); users.push(data); } }); console.log(nodes); // json.foreach(function(data) { // console.log(json); users.foreach(function(d) { if(_.findwhere(sw, { name: d.staff_name}) == undefined) { sw.push({ name : d.staff_name, id : d.staff_id, role : d.role, weight:1, type : "worker" }); } if(_.findwhere(su, { name: d.service_user}) == undefined) { su.push({ name : d.service_user, type : "user", id : d.user_id, weight:1 }); } }); var nodes = sw.concat(su); console.log(nodes); nodes.foreach(function(data){ if(typeof data.linked_to != "undefined") { links.push({ target: _.findindex(nodes, function(user) { return user.id == data.linked_to; }), source: data.id }); } }); console.log(links); // //console.log(json);console.log(links) links.foreach(function(e){ var sourcenode = nodes.filter(function(n) { return n.id === e.source})[0]; var targetnode = nodes.filter(function(n) { return n.id === e.target})[0]; edges.push({ source: sourcenode, target: targetnode }); }); console.log(edges); // console.log(nodes); force .nodes(nodes) .links(edges) .on("tick", tick) .start(); var link = svg.selectall(".link") .data(edges) .enter().append("line") .attr("class", "link"); var node = svg.selectall(".node") .data(nodes) .enter().append("g") .attr("class", "node") .call(force.drag); // node.append("defs") // .append("pattern") // .attr("id", function(d){ // return "image-" + d.id; // }) // .attr("height", 50) // .attr("width", 50) // .attr("x", 0) // .attr("y", 0) // .append("image") // .attr("xlink:href", function(d) { // return d.image; // }) // .attr('height',60) // .attr('width',60) // .attr('x',0) // .attr('y',0); node.append("circle") .attr("class", function(d){ return d.type; }) .attr("r", 25); // .on("mouseover", showdetails) // .on("mouseout", removedetails); node.append("text") .attr("x", 0) .attr("dy", ".35em") .attr("text-anchor", "middle") .text(function(d){ //return d.name; }); // // node.append("svg:a") // // .attr("xlink:href", function(d){ return "" }) // // .append("text") // // .attr("dx", 12) // // .attr("dy", ".35em") // // .text(function(d) { return d.name}) function tick(e) { var k = 6 * e.alpha; // push sources , targets down form weak tree. link .each(function(d) { d.source.y -= k, d.target.y += k; }) .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); node .attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }); node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); } });
you can achieve setting position along y axis d3.forcey()
. according api:
creates new positioning force along y-axis towards given position y.
so, created array using type
specify user , staff:
var nodes = [ {"id": 1, "name": "staff1", "type": "staff"}, {"id": 2, "name": "staff2", "type": "staff"}, {"id": 3, "name": "user1", "type": "user"}, {"id": 4, "name": "user2", "type": "user"}, {"id": 5, "name": "user3", "type": "user"}, {"id": 6, "name": "staff3", "type": "staff"}, {"id": 7, "name": "user4", "type": "user"}, {"id": 8, "name": "user5", "type": "user"}, {"id": 9, "name": "user6", "type": "user"}, {"id": 10, "name": "user7", "type": "user"}, {"id": 11, "name": "user8", "type": "user"}, {"id": 12, "name": "user19", "type": "user"} ];
then, used type
set position:
var simulation = d3.forcesimulation() .force('y', d3.forcey((d) => d.type === "staff" ? height/5 : 4*height/5).strength(2))
here demo:
var nodes = [ {"id": 1, "name": "staff1", "type": "staff"}, {"id": 2, "name": "staff2", "type": "staff"}, {"id": 3, "name": "user1", "type": "user"}, {"id": 4, "name": "user2", "type": "user"}, {"id": 5, "name": "user3", "type": "user"}, {"id": 6, "name": "staff3", "type": "staff"}, {"id": 7, "name": "user4", "type": "user"}, {"id": 8, "name": "user5", "type": "user"}, {"id": 9, "name": "user6", "type": "user"}, {"id": 10, "name": "user7", "type": "user"}, {"id": 11, "name": "user8", "type": "user"}, {"id": 12, "name": "user19", "type": "user"} ]; var links = [ {source: 1, target: 8}, {source: 1, target: 3}, {source: 1, target: 4}, {source: 1, target: 9}, {source: 1, target: 10}, {source: 1, target: 11}, {source: 2, target: 5}, {source: 2, target: 6}, {source: 2, target: 7}, {source: 2, target: 12}, {source: 2, target: 4}, {source: 2, target: 8}, {source: 6, target: 7}, {source: 6, target: 8}, {source: 6, target: 9}, {source: 6, target: 5}, {source: 6, target: 3}, {source: 6, target: 9}, ] var index = 10; var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"), node, link; var simulation = d3.forcesimulation() .force("link", d3.forcelink().id(function(d) { return d.id; })) .force('y', d3.forcey((d) => d.type === "staff" ? height/5 : 4*height/5).strength(2)) .force("charge", d3.forcemanybody()) .force("collide", d3.forcecollide(30)) .force("center", d3.forcecenter(width / 2, height / 2)); update(); function update() { link = svg.selectall(".link") .data(links, function(d) { return d.target.id; }) link = link.enter() .append("line") .attr("class", "link"); node = svg.selectall(".node") .data(nodes, function(d) { return d.id; }) node = node.enter() .append("g") .attr("class", "node") .on("click", click) .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)); node.append("circle") .attr("r", 6) .attr("fill", (d)=> d.type === "user" ? "blue" : "red") node.append("title") .text(function(d) { return d.id; }); node.append("text") .attr("dx", 10) .text(function(d) { return d.name; }); simulation .nodes(nodes) .on("tick", ticked); simulation.force("link") .links(links); } function click(d) { nodes.push({id: index, name: "server " + index}); links.push({source: d.id, target: index}); index++; update(); } function ticked() { link .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); node .attr("transform", function(d) { return "translate(" + d.x + ", " + d.y + ")"; }); } function dragstarted(d) { if (!d3.event.active) simulation.alphatarget(0.3).restart() } function dragged(d) { d.fx = d3.event.x; d.fy = d3.event.y; } function dragended(d) { if (!d3.event.active) simulation.alphatarget(0); d.fx = undefined; d.fy = undefined; }
.link { stroke: #aaa; } .node { pointer-events: all; stroke: none; stroke-width: 40px; }
<script src="https://d3js.org/d3.v4.min.js"></script> <svg width="400" height="400"></svg>
Comments
Post a Comment