d3 graph layout - arrows heads - layout

I've seen several questions on how to move the arrowheads in directed graphs according to the radius of the nodes, but I can't figure out how to do it in my example : https://jsfiddle.net/Lx58yux4/
//arrows
svg.append("defs").selectAll("marker")
.data(["suit", "licensing", "resolved"])
.enter().append("marker")
.attr("id", function(d) { return d; })
.attr("viewBox", "0 -5 10 10")
.attr("refX", 25)
.attr("refY", 0)
.attr("markerWidth", 8)
.attr("markerHeight", 8)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5 L10,0 L0, -5")
.style("stroke", "#4679BD")
.style("opacity", "0.6");
//onTick
force.on("tick", function () {
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;
});
d3.selectAll("circle").attr("cx", function (d) {
//return d.x;
return d.x = Math.max(radius, Math.min(width - 10, d.x));
})
.attr("cy", function (d) {
return d.y = Math.max(radius, Math.min(height - 10, d.y));
//return d.y;
});
d3.selectAll("text").attr("x", function (d) {
return d.x;
})
.attr("y", function (d) {
return d.y;
});
node.each(collide(5.0)); //collision detection
});

Save node radius in data bond to the nodes.
node.append("circle")
.attr("r", function(d) {
d.radius = (10 + d.users/250);
return d.radius;
})
.style("fill", function (d) {
return color(d.group);
});
Now, update the links as shown below in tick function.
link.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
var diffX = d.target.x - d.source.x;
var diffY = d.target.y - d.source.y;
var pathLength = Math.sqrt((diffX * diffX) + (diffY * diffY));
var offsetX = (diffX * d.target.radius) / pathLength;
return d.target.x-offsetX;
})
.attr("y2", function (d) {
var diffX = d.target.x - d.source.x;
var diffY = d.target.y - d.source.y;
var pathLength = Math.sqrt((diffX * diffX) + (diffY * diffY));
var offsetY = (diffY * d.target.radius) / pathLength;
return d.target.y-offsetY;
});
Hope this helps.

Here is the fiddle :
https://jsfiddle.net/Lx58yux4/2/
It may need tweeking but basically you have to work out the difference between the center of the node to the outside and then get the vector between both nodes to move the arrow down. This uses pythagoras's theorum c=sqrt(a^2+b^2);
Here's the main bit of code :
function getVector(d) {
var x1 = d.target.x;
var y1 = d.target.y;
var x2 = d.source.x;
var y2 = d.source.y;
var a = x1 - x2; //difference in x
var b = y1 - y2; //difference in y
var c = Math.sqrt((a * a) + (b * b)); //single vector
var nodeRadius;
node.filter(function(e) {
return e.name === d.target.name; //return the links target
}).each(function(n,i) {
nodeRadius = 10 + n.users / 250 //as you had before, you could set this where you give it to the node
});
var vectorX = a / (c / nodeRadius );
var vectorY = b / (c / nodeRadius );
var thisVector = [vectorX, vectorY];
return thisVector;
}
Then use that in the x and y of the target
.attr("x2", function(d) {
var thisVector = getVector(d);
return d.target.x - thisVector[0];
})
.attr("y2", function(d) {
var thisVector = getVector(d);
return d.target.y - thisVector[1];
});
Notice this way the links dont go to the center, but to the outside. So really this way doesnt move the arrows down the link, but the links to the outside of the node which in turn move the arrows.

Related

Export or Download d3.js sunburst / collapsible tree charts as pdf file

