How to append element to div with id using d3js javascript - javascript

I am using http://d3js.org/d3.v3.min.js.
I have code that append svg to my body html element.
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 + ")");
This code append <svg> to <body>
I am new in javascript and i don't know how to write code that append this svg to my div: <div id="svg">
I try: var svg = d3.select(document.getElementById("svg")).append("svg")... but it not working.
Thank you for any help!
Edit:
There is a full code for testing
<style>
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.node text { font: 12px sans-serif; }
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
</style>
<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"
}
]
}
];
// ************** 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;
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("div#tree").append("svg")
var svg = d3.select("#tree").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];
update(root);
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;
});
// Declare the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function (d) {
return d.id || (d.id = ++i);
});
// Enter the nodes.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function (d) {
return "translate(" + d.y + "," + d.x + ")";
});
nodeEnter.append("circle")
.attr("r", 10)
.style("fill", "#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", 1);
// Declare the links…
var link = svg.selectAll("path.link")
.data(links, function (d) {
return d.target.id;
});
// Enter the links.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", diagonal);
}
</script>

Simply use d3.select("#svg").

Related

D3 Sankey diagram links do not cover the entire node height

I am using D3.js to produce Sankey diagrams, and I'm not satisfied with the resulting connection between nodes, particularly when the total input of a node is different from its total output.
As an example:
// set the dimensions and margins of the data
var margin = { top: 10, right: 10, bottom: 10, left: 10 },
width = 300 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#graph").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(10)
.nodePadding(10)
.size([width, height]);
data = {
"nodes": [
{ "node": 0, "name": "A" },
{ "node": 1, "name": "B" },
{ "node": 2, "name": "C" }
],
"links": [
{ "source": 0, "target": 1, "value": 2 },
{ "source": 1, "target": 2, "value": 1 }
]
}
// Constructs a new Sankey generator with the default settings.
sankey
.nodes(data.nodes)
.links(data.links)
.layout(1);
// add in the links
svg.append("g")
.selectAll(".link")
.data(data.links)
.enter()
.append("path")
.attr("class", "link")
.attr("d", sankey.link())
.style("stroke-width", function (d) { return Math.max(1, d.dy); })
// add in the nodes
var node = svg.append("g")
.selectAll(".node")
.data(data.nodes)
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; })
// add the rectangles for the nodes
node.append("rect")
.attr("height", function (d) { return d.dy; })
.attr("width", sankey.nodeWidth())
// add in the title for the nodes
node.append("text")
.attr("x", -6)
.attr("y", function (d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function (d) { return d.name; })
.filter(function (d) { return d.x < width / 2; })
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start")
<body>
<style>
.link {
fill: none;
stroke: #000;
stroke-opacity: .2;
}
</style>
<div id="graph"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/holtzy/D3-graph-gallery#master/LIB/sankey.js"></script>
<script src="test.js"></script>
</body>
This produces:
But without chaning the input data I would like:
Meaning the node size is determined by the link value, but the link size matches both the input and the output nodes.

insert text in the links of the tree in d3

var treeData = [
{
"name": "glucose_tol",
"directions": ">",
"thresholds": "126",
"exits": 0.0,
"children": [
{
"name": "age",
"directions": ">",
"thresholds": "29",
"exits": 1.0,
"children": [
{
"name": true
},
{
"name": "mass_index",
"directions": ">",
"thresholds": "29.7",
"exits": 0.5,
"children": [
{
"name": true
},
{
"name": false
}
]
}
]
},
{
"name": false
}
]
},
];
// ************** 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;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.x, d.y]; });
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];
update(root);
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 * 120; });
// Declare the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter the nodes.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"; });
nodeEnter.append("circle")
.attr("r", 10)
.style("fill", "#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", 1);
// Declare the links…
var link = svg.selectAll("path.link")
.data(links, function(d) { return d.target.id; });
// Enter the links.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", diagonal);
// Add threshold and directions
link.enter().insert("text")
.attr("font-family", "Arial, Helvetica, sans-serif")
.attr("fill", "Black")
.style("font", "normal 12px Arial")
.attr("transform", function(d) {
return "translate(" +
((d.source.x + d.target.x)/2) + "," +
((d.source.y + d.target.y)/2) + ")";
})
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) {
//check whether thresholds is not undefined && that target.thresholds is not undefined as it will print on both sides
if (d.source.thresholds !== undefined)
if(d.target.thresholds !== undefined)
return d.source.thresholds + ' ' + d.source.directions;
})
}
.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.5.17/d3.min.js"></script>
I am having a problem adding text in middle of the links to a tree, because the last level of the tree doesn't give me any text. This is the code I have to add the text in the links:
// Add threshold and directions
link.enter().insert("text")
.attr("font-family", "Arial, Helvetica, sans-serif")
.attr("fill", "Black")
.style("font", "normal 12px Arial")
.attr("transform", function(d) {
return "translate(" +
((d.source.x + d.target.x)/2) + "," +
((d.source.y + d.target.y)/2) + ")";
})
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) {
//check whether thresholds is not undefined && that target.thresholds is not undefined as it will print on both sides
if (d.source.thresholds !== undefined)
if(d.target.thresholds !== undefined)
return d.source.thresholds + ' ' + d.source.directions;
})
if I comment these two lines : if (d.source.thresholds !== undefined) and if(d.target.thresholds !== undefined) then I get the text on all the links but on both sides, which I don't want. How do I get the text only on one side but also on the last level.
First of all you need to have a way to find out whether the current node is on the last level, or if there are more levels under it. For this we will implement a maxDepth variable that will store a maximum value of depth attribute for all nodes. This is done in the update(root) function:
// Normalize for fixed-depth.
var maxDepth = 0;
nodes.forEach(function(d) { d.y = d.depth * 120; maxDepth = (d.depth>maxDepth)?d.depth:maxDepth;});
Next we add two additional checks to the second if statement like this:
if(d.target.thresholds !== undefined || d.target.name === true && d.target.depth == maxDepth)
It will make sure the text is added to true node only on the last level.
var treeData = [
{
"name": "glucose_tol",
"directions": ">",
"thresholds": "126",
"exits": 0.0,
"children": [
{
"name": "age",
"directions": ">",
"thresholds": "29",
"exits": 1.0,
"children": [
{
"name": true
},
{
"name": "mass_index",
"directions": ">",
"thresholds": "29.7",
"exits": 0.5,
"children": [
{
"name": true
},
{
"name": false
}
]
}
]
},
{
"name": false
}
]
},
];
// ************** 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;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.x, d.y]; });
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];
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 maxDepth = 0;
nodes.forEach(function(d) { d.y = d.depth * 120; maxDepth = (d.depth>maxDepth)?d.depth:maxDepth;});
// Declare the nodes.
var node = svg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter the nodes.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"; });
nodeEnter.append("circle")
.attr("r", 10)
.style("fill", "#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", 1);
// Declare the links…
var link = svg.selectAll("path.link")
.data(links, function(d) { return d.target.id; });
// Enter the links.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", diagonal);
// Add threshold and directions
link.enter().insert("text")
.attr("font-family", "Arial, Helvetica, sans-serif")
.attr("fill", "Black")
.style("font", "normal 12px Arial")
.attr("transform", function(d) {
return "translate(" +
((d.source.x + d.target.x)/2) + "," +
((d.source.y + d.target.y)/2) + ")";
})
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) {
//check whether thresholds is not undefined && that target.thresholds is not undefined as it will print on both sides
if (d.source.thresholds !== undefined)
if(d.target.thresholds !== undefined || d.target.name === true && d.target.depth == maxDepth)
return d.source.thresholds + ' ' + d.source.directions;
})
}
.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.5.17/d3.min.js"></script>

