How to achieve double click in Tree in D3.js? - javascript

I am new to D3.js.
JS for drawing tree :
var json =
{
"name": "Base",
"children": [
{
"name": "Type A",
"children": [
{
"name": "Section 1",
"children": [
{"name": "Child 1"},
{"name": "Child 2"},
{"name": "Child 3"}
]
},
{
"name": "Section 2",
"children": [
{"name": "Child 1"},
{"name": "Child 2"},
{"name": "Child 3"}
]
}
]
},
{
"name": "Type B",
"children": [
{
"name": "Section 1",
"children": [
{"name": "Child 1"},
{"name": "Child 2"},
{"name": "Child 3"}
]
},
{
"name": "Section 2",
"children": [
{"name": "Child 1"},
{"name": "Child 2"},
{"name": "Child 3"}
]
}
]
}
]
};
var width = 700;
var height = 650;
var maxLabel = 150;
var duration = 500;
var radius = 5;
var i = 0;
var j = 0;
var root;
var columnAttribute ;
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)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + maxLabel + ",0)")
;
root = json;
root.x0 = height / 2;
root.y0 = 0;
root.children.forEach(collapse);
function update(source)
{
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
var links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * maxLabel; });
// 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 + ")"; });
nodeEnter.append("circle")
.attr("r", 0)
.style("fill", function(d){
return d._children ? "lightsteelblue" : "white";
});
nodeEnter.append("text")
.attr("x", function(d){
var spacing = computeRadius(d) + 5;
return d.children || d._children ? -spacing : spacing;
})
.attr("dy", "3")
.attr("text-anchor", function(d){ return d.children || d._children ? "end" : "start"; })
.text(function(d){ return d.name; })
.style("fill-opacity", 0);
// 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", function(d){ return computeRadius(d); })
.style("fill", function(d) { return 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", 0);
nodeExit.select("text").style("fill-opacity", 0);
// 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;
});
}
function computeRadius(d)
{
if(d.children || d._children) return radius + (radius * nbEndNodes(d) / 10);
else return radius;
}
function nbEndNodes(n)
{
nb = 0;
if(n.children){
n.children.forEach(function(c){
nb += nbEndNodes(c);
});
}
else if(n._children){
n._children.forEach(function(c){
nb += nbEndNodes(c);
});
}
else nb++;
return nb;
}
function click(d)
{
if (d.children){
d._children = d.children;
d.children = null;
}
else{
d.children = d._children;
d._children = null;
}
update(d);
}
function collapse(d){
if (d.children){
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
update(root);
I want to save node name on double click on a node in columnAttribute variable.
For example, on click on node named Child 1 it save is in columnAttribute : ["Child 1"]. Similarly on click on node named Child 2 it save is in columnAttribute : ["Child 1","Child2"]
JSFiddle: http://jsfiddle.net/MetalMonkey/JnNwu/

You can just use the double click event (called dblclick) on newly created nodes:
var nodeEnter = node.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d){ return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click)
.on("dblclick", dblClick)
In the dblClick function, just add the name or whatever you want to columnAttribute:
var columnAttribute = [];
function dblClick(d) {
columnAttribute.push(d.name);
console.log(columnAttribute);
}
See this fiddle

Related

Cannot render path from source to target in D3.js, migrating v3 to v4 [duplicate]

This question already has answers here:
Where is d3.svg.diagonal()?
(5 answers)
Closed 5 years ago.
I've been trying to migrate from D3.js v3 to version 4. I've reviewed the changelog and updated all functions, but I'm unable to render the path from source to target nodes now that the diagonal function is removed.
I'm using a Parse Tree generated by a Python Script via HTML and d3.js. The Python Script generates an HMTL document, here it is running with D3.js version 3
function drawTree(){
var margin = {top: 20, right: 120, bottom: 20, left: 120},
width = 1060 - margin.right - margin.left,
height = 600 - margin.top - margin.bottom;
var i = 0,
duration = 750,// animation duration
root;// stores the tree structure in json format
var tree = d3.layout.tree()
.size([height, width]);
var edge_weight = d3.scale.linear()
.domain([0, 100])
.range([0, 100]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
// adding the svg to the html structure
var svg = d3.select("div#viz").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 treeData =
{
"name": "Grandparent",
"size" : 100,
"children": [
{
"name": "Parent A",
"size": 70,
"children": [
{ "name": "Son of A",
"size" : 30,
"children": [
{ "name": "grandson of A",
"size" : 3},
{ "name": "grandson 2 of A",
"size" : 2},
{ "name": "grandson 3 of A",
"size" : 5},
{ "name": "grandaughter of A",
"size" : 20,
"children": [
{ "name": "great-grandson of A",
"size" : 15},
{ "name": "great-grandaughter of A",
"size" : 5}
]
}
],
},
{ "name": "Daughter of A" ,
"size" : 40
}
]
},
{ "name": "Parent B",
"size" : 30 }],
};
edge_weight.domain([0,treeData.size]);
// Assigns parent, children, height, depth
root = treeData;
root.x0 = height / 2;
root.y0 = 0;
root.children.forEach(collapse);
update(root);
d3.select(self.frameElement).style("height", "800px");
/**
* Updates the node.
* cloppases and expands the node bases on the structure of the source
* all 'children' nodes are expanded and '_children' nodes collapsed
* #param {json structure} source
*/
function update(source) {
// 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('class', 'node')
.attr('r', 1e-6)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.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", function(d){ console.log(">>>>>>>>", d);return edge_weight(d.size/2);})
.style("fill", function(d) {
return 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…
// 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("stroke-width", function(d){
return 1;
})
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
})
.attr("stroke", function(d){
return "lavender";});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", function(d){
/* calculating the top shift */
var source = {x: d.source.x - edge_weight(calculateLinkSourcePosition(d)), y: d.source.y};
var target = {x: d.target.x, y: d.target.y};
return diagonal({source: source, target: target});
})
.attr("stroke-width", function(d){
return edge_weight(d.target.size);
});
// 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;
});
}
/**
* Calculates the source y-axis position of the link.
* #param {json structure} link
*/
function calculateLinkSourcePosition(link) {
targetID = link.target.id;
var childrenNumber = link.source.children.length;
var widthAbove = 0;
for (var i = 0; i < childrenNumber; i++)
{
if (link.source.children[i].id == targetID)
{
// we are done
widthAbove = widthAbove + link.source.children[i].size/2;
break;
}else {
// keep adding
widthAbove = widthAbove + link.source.children[i].size
}
}
return link.source.size/2 - widthAbove;
}
/*
* Toggle children on click.
* #param {node} d
*/
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
/*
* Collapses the node d and all the children nodes of d
* #param {node} d
*/
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
/*
* Collapses the node in the tree
*/
function collapseAll() {
root.children.forEach(collapse);
update(root);
}
/*
* Expands the node d and all the children nodes of d
* #param {node} d
*/
function expand(d) {
if (d._children) {
d._children = null;
}
if (d.children) {
d.children.forEach(expand);
}
}
/*
* Expands all the nodes in the tree
*/
function expandAll() {
root.children.forEach(expand);
update(root);
}
}
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
}
.link {
fill: none;
/*stroke: steelblue;*/
opacity: 0.3;
/*stroke-width: 1.5px;*/
}
#levels{
margin-left: 120px;
}
<!DOCTYPE html>
<meta charset="utf-8">
<body onLoad="drawTree()">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.min.js"></script>
<button type="button" onclick="collapseAll()">Collapse All</button>
<button type="button" onclick="expandAll()">Expand All</button>
<div id="viz"></div>
</body>
And here's as far as I got with the v4 migration.
var margin = {
top: 20,
right: 120,
bottom: 20,
left: 120
},
width = 900 - margin.right - margin.left,
height = 400 - margin.top - margin.bottom;
var i = 0,
duration = 750, // animation duration
root; // stores the tree structure in json format
// declares a tree layout and assigns the size
var treemap = d3.tree().size([height, width]);
var edge_weight = d3.scaleLinear()
.domain([0, 100])
.range([0, 100]);
// Creates a curved (diagonal) path from parent to the child nodes
function diagonal(s, d) {
path = `M ${s.y} ${s.x}
C ${(s.y + d.y) / 2} ${s.x},
${(s.y + d.y) / 2} ${d.x},
${d.y} ${d.x}`
return path
}
// adding the svg to the html structure
var svg = d3.select("div#viz").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 treeData = {
"name": "Grandparent",
"size": 100,
"children": [{
"name": "Parent A",
"size": 70,
"children": [{
"name": "Son of A",
"size": 30,
"children": [{
"name": "grandson of A",
"size": 3
},
{
"name": "grandson 2 of A",
"size": 2
},
{
"name": "grandson 3 of A",
"size": 5
},
{
"name": "grandaughter of A",
"size": 20,
"children": [{
"name": "great-grandson of A",
"size": 15
},
{
"name": "great-grandaughter of A",
"size": 5
}
]
}
],
},
{
"name": "Daughter of A",
"size": 40
}
]
},
{
"name": "Parent B",
"size": 30
}
],
};
edge_weight.domain([0, treeData.size]);
// Assigns parent, children, height, depth
root = d3.hierarchy(treeData, function(d) {
return d.children;
});
root.x0 = height / 2;
root.y0 = 0;
root.children.forEach(collapse);
update(root);
d3.select(self.frameElement).style("height", "800px");
/**
* Updates the node.
* cloppases and expands the node bases on the structure of the source
* all 'children' nodes are expanded and '_children' nodes collapsed
* #param {json structure} source
*/
function update(source) {
// Assigns the x and y position for the nodes
var treeData = treemap(root);
// Compute the new tree layout.
var nodes = treeData.descendants(),
links = treeData.descendants().slice(1);
// 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('class', 'node')
.attr('r', 1e-6)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.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 = nodeEnter.merge(node);
nodeUpdate.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
});
nodeUpdate.select("circle")
.attr("r", function(d) {
return edge_weight(d.data.size / 2);
})
.style("fill", function(d) {
return 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.id;
});
//.data(links, function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
var linkEnter = link.enter().insert('path', "g")
.attr("class", "link")
.attr('d', function(d) {
console.log("linkEnter", d);
var o = {
x: source.x,
y: source.y
}
console.log("o", o);
return diagonal(o, o)
})
.attr("stroke", function(d) {
return "cyan";
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", function(d) {
console.log("lala", d);
/* calculating the top shift */
var source = {
x: d.x - edge_weight(calculateLinkSourcePosition(d)),
y: d.y
};
var target = {
x: d.parent.x,
y: d.parent.y
};
return diagonal({
source: source,
target: target
});
})
.attr("stroke-width", function(d) {
return edge_weight(d.target.size);
});
// 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) {
console.log("stash", d);
d.x0 = d.x;
d.y0 = d.y;
});
}
/**
* Calculates the source y-axis position of the link.
* #param {json structure} link
*/
function calculateLinkSourcePosition(link) {
targetID = link.target.id;
var childrenNumber = link.source.children.length;
var widthAbove = 0;
for (var i = 0; i < childrenNumber; i++) {
if (link.source.children[i].id == targetID) {
// we are done
widthAbove = widthAbove + link.source.children[i].size / 2;
break;
} else {
// keep adding
widthAbove = widthAbove + link.source.children[i].size
}
}
return link.source.size / 2 - widthAbove;
}
/*
* Toggle children on click.
* #param {node} d
*/
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
/*
* Collapses the node d and all the children nodes of d
* #param {node} d
*/
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
/*
* Collapses the node in the tree
*/
function collapseAll() {
root.children.forEach(collapse);
update(root);
}
/*
* Expands the node d and all the children nodes of d
* #param {node} d
*/
function expand(d) {
if (d._children) {
d.children = d._children;
d._children = null;
}
if (d.children) {
d.children.forEach(expand);
}
}
/*
* Expands all the nodes in the tree
*/
function expandAll() {
root.children.forEach(expand);
update(root);
}
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
}
.link {
fill: none;
/*stroke: steelblue;*/
opacity: 0.3;
/*stroke-width: 1.5px;*/
}
#levels {
margin-left: 120px;
}
<body>
<script src="http://d3js.org/d3.v4.min.js"></script>
<button type="button" onclick="collapseAll()">Collapse All</button>
<button type="button" onclick="expandAll()">Expand All</button>
<div id="viz"></div>
</body>
Most likely I'm just blind and you'll instantly see what I did wrong, but I've been staring at this for a while now...
Thanks in advance for any help!
I'm currently working on a similar project myself and figured this could be pretty helpful.. It seems you were really close, just needed to adjust a few minor paths to reach parent/child nodes..
Basically "source" is now "parent" and there is no "target". You can see most of the updates where commented out lines are v3 with v4 updates just below. For example:
link.target.id --> link.id
link.source.children.length --> link.parent.children.length
link.source.size --> link.parent.data.size
There's a few other miscellaneous updates throughout the code as well. The one thing I couldn't get working fully were the "Expand All/Collapse All" buttons. "Expand All" seems to work ok, but "Collapse All" seems to leave the link paths alone..
Here's a working fiddle: https://jsfiddle.net/jufra0b2/
I suspect there's something that can be done to the exit link but not sure. Anyways it's a step in the right direction. Hope you figure out the rest ok..

