I am currently developing a program to create a graph(vertexes + edges) and apply an algorithm. I chose 3d.js to make this program.
I am confronted a problem about the repaintfunction when I add a vertex.
When I add the first vertex, it's work but for the following, my vertexes multiply rapidly(vertex&label)...
Screenshots:
Source code:
var graph = (function() {
return {
modules: {},
nodes: [],
links: []
}
})();
graph.modules.engin = (function() {
var w, h, circleWidth, svgApp, force, link, node, nodes;
var palette = {
"white": "#FFFFFF",
"gray": "#708284",
"orange": "#BD3613",
"red": "#D11C24",
"blue": "#2176C7"
};
return {
init: function() {
var w = 960,
h = 450;
circleWidth = 7;
svgApp = d3.select("body")
.append("svg:svg")
.attr("width", w)
.attr("height", h)
.attr("id", "svg")
.attr("pointer-events", "all")
.attr("viewBox", "0 0 " + w + " " + h)
.attr("perserveAspectRatio", "xMinYMid")
.append('svg:g');
force = d3.layout.force()
.nodes(graph.nodes)
.links([])
.gravity(0.1)
.charge(-1000)
.size([w, h]);
//console.log(nodes);
//nodes.push({})
graph.modules.engin.repaint();
graph.modules.engin.insertNode('V1');
graph.modules.engin.insertNode('V2');
graph.modules.engin.insertNode('V3');
},
repaint: function() {
console.log('update');
nodes = force.nodes();
var links = force.links();
link = svgApp.selectAll(".link")
.data(links);
link.enter().append("line")
.attr("class", "link")
.attr("stroke", palette.gray)
.attr("fill", "none");
link.exit().remove();
node = svgApp.selectAll("circle.node")
.data(nodes);
node.enter().append("g")
.attr("class", "node")
.on("mouseover", function(d, i) { //MOUSEOVER
if (!d.root) {
d3.select(this).selectAll("circle")
.transition()
.duration(250)
.style("cursor", "none")
.attr("r", circleWidth + 3)
.attr("fill", palette.orange);
d3.select(this).select("text")
.transition()
.style("cursor", "none")
.duration(250)
.style("cursor", "none")
.attr("font-size", "1.5em")
.attr("x", 15)
.attr("y", 5)
} else {
d3.select(this).selectAll("circle")
.style("cursor", "none");
d3.select(this).select("text")
.style("cursor", "none");
}
})
.on("mouseout", function(d, i) { //MOUSEOUT
if (!d.root) {
//CIRCLE
d3.select(this).selectAll("circle")
.transition()
.duration(250)
.attr("r", circleWidth)
.attr("fill", palette.blue);
//TEXT
d3.select(this).select("text")
.transition()
.duration(250)
.attr("font-size", "1em")
.attr("x", 8)
.attr("y", 4)
}
})
.call(force.drag);
node.append("svg:circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", circleWidth)
.attr("fill", function(d, i) {
if (!d.root) {
return palette.blue;
} else {
return palette.red
}
});
node.append("text")
.text(function(d, i) {
return d.name;
})
.attr("x", function(d, i) {
return circleWidth + 5;
})
.attr("y", function(d, i) {
if (!d.root) {
return circleWidth
} else {
return circleWidth + 5
}
})
.attr("font-family", "Bree Serif")
.attr("fill", function(d, i) {
return palette.white;
})
.attr("font-size", function(d, i) {
return "1em";
})
.attr("text-anchor", function(d, i) {
if (!d.root) {
return "beginning";
} else {
return "end"
}
});
node.exit().remove();
force.on("tick", function(e) {
node.attr("transform", function(d, i) {
return "translate(" + d.x + "," + d.y + ")";
});
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;
})
});
force.start();
},
insertNode: function(name) {
nodes.push({
name: name
})
graph.modules.engin.repaint();
}
}
})();
$(document).ready(function() {
graph.modules.engin.init();
});
html {
background-color: #042029;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<button onclick="addNodes()">Restart Animation</button>
Thank you,
YM
I solved my problem: variable ref mistake and selector elements:
Source code:
var graph = (function() {
return {
modules: {},
nodes: [],
links: []
}
})();
graph.modules.engin = (function() {
var w, h, circleWidth, svgApp, force;
var palette = {
"white": "#FFFFFF",
"gray": "#708284",
"orange": "#BD3613",
"red": "#D11C24",
"blue": "#2176C7"
};
return {
init: function() {
h = $('body').height();
w = $('body').width();
circleWidth = 7;
svgApp = d3.select("body")
.append("svg:svg")
.attr("pointer-events", "all")
.attr("width", w)
.attr("height", h)
.attr("viewBox", "0 0 " + w + " " + h)
.attr("perserveAspectRatio", "xMinYMid");
force = d3.layout.force();
graph.nodes = force.nodes();
graph.links = force.links();
graph.modules.engin.repaint();
graph.modules.engin.insertNode('V1');
graph.modules.engin.insertNode('V2');
graph.modules.engin.insertNode('V3');
},
repaint: function() {
console.log('update');
var nodes = force.nodes();
var links = force.links();
console.log('BEFORE REPAINT');
console.log(nodes);
console.log(links);
console.log(graph.nodes);
console.log(graph.links);
var link = svgApp.selectAll("line.link")
.data(links);
var linkEnter = link.enter().append("line")
.attr("class", "link")
.attr("stroke", palette.gray)
.attr("fill", "none");
link.exit().remove();
var node = svgApp.selectAll("g.node")
.data(nodes, function(d) {
return d.name;
});
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.on("mouseover", function(d, i) {
if (!d.root) {
d3.select(this).select("circle")
.transition()
.duration(250)
.style("cursor", "none")
.attr("r", circleWidth + 3)
.attr("fill", palette.yellow);
d3.select(this) //.select("text")
.transition()
.style("cursor", "none")
.duration(250)
.style("cursor", "none")
.attr("font-size", "1.5em")
.attr("x", 15)
.attr("y", 5)
} else {
d3.select(this).select("circle")
.style("cursor", "none");
d3.select(this).select("text")
.style("cursor", "none");
}
})
.on("mouseout", function(d, i) {
if (!d.root) {
d3.select(this).select("circle")
.transition()
.duration(250)
.attr("r", circleWidth)
.attr("fill", palette.blue);
d3.select(this) //.select("text")
.transition()
.duration(250)
.attr("font-size", "1em")
.attr("x", 8)
.attr("y", 4)
}
})
.call(force.drag);
nodeEnter.append("svg:circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", circleWidth)
.attr("fill", function(d, i) {
if (!d.root) {
return palette.blue;
} else {
return palette.red
}
}).attr("id", function(d) {
return "Node-" + d.name;
});
nodeEnter.append("svg:text")
.text(function(d, i) {
return d.name;
})
.attr("x", function(d, i) {
return circleWidth + 5;
})
.attr("y", function(d, i) {
if (!d.root) {
return circleWidth - 2
} else {
return circleWidth + 5
}
})
.attr("font-family", "Bree Serif")
.attr("fill", function(d, i) {
return palette.white;
})
.attr("font-size", function(d, i) {
return "1em";
})
.attr("text-anchor", function(d, i) {
if (!d.root) {
return "beginning";
} else {
return "end"
}
});
node.exit().remove();
force.on("tick", function(e) {
node.attr("transform", function(d, i) {
return "translate(" + d.x + "," + d.y + ")";
});
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;
})
});
force.gravity(0.1)
.charge(-1000)
.size([w, h])
.start();
},
insertNode: function(name) {
graph.nodes.push({
name: name
})
graph.modules.engin.repaint();
}
}
})();
$(document).ready(function() {
graph.modules.engin.init();
});
html {
background-color: #042029;
}
body {
height: 600px;
width: 100%;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<button onclick="addNodes()">Restart Animation</button>
Related
I am trying to wrap text which is parsed from a json response into my application.
I have two svg elements : rect and text. I want to find a way where I can wrap my svg text such that it fits in the rectangle.
( Picture Force layout with text labels and rectangles )
This is the link to the original project in which I have made modifications
Visualizing Reddit Discussions
setupGraph();
function setupGraph() {
$(".network").empty();
names = {};
nodecolor = {};
force = d3.layout.force()
.charge(-500)
.linkDistance(20)
.size([width, height]);
nodes = force.nodes(),
links = force.links();
force.on("tick", function() {
svg.selectAll("line.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;
});
svg.selectAll("rect.node")
.attr("x", function(d) {
return d.x - d.curWidth / 2;
})
.attr("y", function(d) {
return d.y - d.curHeight / 2;
});
svg.selectAll("text.node")
.attr("x", function(d) {
return d.x - d.curWidth / 2 + 8;
})
.attr("y", function(d) {
return d.y - d.curHeight / 2 + 20;
});
});
d3.select("svg").remove();
svg = d3.select("#chart").append("svg:svg")
.attr("width", width)
.attr("height", height)
.attr("class", "network");
}
function updateNetwork() {
var link = svg.selectAll("line.link")
.data(links, function(d) {
return d.source.id + "-" + d.target.id;
});
link.enter().insert("svg:line", "text.node", "rect.node")
.attr("class", "link")
.style("stroke-width", function(d) {
return 2;
})
.style("stroke", "gray")
.style("opacity", 0.1);
var node = svg.selectAll("rect.node")
.data(nodes, function(d) {
return d.id;
});
var node = svg.selectAll("text.node")
.data(nodes, function(d) {
return d.id;
});
var nodeEnter = node.enter().append("svg:rect")
.attr("class", "node")
.call(force.drag)
.attr("width", function(d) {
return d.curWidth;
})
.attr("height", function(d) {
return d.curHeight;
})
.style("opacity", 1.0)
.on("mouseover", displayTooltip)
.on("mousemove", moveTooltip)
.on("mouseout", removeTooltip)
.on("mouseover", function(d) {
d3.select(this).transition().attr("height", 100).attr("width", 100); //.style("fill", "red");
})
.call(force.drag)
var nodeEnterr = node.enter().append("svg:text")
.attr("class", "node")
.text(function(d) {
return d.name + ": " + d.body
})
.call(force.drag)
.style("opacity", 1.0)
.on("mouseover", displayTooltip)
.on("mousemove", moveTooltip)
.on("mouseout", removeTooltip)
.call(force.drag)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I currently have a D3 that displays a force directed network and will collapse its children on click. I would like to to also display the names of the nodes on hover. Something like this: https://bl.ocks.org/mbostock/1212215
Below is my code so far.
.node {
cursor: pointer;
stroke: #3182bd;
stroke-width: 1.5px;
}
.link {
fill: none;
stroke: #9ecae1;
stroke-width: 1.5px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500,
root;
var force = d3.layout.force()
.size([width, height])
.on("tick", tick);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
//Added markers to indicate that this is a directed graph
svg.append("defs").selectAll("marker")
.data(["arrow"])
.enter().append("marker")
.attr("id", function(d) { return d; })
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 4)
.attr("markerHeight", 4)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5");
var link = svg.selectAll(".link"),
node = svg.selectAll(".node");
d3.json("test.json", function(json) {
root = json;
//Give nodes ids and initialize variables
for(var i=0; i<root.nodes.length; i++) {
var node = root.nodes[i];
node.id = i;
node.collapsing = 0;
node.collapsed = false;
}
//Give links ids and initialize variables
for(var i=0; i<root.links.length; i++) {
var link = root.links[i];
link.source = root.nodes[link.source];
link.target = root.nodes[link.target];
link.id = i;
}
// for (var i=0; i<root.nodes.length; i++){
// var node = root.nodes[i];
// }
update();
});
function update() {
//Keep only the visible nodes
var nodes = root.nodes.filter(function(d) {
return d.collapsing == 0;
});
var links = root.links;
//Keep only the visible links
links = root.links.filter(function(d) {
return d.source.collapsing == 0 && d.target.collapsing == 0;
});
force
.nodes(nodes)
.links(links)
.start();
// Update the links…
link = link.data(links, function(d) { return d.id; });
// Exit any old links.
link.exit().remove();
// Enter any new links.
link.enter().insert("line", ".node")
.attr("class", "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; })
// Update the nodes…
node = node.data(nodes, function(d){ return d.id; }).style("fill", color);
// Exit any old nodes.
node.exit().remove();
// Enter any new nodes.
node.enter().append("circle")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
.style("fill", color)
.on("click", click)
.call(force.drag);
}
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("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
// Color leaf nodes orange, and packages white or blue.
function color(d) {
return d.collapsed ? "#3182bd" : d.children ? "#c6dbef" : "#fd8d3c";
}
// Toggle children on click.
function click(d) {
if (!d3.event.defaultPrevented) {
//check if link is from this node, and if so, collapse
root.links.forEach(function(l) {
if(l.source.id == d.id) {
if(d.collapsed){
l.target.collapsing--;
} else {
l.target.collapsing++;
}
}
});
d.collapsed = !d.collapsed;
}
update();
}
</script>
My issue is with the update function. I was able to get it to display, but when I clicked to collapse, it wouldn't show the labels after. Im not sure if I should be tweeting the tick or what.
thanks!
Group the circle and text labels using SVG group element as shown below.
var groupNodes = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate("+d.x+","+d.y+")"; });
.on("click", click)
.on("mouseover", function(){
d3.select(this).select("text").style("display","block");
})
.on("mouseout", function(){
d3.select(this).select("text").style("display","none");
})
.call(force.drag);
groupNodes.append("circle")
.attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
.style("fill", color);
var label = groupNodes.append("text")
.attr("dy", ".35em")
.style("display", "none)
.text(function(d) { return d.name; //Use the key which holds the name value });
The above code replaces following part of the code in the update function.
node.enter().append("circle")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
.style("fill", color)
.on("click", click)
.call(force.drag);
and now change the tick function as follows
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+")";
});
}
Now all other functionalities should work as expected.
I have this data :
[{"node":"A","group":"1","type":"node"},
{"node":"B","group":"2","type":"node"},
{"node":"D","group":"1","type":"node"},
{"node":"C","group":"2","type":"node"},
{"type":"link","interest":"1","source":"A","target":"B"},
{"type":"link","interest":"2","source":"A","target":"C"},
{"type":"link","interest":"10","source":"B","target":"C"},
{"type":"link","interest":"3","source":"D","target":"B"}]
Here is my code:
var force = d3.layout.force()
.nodes(data)
.size([+width(), +height()])
.gravity(.08)
.charge(-10)
.on("tick", tick)
.on("end", function(){
chart.dispatchEndDrawing()
})
.start();
var g = selection
.attr("width", width)
.attr("height", height);
var link = g.selectAll("line")
.data(data.filter(function (d){ return d.type == "link"; }))
.enter().append("line")
.style("stroke-width", function(d) { return d.interest; })
.style("stroke", "grey")
.call(force.drag);
var node = g.selectAll("circle")
.data(data.filter(function (d){ return d.type == "node"; }))
.enter().append("circle")
.attr("r", 5)
.style("fill", "blue")
.call(force.drag);
function tick(e) {
node
.attr("cx", function(d) { return d.x = Math.max(radius(), Math.min(width() - radius(), d.x)); })
.attr("cy", function(d) { return d.y = Math.max(radius(), Math.min(height()-10 - radius(), d.y)); });
link
.attr("x1", function(d) { return d3.selectAll('circle').filter(function (k) { return d.source === k.node; }).attr('cx');})
.attr("y1", function(d) { return d3.selectAll('circle').filter(function (k) { return d.source === k.node; }).attr('cy'); })
.attr("x2", function(d) { return d3.selectAll('circle').filter(function (k) { return d.target === k.node; }).attr('cx'); })
.attr("y2", function(d) { return d3.selectAll('circle').filter(function (k) { return d.target === k.node; }).attr('cy'); });
chart.dispatchStartDrawing()
}
})
I want to display 4 circles (A, B, C, D) in separate groups:
Group 1 - (A,D) | Group 2 - (B,C).
The grouping should be automatic by using the attribute "group".
The simulation is done by creating a d3 force layout object
I am making a timeline sort of project. As of right now, my code looks like the following:
var width = 960,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-300)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("input.json", function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); })
.style("visibility", function(d) {
return d.value == 2 ? "hidden" : "visible";
});
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 20)
.style("fill", function(d) { return color(d.group); })
.call(force.drag)
.style("visibility", function(d) {
return d.group == 1 ? "hidden" : "visible";
})
.on("mouseover", function(d) {
if(d.group == 2) {
node.filter(function(d) { return d.group == 1; }).style("visibility", "visible");
link.filter(function(d) { return d.value == 2; }).style("visibility", "visible");
texts.filter(function(d) { return d.value == 2; }).style("visibility", "visible");
}
}).on("mouseout", function(d) {
if(d.group == 2) {
node.filter(function(d) { return d.group == 1; }).style("visibility", "hidden");
link.filter(function(d) { return d.value == 2; }).style("visibility", "hidden");
}
});
var texts = svg.selectAll("text.label")
.data(graph.nodes)
.enter().append("text")
.attr("class", "label")
.attr("fill", "black")
.text(function(d) { return d.name; });
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; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
texts.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
});
As of right now, the text, or labelsconstantly show, even when the nodes and links don't. I'm wondering what I need to do? I don't know if I can assign a value or group to the labels
I still not understanding why the code bellow does not display its labels / text...
I have defined the css and set the attribute like the title when the move is over the node:
Json:
{
"nodes":[
{"name":"t1","group":1},
{"name":"t2","group":1},
{"name":"t3","group":1},
{"name":"t4","group":1},
{"name":"hate","group":2},
{"name":"good","group":2},
{"name":"aiport","group":3},
{"name":"flight","group":3}
],
"links":[
{"source":0,"target":4,"value":4},
{"source":0,"target":5,"value":4},
{"source":1,"target":4,"value":4},
{"source":2,"target":5,"value":4},
{"source":3,"target":5,"value":4},
{"source":4,"target":6,"value":4},
{"source":5,"target":6,"value":4},
{"source":5,"target":7,"value":4}
]
}
Code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
fill: #555;
stroke: #999;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 1024,
height = 768;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("data.json", function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll("line.link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll("circle.node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function(d) { return color(d.group); })
.call(force.drag);
node.append("title")
.text(function(d) { return d.name; });
node.append("text")
.text(function(d) { return d.name; });
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; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});
</script>
</body>
</html>
You are adding the text element inside the circle element - try running your code and have a look at the svg with the DOM inspector. I'm not sure text is allowed there. Instead add the text elements separately - like another rendering of the nodes:
var texts = svg.selectAll("text.label")
.data(graph.nodes)
.enter().append("text")
.attr("class", "label")
.attr("fill", "black")
.text(function(d) { return d.name; });
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; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
texts.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
Another option would be to add both circle and text elements inside a g container element as shown below:
var container = svg.selectAll("g.node").data(graph.nodes).enter().append("g")
.attr("class", "node")
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
}).call(force.drag);
container.append("circle")
.attr("r", 5)
.style("fill", color);
container.append("text")
.style("text-anchor", "middle")
.text(function (d) {
return d.name;
});
Here you can play with a working jsfiddle:
http://jsfiddle.net/vfu78/16/