D3.js stick parent object in middle of the svg

d3.js, force-layout, javascript, svg

Solution

What you need to do for this is set the `fixed` property of the node in question to `true` (see the documentation) after having set its coordinates to the center, so something like

nodes.forEach(function(d) {
   if(d._children || d.children) {
     d.x = width/2, d.y = height/2;
     d.fixed = true;
   }
});

immediately at the start of the `update` function.

If you want to disable drag for that node as well, you can do

nodeEnter.filter(function(d) {
           return d.children === undefined && d._children === undefined;
         })
         .call(force.drag);

instead of calling `force.drag` on all the nodes. Complete example here.

Problem

I have modified Collapsible Force Layout http://mbostock.github.io/d3/talk/20111116/force-collapsible.html example: ...and now it looks like this All circle are now dragable. I want to stick middle circle (blue circle) middle of the svg. Is it possible? Thank you. ``` <script> var width = 960, height = 600, root; var force = d3.layout.force() .linkDistance(175) .charge(-200) .gravity(0) .size([width, height]) .on("tick", tick); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var link = svg.selectAll(".link"), node = svg.selectAll(".node"); d3.json("graph.json", function(error, json) { root = json; update(); }); function update() { var nodes = flatten(root), links = d3.layout.tree().links(nodes); // Restart the force layout. force .nodes(nodes) .links(links) .start(); // Update links. link = link.data(links, function(d) { return d.target.id; }); link.exit().remove(); link.enter().insert("line", ".node") .attr("class", "link"); // Update nodes. node = node.data(nodes, function(d) { return d.id; }); node.exit().remove(); var nodeEnter = node.enter().append("g") .attr("class", "node") .on("click", click) .call(force.drag) .attr("href", function(d) { return d.link; }); nodeEnter.append("svg:a") .attr("xlink:href", function(d){return d.link;}) .append("circle") .attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; }); nodeEnter.append("text") .attr("dy", ".35em") .text(function(d) { return d.name; }); node.select("circle") .style("fill", color); } function tick() { 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 color(d) { return d._children ? "#3182bd" // collapsed package : d.children ? "#2F9BC1" // expanded package : "#fd8d3c"; // leaf node } // Toggle children on click. function click(obj) { if (d3.event.defaultPrevented) return; // ignore drag if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } update(); } // Returns a list of all nodes under the root. function flatten(root) { var nodes = [], 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; } </script> ``` json file: ``` { "name": "Me", "size": 200000, "link": "http://google.com", "children": [ {"name": "Person 01", "size": 150000, "link": "http://google.com"}, {"name": "Person 02", "size": 150000, "link": "http://yahoo.com"}, {"name": "Person 03", "size": 150000, "link": "http://youtube.com"}, {"name": "Person 04", "size": 150000, "link": "http://twitter.com"}, {"name": "Person 05", "size": 150000, "link": "http://facebook.com"} ] } ```

Original source