Put a timeline to a D3.js Tree graph

I am completely new to the D3.js so this might be an easy question. I have a simple D3 tree graph and in my treeData json I have a “date” component for each node. How can I glue the time line below the tree graph so that each node corresponds to the date in the timeline?
Below is the complete code. I have tried to find a similar example that works, couldn't find anything. Found an example here but it does not work:
d3.js - Having a tree layout, how to change the X-axis to use a time scale in D3?
var treeData = [{
"name": "Top Level",
"date": "12-Jan-15",
"parent": "null",
"children": [{
"name": "Level 2: A",
"date": "13-Mar-16",
"parent": "Top Level",
"children": [{
"name": "Son of A",
"date": "1-Aug-16",
"parent": "Level 2: A"
}, {
"name": "Daughter of A",
"date": "5-Sep-16",
"parent": "Level 2: A"
}]
}, {
"name": "Level 2: B",
"date": "12-Jan-17",
"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;
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("#tree").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];
update(root);
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;
});
// Declare the nodes
var node = svg.selectAll("g.node")
.data(nodes, function(d) {
return d.id || (d.id = ++i);
});
// Enter the nodes.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
});
nodeEnter.append("circle")
.attr("r", 10)
.style("fill", "#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", 1);
// Declare the links
var link = svg.selectAll("path.link")
.data(links, function(d) {
return d.target.id;
});
// Enter the links.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", diagonal);
}
.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://d3js.org/d3.v3.min.js"></script>
<div id="tree">
</div>
<div id="time">
</div>
Here is the answer that can be used when creating the timeline to a D3 tree graph. The code has comments, it should be clear what it does. Save it as .html and it should work in browser.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Simple Tree Example</title>
<style>
.node circle {
fill: steelblue;
stroke: grey;
stroke-width: 3px;
}
.node text {
font: 12px sans-serif;
}
/* link is for the lines */
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
z-index: -1;
}
.axis path,
.axis line {
fill: none;
stroke: slategray;
shape-rendering: crispEdges;
}
.x.axis line,
.x.axis path {
fill: none;
stroke: #000;
}
</style>
</head>
<body>
</div>
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var treeData = [{
"name": "Root",
"date": "01-01-2017",
"children": [{
"name": "A",
"date": "01-02-2017",
"children": [
{
"name": "B",
"date": "01-05-2017",
"children": [{
"name": "C",
"date": "01-06-2017",
"children": [{
"name": "D",
"date": "01-07-2017",
}]
}]
}
]
}
]
}];
// ************** Generate the tree diagram *****************
var margin = {
top: 20,
right: 60,
bottom: 20,
left: 120
},
width = 1000 - margin.right - margin.left,
height = 200 - margin.top - margin.bottom;
var i = 0;
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),
g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
root = treeData[0];
var nodes = tree.nodes(root).reverse();
var maxdate = d3.max(nodes, function (d) {
return new Date(d.date.replace(/(\d{2})-(\d{2})-(\d{4})/, "$1/$2/$3"));
});
var mindate = d3.min(nodes, function (d) {
return new Date(d.date.replace(/(\d{2})-(\d{2})-(\d{4})/, "$1/$2/$3"));
});
mindate.setMonth(mindate.getMonth() + 1);
maxdate.setMonth(maxdate.getMonth() + 1);
maxdate.setDate(maxdate.getDate() + 5);
var x = d3.time.scale()
.domain([mindate, maxdate])
.range([0, width]);
var xAxis = d3.svg.axis()
.orient("bottom")
.scale(x)
.ticks(10);
g.append('g')
.attr('transform', 'translate(0,' + height + ')') .attr("class", "axis")
.call(customXAxis);
var linksg = g.append("g");
function customXAxis(g) {
g.call(xAxis);
//g.select('.domain').remove();
};
update(root);
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 * 80;
});
// Declare the nodes…
var node = g.selectAll("g.node")
.data(nodes, function (d) {
return d.id || (d.id = ++i);
});
// Enter the nodes.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function (d) {
var ddate = d.date.split("-");
var t = new Date(ddate[2], ddate[0], ddate[1]);
return "translate(" + x(t) + "," + d.x + ")";
});
nodeEnter.append("circle")
.attr("r", 15)
.transition()
.delay(350)
.style("fill", "steelblue");
nodeEnter.append("text")
.attr("x", function (d) {
return d.children || d._children ? -20 : 20;
})
.attr("dy", ".35em")
.attr("text-anchor", function (d) {
return d.children || d._children ? "end" : "start";
})
.text(function (d) {
return d.name
})
.style("fill-opacity", 1);
// Declare the links…
var link = linksg.selectAll('.link')
.data(nodes)
.enter().append('path')
.attr('class', 'link')
.attr('d', function (d) {
if (d.parent != undefined) {
var res = d.date.split("-");
var nodeDate = new Date(+res[2], +res[0], +res[1]);
var res = d.parent.date.split("-");
var parentDate = new Date(+res[2], +res[0], +res[1]);
return 'M' + x(nodeDate) + ',' + d.x +
'C' + (x(nodeDate) + x(parentDate)) / 2 + ',' + d.x +
' ' + (x(nodeDate) + x(parentDate)) / 2 + ',' + d.parent.x +
' ' + x(parentDate) + ',' + d.parent.x;
}
});
} // end update () function
</script>
</body>
</html>.

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>

Categories