Select all the paths and parent nodes of a child node in tree layout

I'm following this
tutorial to learn d3 js tree layout and i'm playing around with it. On clicking a child node I'm trying to select all the ancestor nodes and the paths connecting them.
I have changed the default click function in the tutorial to something that looks like this.
function click(d) {
console.log(d.parent);
while(d.parent)
{
d = d.parent;
console.log(d.parent);
}
}
This select all the ancestor nodes one by one , but how can i select all the connecting paths between them ?
For eg: If i want to color all the ancestor nodes and the connecting paths , how can i do that ?
var treeData = [{
"name": "Top Level",
"parent": "null",
"children": [{
"name": "Level 2: A",
"parent": "Top Level",
"children": [{
"name": "Son of A",
"parent": "Level 2: A"
}, {
"name": "Daughter of A",
"parent": "Level 2: A"
}]
}, {
"name": "Level 2: B",
"parent": "Top Level"
}]
}];
// ************** Generate the tree diagram *****************
var margin = {
top: 20,
right: 120,
bottom: 20,
left: 120
},
width = 960 - margin.right - margin.left,
height = 500 - 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 = 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 + ")");
root = treeData[0];
root.x0 = height / 2;
root.y0 = 0;
update(root);
d3.select(self.frameElement).style("height", "500px");
function update(source) {
// 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", 1e-6)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.append("text")
.attr("x", function(d) {
return d.children || d._children ? -13 : 13;
})
.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", 10)
.style("fill", function(d) {
return 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) {
console.log(d.parent);
while (d.parent) {
d = d.parent;
console.log(d.parent);
}
}
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.node text {
font: 12px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
First give Ids to link path like this:
link.enter().insert("path", "g")
.attr("class", "link")
.attr("id", function(d){ return ("link" + d.source.id + "-" + d.target.id)})//unique id
Then give id to all nodes.
nodeEnter.append("circle")
.attr("r", 1e-6)
.attr("id", function(d){return "node" + d.id;})//id of the node.
Then in the click function do the selection based on the ids:
function click(d) {
//reset all nodes color
d3.selectAll("circle").style("fill", "white");//reset all node colors
d3.selectAll("path").style("stroke", "#c3c3c3");//reset the color for all links
while (d.parent) {
d3.selectAll("#node"+d.id).style("fill", "red");//color the node
if (d.parent != "null")
d3.selectAll("#link"+d.parent.id + "-" + d.id).style("stroke", "red");//color the path
d = d.parent;
}
}
Working code here
EDIT: Plunker adapted to stack snippet:
var treeData = [{
"name": "Top Level",
"parent": "null",
"children": [{
"name": "Level 2: A",
"parent": "Top Level",
"children": [{
"name": "Son of A",
"parent": "Level 2: A"
}, {
"name": "Daughter of A",
"parent": "Level 2: A"
}]
}, {
"name": "Level 2: B",
"parent": "Top Level"
}]
}];
// ************** Generate the tree diagram *****************
var margin = {
top: 20,
right: 120,
bottom: 20,
left: 120
},
width = 960 - margin.right - margin.left,
height = 180 - 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 = 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 + ")");
root = treeData[0];
root.x0 = height / 2;
root.y0 = 0;
update(root);
d3.select(self.frameElement).style("height", "500px");
function update(source) {
// 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", 1e-6)
.attr("id", function(d){return "node" + d.id;})
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.append("text")
.attr("x", function(d) {
return d.children || d._children ? -13 : 13;
})
.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", 10)
.style("fill", function(d) {
return 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("id", function(d){ return ("link" + d.source.id + "-" + d.target.id)})
.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) {
//reset all nodes color
d3.selectAll("circle").style("fill", "white");
d3.selectAll("path").style("stroke", "#c3c3c3");
while (d.parent) {
d3.selectAll("#node"+d.id).style("fill", "red")
if (d.parent != "null")
d3.selectAll("#link"+d.parent.id + "-" + d.id).style("stroke", "red")
d = d.parent;
}
}
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.node text {
font: 12px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
D3 v6 example here.

D3 Tree orientation

I'm working with the D3 Tree layout, similar to this jsfiddle, the only problem is that I need the orientation of each node to start at the top left of the layout and not on the top center.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
});
Something similar to this:
Any ideas on how to do that?
Thank you in advance.
Building off of this example.
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// figure out the placement of the "top-most" node at each depth
var nodeMap = {};
nodes.forEach(function(d) {
if (!nodeMap[d.depth] || d.x < nodeMap[d.depth]){
nodeMap[d.depth] = d.x;
}
});
// shift all nodes up
nodes.forEach(function(d) {
d.y = d.depth * 100;
d.x -= nodeMap[d.depth];
});
This produces:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tree Example</title>
<style>
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.node text {
font: 12px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
</style>
</head>
<body>
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var treeData = [
{
"name": "Top Level",
"parent": "null",
"children": [
{
"name": "Level 2: A",
"parent": "Top Level",
"children": [
{
"name": "Son of A",
"parent": "Level 2: A"
},
{
"name": "Daughter of A",
"parent": "Level 2: A"
}
]
},
{
"name": "Level 2: B",
"parent": "Top Level",
"children": [
{
"name": "Son of B",
"parent": "Level 2: B"
},
{
"name": "Daughter of B",
"parent": "Level 2: B"
}
]
}
]
}
];
// ************** Generate the tree diagram *****************
var margin = {top: 20, right: 120, bottom: 20, left: 120},
width = 960 - margin.right - margin.left,
height = 500 - 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 = 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 + ")");
root = treeData[0];
root.x0 = height / 2;
root.y0 = 0;
update(root);
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth.
var nodeMap = {};
nodes.forEach(function(d) {
if (!nodeMap[d.depth] || d.x < nodeMap[d.depth]){
nodeMap[d.depth] = d.x;
}
});
nodes.forEach(function(d) {
d.y = d.depth * 100;
d.x -= nodeMap[d.depth];
});
// 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", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeEnter.append("text")
.attr("x", function(d) { return d.children || d._children ? -13 : 13; })
.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", 10)
.style("fill", function(d) { return 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) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
</script>
</body>
</html>
not only the nodes (x,y) should be interchanged but also the links connecting the nodes i.e.
var diagonal = d3.svg.diagonal()
.projection(function(d) {return [d.y,d.x];});
have a look at this example i made
<!doctype html>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script>
var data = {
"name" : "A",
"children" : [
{
"name" : "B",
"children" : [
{
"name" : "F"
},
{
"name" : "G"
}
]
},
{
"name" : "C",
"children" : [
{
"name" : "H"
},
{
"name" : "I"
},
{
"name" : "J"
}
]
},
{
"name" : "D",
"children" : [
{
"name" : "K"
},
{
"name" : "L"
}
]
},
{
"name" : "E"
}
]
};
var canvas = d3.select("body")
.append("svg")
.attr("width",600)
.attr("height",500)
.append("g")
.attr("transform","translate(50,50)");
var cluster = d3.layout.cluster()
.size([400,400]);
var nodes = cluster.nodes(data);
var links = cluster.links(nodes);
var node = canvas.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class","node")
.attr("transform",function(d) {return "translate(" + d.y + "," + d.x + ")"});
node.append("circle")
.attr("r",5)
.attr("fill","silver");
node.append("text")
.text(function(d) {return d.name;});
var diagonal = d3.svg.diagonal()
.projection(function(d) {return [d.y,d.x];});
canvas.selectAll(".link")
.data(links)
.enter()
.append("path")
.attr("class","link")
.attr("fill","none")
.attr("stroke","#ADADAD")
.attr("d",diagonal);
</script>

Extending d3js hierarchical tree for representing topology

We want to use d3js hierarchical tree for representing topology.
The features that we are looking for are:
Peer to peer linking
Child with 2 parents
Link between two objects represented as straight line instead of default curves.
These features are not supported by default, has anybody modified the D3js code to support any of the above mentioned features? Or is aware of any wrapper library which can be used?
Suggestion of any other library which support above feature will also help.
Attaching image for refrence
JSFiddle link: http://jsfiddle.net/MetalMonkey/JnNwu/
var json =
{
"name": "Base",
"children": [
{
"name": "Type A",
"children": [
{
"name": "Section 1",
"children": [
{"name": "Child 1"},
{"name": "Child 2"},
{"name": "Child 3"}
]
},
{
"name": "Section 2",
"children": [
{"name": "Child 1"},
{"name": "Child 2"},
{"name": "Child 3"}
]
}
]
},
{
"name": "Type B",
"children": [
{
"name": "Section 1",
"children": [
{"name": "Child 1"},
{"name": "Child 2"},
{"name": "Child 3"}
]
},
{
"name": "Section 2",
"children": [
{"name": "Child 1"},
{"name": "Child 2"},
{"name": "Child 3"}
]
}
]
}
]
};
var width = 700;
var height = 650;
var maxLabel = 150;
var duration = 500;
var radius = 5;
var i = 0;
var 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)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + maxLabel + ",0)");
root = json;
root.x0 = height / 2;
root.y0 = 0;
root.children.forEach(collapse);
function update(source)
{
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
var links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * maxLabel; });
// 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", 0)
.style("fill", function(d){
return d._children ? "lightsteelblue" : "white";
});
nodeEnter.append("text")
.attr("x", function(d){
var spacing = computeRadius(d) + 5;
return d.children || d._children ? -spacing : spacing;
})
.attr("dy", "3")
.attr("text-anchor", function(d){ return d.children || d._children ? "end" : "start"; })
.text(function(d){ return d.name; })
.style("fill-opacity", 0);
// 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", function(d){ return computeRadius(d); })
.style("fill", function(d) { return 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", 0);
nodeExit.select("text").style("fill-opacity", 0);
// 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;
});
}
function computeRadius(d)
{
if(d.children || d._children) return radius + (radius * nbEndNodes(d) / 10);
else return radius;
}
function nbEndNodes(n)
{
nb = 0;
if(n.children){
n.children.forEach(function(c){
nb += nbEndNodes(c);
});
}
else if(n._children){
n._children.forEach(function(c){
nb += nbEndNodes(c);
});
}
else nb++;
return nb;
}
function click(d)
{
if (d.children){
d._children = d.children;
d.children = null;
}
else{
d.children = d._children;
d._children = null;
}
update(d);
}
function collapse(d){
if (d.children){
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
update(root);
I need to draw edge between Type A and Type B node which are at same level
It has already been answered here : StackOverflow question.
The only difference is the way you handle X versus Y positions. You have to declare :
var line = d3.svg.line()
.x( function(point) { return point.ly; })
.y( function(point) { return point.lx; });
function lineData(d){
var points = [
{lx: d.source.x, ly: d.source.y},
{lx: d.target.x, ly: d.target.y}
];
return line(points);
}
Please pay attention to the invertion of X and Y in line function declaration.
Then in your code (in attr('d') calls) instead of using diagonal just use lineData.

D3 horizontal tree layout with rect and text wrapping

Have been struggling for ages to create a horizontal tree layout with rectangles instead of circles, and have the text wrap inside those rectangles. Nothing I do seems to work, I have tried this code but whoever made it has left out a crucial step, in defining the variable d before the line
if (d.name.length > 26) which stops the whole script from running.
I have also been trying to use d3plus.js from http://d3plus.org/ in order to wrap text inside rect tags but it actually doesn't work half the time and seems to need a trigger like a click function in order to work. Also considering using this example as a guide on text wrapping.
In my research I have not found that anybody has done the combination of horizontal, rectangles and wrapped text in one diagram.
Also I am a bit of a d3 noob so all help is appreciated.
Here is a JSFiddle.
Here is the current code I am using which isn't working:
var w = 960,
h = 2000,
i = 0,
duration = 500,
root;
var tree = d3.layout.tree()
.size([h, w - 160]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var vis = d3.select("#container").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(40,0)");
root = treeData[0];
root.x0 = h / 2;
root.y0 = 0;
update(root);
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; });
// Enter any new nodes at the parent's previous position.
nodeEnter.append("svg:rect")
.attr("width", 150)
.attr("height", function(d) { return (d.name.length > 30) ? 38 : 19;})
.attr("y",-11)
.attr("rx",2)
.attr("ry",2)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; })
.on("click", click);
if (d.name.length > 26) {
nodeEnter.append("svg:text")
.attr("x", function(d) { return d._children ? -8 : 8; })
.attr("y", 3)
.text(function(d) { return d.name; });
} else {
nodeEnter.append("svg:text")
.attr("x", function(d) { return d._children ? -8 : 8; })
.attr("y", 3)
.append("svg:tspan")
.text(function(d) { return d.name.slice(0,26); })
.append("svg:tspan")
.attr("x", function(d) { return d._children ? -8 : 8; })
.attr("y",15)
.text(function(d) { return d.name.slice(26); });
}
}
// Transition nodes to their new position.
nodeEnter.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
.style("opacity", 1)
.select("rect")
.style("fill", "lightsteelblue");
node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
.style("opacity", 1);
node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.style("opacity", 1e-6)
.remove();
// 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 parent's 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 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) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
d3.select(self.frameElement).style("height", "2000px");
As well as my json:
var treeData = [
{
"name": "Do trainees require direction as to what to do or how to do the task (either before they start or while they are completing it?",
"children": [
{
"name": "Can they satisfactorily complete the task assigned to them?",
"children": [
{
"name": "Rating level 4",
"parent": "A",
},
{
"name": "How many problems / queries are there that still need to be addressed / resolved to be able to satisfactorily complete the task?",
"children": [
{
"name": "Are problems / queries fundamental to the completion of the task at hand?",
"children": [
{
"name": "Rating level 4",
},
{
"name": "Can the problems be resolved by the trainee (after receiving guidance)?",
"children": [
{
"name": "Rating level 3",
},
{
"name": "Can the problems be resolved by the trainee (after receiving guidance)?",
"children": [
{
"name": "Rating level 2",
},
{
"name": "Rating level 1",
}
]
}
]
}
]
},
{
"name": "Are problems / queries fundamental to the completion of the task at hand?",
}
]
}
]
},
{
"name": "Can they satisfactorily complete the task assigned to them?",
"children": [
{
"name": "Rating 1",
},
{
"name": "Rating 2",
},
{
"name": "Rating 3",
},
{
"name": "Rating 4",
}
]
}
]
}];
Your code throws an error at this line:
if (d.name.length > 26) {
d isn't defined. When d3 code references d, it's usually in the scope of a data binding. At this place in the code, you are not looping a binding, like:
nodeEnter.append("text")
.attr("x", function(d) {
return d._children ? -8 : 8;
})
.attr("y", 3)
.attr("dy", "0em")
.text(function(d) {
return d.name; // d is defined from the binding
});
That said, I like the wrap function you link to. So add your text like above and then wrap the text:
wrap(d3.selectAll('text'),150);
Here's a quick modification to the wrap that'll resize your rects as well:
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
// find corresponding rect and reszie
d3.select(this.parentNode.children[0]).attr('height', 19 * (lineNumber+1));
});
}
Example here.

Categories