I need to download my d3.js collapsible tree chart and sunburst chart as PDF file .
I tried using jspdf.plugin.svgToPdf plugin but it doesnt work.
Could someone guide me in downloading the charts as pdf ?
My source code for collapsible tree
(function () {
var out$ = typeof exports != 'undefined' && exports || this;
var margin = {
top : 20,
right : 120,
bottom : 20,
left : 120
},
width = 960 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;
var i = 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;
out$.treeChart = (function (divTag, jsonData) {
svg = d3.select(divTag).append("svg")
.attr("id", "treeChart")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json(jsonData, function (error, flare) {
root = flare;
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);
});
d3.select(self.frameElement).style("height", "800px");
});
function update(source) {
$('#loading' + source.id).hide();
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function (d) {
d.y = d.depth * 180;
});
// Update the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function (d) {
return d.id || (d.id = ++i);
});
// Enter any new nodes at the 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);
nodeEnter.append("circle")
.attr("r", 15)
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.append("svg:image")
.attr("class", "circle")
.attr("xlink:href", "logo.png")
.attr("x", "-8px")
.attr("y", "-8px")
.attr("width", "16px")
.attr("height", "16px");
var spinner = nodeEnter.append("foreignObject")
.attr("width", 100)
.attr("height", 100)
.attr("id", function (d) {
return "loading" + d.id;
})
.style("display", "none")
.append("xhtml:div")
.html("<img src=\"loading.GIF\"/>");
nodeEnter.append("a")
.attr("xlink:href", function (d) {
return d.url;
})
.append("text")
.attr("x", function (d) {
return d.children || d._children ? -10 : 10;
})
.attr("dy", ".35em")
.attr("text-anchor", function (d) {
return d.children || d._children ? "end" : "start";
})
.text(function (d) {
return d.name;
})
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + d.y + "," + d.x + ")";
});
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function (d) {
return d._children || d.children ? "lightsteelblue" : "#fff";
});
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the 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 the links…
var link = svg.selectAll("path.link")
.data(links, function (d) {
return d.target.id;
});
// Enter any new links at the 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 to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the 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 the old positions for transition.
nodes.forEach(function (d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// Toggle children on click.
function click(d) {
$('#loading' + d.id).show();
setTimeout(function () {
$.getJSON("http://localhost:8080/demo/gateways.json", function (addJson) {
var childObj = getObjects(addJson, 'name', d.name);
if (childObj[0].children != null) {
var len = (childObj[0].children).length;
function collapse2(k) {
if (k.children) {
k._children = k.children;
k._children.forEach(collapse2);
k.children = null;
}
}
childObj[0].children.forEach(collapse2);
var newnodes = tree.nodes(childObj[0].children).reverse();
if (d.children) {
d._children = newnodes[0];
d.children = null;
} else {
d.children = newnodes[0];
d._children = null;
}
update(d);
} else
$('#loading' + d.id).hide();
});
//do something special
}, 2000);
}
function getObjects(obj, key, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i))
continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjects(obj[i], key, val));
} else if (i == key && obj[key] == val) {
objects.push(obj);
}
}
return objects;
}
})();
this is the fastest way to download the svg from a webpage: http://nytimes.github.io/svg-crowbar/ you can then easily convert the svg to pdf

How to select multiple svg texts in a single customized zoom function

I am working on the zoom function of d3 but I am not able to zoom on two different text(labels).
text code: (they are working)
var texts = canvas.selectAll("text")
.data(nodes)
.enter();
texts.append("text")
.attr("class", function(d) { return d.children ? "parent" : "child"; })
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.style("opacity", function(d) { return d.r > 20 ? 1 : 0; })
.text(function(d) {return d.children ? "" : d.name;; });
texts.append("text")
.attr("class", function(d) { return d.children ? "parent" : "child"; })
.attr("x", function(d) { return d.x ; })
.attr("y", function(d) { return d.y + 20; }) // for not overlapping name and the title
.attr("dy", ".45em")
.style("opacity", function(d) { return d.r > 20 ? 1 : 0; })
.text(function(d) {return d.children ? "" : d.title; });
Zoom Code: (second part not working)
function zoom(d, i) {
var k = r / d.r / 2;
x.domain([d.x - d.r, d.x + d.r]);
y.domain([d.y - d.r, d.y + d.r]);
var t = canvas.transition()
.duration(d3.event.altKey ? 7500 : 750);
t.selectAll("text")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y); })
.style("opacity", 0.15 });
t.selectAll("text")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y) + 20 })
.style("opacity", 0.15 });
}
Now the question is how to keep the displacement (d.y + 20; }) done in text2 part as both of them overlapping during zoom operation... I also used variable instead of using the text but none of them worked.. Any help

d3 treemap rect orientation error when updating

I wrote a d3.js treemap that updates and re-renders when I receive new data. When I do graph the maps, the rects sometimes shift positions, and it seems like the orientation of the elements is messed up because they move outside the chart or overlap with another element, leaving whitespace in the throughout the graph, but after re-rendering the graph usually corrects itself, and then messes up again. I think the problem comes about because the graph is resizing itself with regards to absolute positions, but rects in certain positions from the previous render are messing things up. Any clue how to stop this intermediate phase of having a messed up graph before being able to re-render? Thanks.
This is the code I use to initially draw the d3 regraph.
function drawTreeMap(array1,array2, colorArray)
{
console.log("got to drawing");
var cellMargin=5;
this.marginTree = {top:20, right:20, bottom:20, left:20};
var coloring = d3.scale.linear()
.range(['lightblue', 'green']) // or use hex values
.domain([this.getMinOfThisArray(colorArray), this.getMaxOfThisArray(colorArray)]);
this.nestedJson = this.createObj(array1, array2, colorArray);
this.w = 1700 - 80,
this.h = 980 - 180,
this.x = d3.scale.linear().range([0, this.w]),
this.y = d3.scale.linear().range([0, this.h]),
this.root,
this.node;
this.treemap = d3.layout.treemap()
.round(false)
.size([this.w, this.h])
.sticky(true)
.padding([this.marginTree.bottom, this.marginTree.right, this.marginTree.top, this.marginTree.left])
.sort(function(a,b) {
return a.value - b.value;
})
.value(function(d) { return d.size; });
this.svg = d3.select("#body").append("div")
.attr("class", "chart")
.style("position", "relative")
.style("width", (this.w) + "px")
.style("height", (this.h ) + "px")
.style("left", this.marginTree.left +"px")
.style("top", this.marginTree.top + "px")
.append("svg:svg")
.attr("width", this.w)
.attr("height", this.h)
.append("svg:g")
.attr("transform", "translate(.5,.5)");
this.node = this.root = this.nestedJson;
var nodes = this.treemap.nodes(this.root)
.filter(function(d) { return !d.children; });
this.tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d) {
return "<span style='color:white'>" + (d.name+",\n "+d.size) + "</span>";
})
this.svg.call(this.tip);
var cell = this.svg.selectAll("g")
.data(nodes)
.enter().append("svg:g")
.attr("class", "cell")
.call(this.position)
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.on("click", function(d) { return this.zoom(this.node == d.parent ? this.root : d.parent); });
var borderPath = this.svg.append("rect")
.attr("class", "border")
.attr("x", this.marginTree.left)
.attr("y", this.marginTree.top)
.attr("height", this.h - this.marginTree.top - this.marginTree.bottom )
.attr("width", this.w - this.marginTree.left - this.marginTree.right)
.style("stroke", 'darkgrey')
.style("fill", "none")
.style("stroke-width", '3px');
cell.append("svg:rect")
.attr("id", function(d,i) { return "rect-" + (i+1); })
.attr("class","highlighting2 cell-rects")
.attr("title", function(d) {return (d.name+", "+d.size);})
.attr("data-original-title", function(d) {return (d.name+",\n "+d.size);})
.attr("width", function(d) { return d.dx ; })
.attr("height", function(d) { return d.dy ; })
.on('mouseover', this.tip.show)
.on('mouseout', this.tip.hide)
.style("fill", function(d) {return coloring(d.color);});
cell.append("svg:text")
.attr("class", "treemap-text nameTexts")
.attr("id", function(d,i) { return "name-" + (i+1); })
.attr("x", cellMargin)
.attr("y", function(d) { return parseInt($('.treemap-text').css('font-size'))+cellMargin; })
.text(function(d) {return (d.name);});
cell.append("svg:text")
.attr("class", "treemap-text sizeTexts")
.attr("id", function(d,i) { return "size-" + (i+1); })
.attr("x", cellMargin)
.attr("y", function(d) { return 2*parseInt($('.treemap-text').css('font-size'))+2*cellMargin; })
.text(function(d) {return (d.size);});
// d3.selectAll("svg:rect")
// .style("stroke-width", 2)
// .style("stroke", function(d){ return this.LightenDarkenColor(coloring(d.color), -5);});
this.treeMapping = true;
$(document).ready(function(){
for (var i =1 ; i<graphObj.rc.positions[graphObj.currentVpName].SetSize; i++){
var obj = "rect-"+i;
var size = "size-"+i;
var name = "name-"+i;
graphObj.formatNumbers(size);
graphObj.placeTextWithEllipsis(obj, size);
graphObj.placeTextWithEllipsis(obj, name);
}
d3.selectAll(".nameTexts")
.style("fill", "#333333");
d3.selectAll(".sizeTexts")
.style("fill","#383838");
});
}
This is the file I use to re-render the treemap when I receive new data.
function redrawGraph(array1, array2, colorArray)
{
this.nestedJson = this.createObj(array1, array2, colorArray);
var coloring = d3.scale.linear()
.range(['lightblue', 'green']) // or use hex values
.domain([this.getMinOfThisArray(colorArray), this.getMaxOfThisArray(colorArray)]);
var cellMargin = 5;
this.svg = d3.select("#body").append("div")
this.treemap
.mode("squarify")
.round(false)
.size([this.w,this.h])
.sticky(true)
.value(function(d) { return d.size; });
// Draw the graph
this.node = this.root = this.nestedJson;
var nodes = this.treemap.nodes(this.root)
.filter(function(d) { return !d.children; });
var rect = d3.select("#body").selectAll(".cell-rects")
.data(nodes);
rect.exit().remove();
rect.enter().append("rect");
rect
.transition()
.attr("width", function(d) { return d.dx ; })
.attr("height", function(d) { return d.dy ; })
.attr("title", function(d) {return (d.name+", "+d.size);})
.attr("data-original-title", function(d) {return (d.name+",\n "+d.size);})
.style("fill", function(d) { return coloring(d.color)})
.call(this.position);
var text = d3.select("#body").selectAll(".nameTexts")
.data(nodes);
text.exit().remove();
text.enter().append("text");
text
.attr("class", "treemap-text nameTexts")
.attr("x", cellMargin)
.attr("y", function(d) { return parseInt($('.treemap-text').css('font-size'))+cellMargin; })
.text(function(d) { return (d.name); });
var text2 = d3.select("#body").selectAll(".sizeTexts")
.data(nodes);
text2.exit().remove();
text2.enter().append("text");
text2
.attr("class", "treemap-text sizeTexts")
.attr("x", cellMargin)
.attr("y", function(d) { return 2*parseInt($('.treemap-text').css('font-size'))+2*cellMargin; })
.text(function(d) { return (d.size); });
var cell = this.svg.selectAll("g")
cell.append("svg:rect")
cell.append("svg:text");
// var border = this.svg.append("rect")
// .attr("x", this.marginTree.left)
// .attr("y", this.marginTree.top)
// .attr("height", this.h - this.marginTree.top - this.marginTree.bottom )
// .attr("width", this.w - this.marginTree.left - this.marginTree.right)
// .style("stroke", 'darkgrey')
// .style("fill", "none")
// .style("stroke-width", '3px');
// d3.select(window).on("click", function() {
// this.zoom(this.root); });
// d3.select("select").on("change", function()
// {
// this.treemap.value(this.value == "size" ? this.size : this.count).nodes(this.root);
// this.zoom(this.node);
// });
d3.selectAll(".nameTexts")
.style("fill", "#333333");
d3.selectAll(".sizeTexts")
.style("fill","#383838");
$(document).ready(function(){
for (var i =1 ; i<graphObj.rc.positions[graphObj.currentVpName].SetSize; i++){
var obj = "rect-"+i;
var size = "size-"+i;
var name = "name-"+i;
graphObj.formatNumbers(size);
graphObj.placeTextWithEllipsis(obj, size);
graphObj.placeTextWithEllipsis(obj, name);
}
});
}
function position()
{
this.style("left", function(d) { return d.x + "px"; })
.style("top", function(d) { return d.y + "px"; })
.style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
.style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
}
Also by white space I mean this.
Image is linked here. [http://i.stack.imgur.com/LTLk6.png][1]

d3 pie charts innerRadius and outerRadius acting funky

The pie charts' arcs each seem to have their own radius behaviors, when i want them to all share the radius of the highest value passed in. here's the relevant code.
var pie = d3.layout.pie()
.value(function(d) {
return d;
}).sort(null);
var arc = d3.svg.arc()
.innerRadius(function(d, i) { console.log(d, i); return (d.value * .6) })
.outerRadius(function(d) { return d.value; });
var fill = d3.scale.linear()
.domain([0, 2])
.range(["red", "blue"]);
var force = d3.layout.force()
.nodes(data)
.size([width + 250, height + 50])
.on("tick", tick)
.charge(charge)
.gravity(.15);
force.start();
function charge(d) {
return d.rank * d.rank * -.25;
}
var svg = d3.select("body").append("svg")
.attr("width", width + 250)
.attr("height", height + 50);
var nodes = svg.selectAll(".node")
.data(data)
.enter()
.append("g")
.attr("class", "node");
// .attr("cx", function(d) { return d.x; })
// .attr("cy", function(d) { return d.y; })
// .attr("r", function(d) { return d.rank; })
nodes.selectAll("path")
.data(function(d) {
var ar = [];
ar.push(prostitution_scale(d.prostitution));
ar.push(cigarette_scale(d.cigarettes));
ar.push(alcohol_scale(d.alcohol));
return pie(ar);
})
.enter()
.append("svg:path")
.attr("d", arc)
.style("fill", function(d, i) { return fill(i); })
.style("stroke", function(d, i) { return d3.rgb(fill(d.value)).darker(2); })
.call(force.drag);
You're passing functions to the accessors for the radii:
.innerRadius(function(d, i) { console.log(d, i); return (d.value * .6) })
.outerRadius(function(d) { return d.value; });
So D3 is going to call these functions for every data element and use the value it gets from that. If you want something constant, specify a single number, e.g.
.innerRadius(30)
.outerRadius(50);
To get use the maximum value for each arc, you could do something like this.
nodes.selectAll("path")
.data(function(d) {
var ar = [];
ar.push(prostitution_scale(d.prostitution));
ar.push(cigarette_scale(d.cigarettes));
ar.push(alcohol_scale(d.alcohol));
var segments = pie(ar),
maxValue = d3.max(segments, function(d) { return d.value; });
pie.forEach(function(d) { d.maxVal = maxValue; });
return segments;
})
.enter()
.append("svg:path")
.attr("d", arc.innerRadius(function(d) { return d.maxVal * 0.6; })
.outerRadius(function(d) { return d.maxVal; }))
// etc

Add multiple svg:lines in D3.js

i try to enhance a D3.js example and have some problems to add multiple lines to an svg:g container. One line is working fine, but adding a second line end with an empty website.
Here is my working code:
function update(source) {
var duration = d3.event && d3.event.altKey ? 5000 : 500;
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 280; });
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parents previous position.
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", function(d) { toggle(d); update(d); });
nodeEnter.append("svg:rect")
.attr("x", -100)
.attr("y", -40)
.attr("rx", 6)
.attr("ry", 6)
.attr("width", 200)
.attr("height", 80)
.style("fill-opacity", 1)
.style("fill", function(d) { return d._children ? "#FF0033" : "#fff"; });
nodeEnter.append("svg:line")
.attr("x1",-100)
.attr("y1",-25)
.attr("x2",100)
.attr("y2",-25)
.attr("stroke-width","2px")
.attr("stroke","#f03");
And here is my not working code:
function update(source) {
var duration = d3.event && d3.event.altKey ? 5000 : 500;
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 280; });
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parents previous position.
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", function(d) { toggle(d); update(d); });
nodeEnter.append("svg:rect")
.attr("x", -100)
.attr("y", -40)
.attr("rx", 6)
.attr("ry", 6)
.attr("width", 200)
.attr("height", 80)
.style("fill-opacity", 1)
.style("fill", function(d) { return d._children ? "#FF0033" : "#fff"; });
nodeEnter.append("svg:line")
.attr("x1",-100)
.attr("y1",-25)
.attr("x2",100)
.attr("y2",-25)
.attr("stroke-width","2px")
.attr("stroke","#f03");
nodeEnter.append("svg:line")
.attr("x1",-100)
.attr("y1",-40)
.attr("x2",100)
.attr("y2",-40)
.attr("stroke-width","2px")
.attr("stroke","#f03");
How can i add a second SVG:LINE object?
Here is the rest of my coding:
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.selectAll("rect")
.style("fill", function(d) { return d._children ? "#FF0033" : "#fff"; });
nodeUpdate.selectAll("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parents new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.selectAll("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = vis.selectAll("path.link")
.data(tree.links(nodes), function(d) { return d.target.id; });
// Enter any new links at the parents previous position.
link.enter().insert("svg:path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
})
.transition()
.duration(duration)
.attr("d", diagonal);
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parents 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 the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// Toggle children.
function toggle(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
}
Regards,
Anton

Resources