D3 Collapsible Tree, drag() event: d is not defined error - javascript

I am new to D3 and I am trying to implement drag behaviour in case of the Collapsible Tree.
The variable d in the following code is showing the error undefined
var drag = d3.behavior.drag()
.on("drag", function(d,i) {
d.x += d3.event.x;
d.x += d3.event.y;
d3.select(this).attr("transform", function(d,i){
return "translate(" + [d.x,d.y ] + ")"
})
});
I tried setting the origin() but it didnt solve the issue
var drag = d3.behavior.drag()
.origin(function() {
var t = d3.select(this);
return {x: t.attr("x"), y: t.attr("y")};
})
.on("drag", function(d,i) {
d.x += d3.event.x;
d.x += d3.event.y;
d3.select(this).attr("transform", function(d,i){
return "translate(" + [d.x,d.y ] + ")"
})
});
I tried by capturing the d3.event.x/y and then transform by that amount but it was offset by an amount......
Can you please let me know where I am getting it wrong?? Any help would me much appreciated....
The complete code is as follows:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<style>
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
.templink {
fill: none;
stroke: red;
stroke-width: 3px;
}
.ghostCircle.show{
display:block;
}
.ghostCircle, .activeDrag .ghostCircle{
display: none;
}
</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 120, bottom: 20, left: 120},
width = 1960 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var drag = d3.behavior.drag()
.on("drag", function() {
d3.select(this).attr("transform", function(){
return "translate(" + [ d3.event.x,d3.event.y ] + ")"
})
});
var svg = d3.select("body")
.append("svg:svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("svg:g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.append("svg:g")
.call(drag);
var tree = d3.layout.tree()
.size([height, width]);
d3.json("test_1_final.json", function(error, flare) {
root = flare;
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse);
update(root);
});
//////////////////////////////////////////////////////////////////////////////
// sort the tree according to the node names
function sortTree() {
tree.sort(function(a, b) {
return b.name.toLowerCase() < a.name.toLowerCase() ? 1 : -1;
});
}
// Sort the tree initially incase the JSON isn't in a sorted order.
sortTree();
////////////////////////////////////////////////////////////////////////////////
// Define the zoom function for the zoomable tree
function zoom() {
svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
// define the zoomListener which calls the zoom function on the "zoom" event constrained within the scaleExtents
var zoomListener = d3.behavior.zoom().scaleExtent([0.1, 3]).on("zoom", zoom);
////////////////////////////////////////////////////////////////////////////////
d3.select(self.frameElement).style("height", "800px");
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 ? -10 : 10; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function(d) { return d._children ? "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>
</bodya
</html>

Related

How to have marker end enable to end of path in a d3 tree

Below is my code snippet where I would like to have multiple arrowhead markers at the end of my path pointing it towards the children instead of the parent. But I have been able to point a single arrow marker towards my parent but not a child. Please let me know what needs to be done
The below image shows the arrow pointing towards the parent. I would like to have it point towards children.
The below image shows is the plain code without arrow markers
I would like to see the below image like type functionality to my code
<!DOCTYPE html>
<meta charset="UTF-8">
<style>
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.node text {
font: 12px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
.link path {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
.link text {
font: 12px sans-serif;
stroke: #333;
stroke-width: 1;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var treeData =
{
"name": "Top Level",
"linkname": "null",
"children": [
{
"name": "Level 2: A",
"linkname": "Link_1",
"children": [
{ "name": "Son of A", "linkname": "Link_2.1" },
{ "name": "Daughter of A", "linkname": "Link_2.2" }
]
},
{ "name": "Level 2: B", "linkname": "Link_3", }
]
};
// Set the dimensions and margins of the diagram
var margin = { top: 20, right: 90, bottom: 30, left: 90 },
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// append the svg object to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
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 + ")");
var i = 0,
duration = 750,
root;
// declares a tree layout and assigns the size
var treemap = d3.tree().size([height, width]);
// Assigns parent, children, height, depth
root = d3.hierarchy(treeData, function (d) { return d.children; });
root.x0 = height / 2;
root.y0 = 0;
// Collapse after the second level
root.children.forEach(collapse);
update(root);
// Collapse the node and all it's children
function collapse(d) {
if (d.children) {
d._children = d.children
d._children.forEach(collapse)
d.children = null
}
}
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
});
// ****************** Nodes section ***************************
// Update the nodes...
var node = svg.selectAll('g.node')
.data(nodes, function (d) {
return d.id || (d.id = ++i);
});
// Enter any new modes 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);
// Add Circle for the nodes
nodeEnter.filter(function (d) {
return (!d.data.type || d.data.type !== 'data');
}).append('circle')
.attr('class', 'node')
.attr('r', 1e-6)
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.filter(function (d) {
return (d.data.type && d.data.type === 'data');
}).append('rect')
.attr('class', 'node')
.attr('width', 20)
.attr('height', 20)
.attr('y', -10)
.attr('x', -10)
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "#fff";
});
// Add labels for the nodes
nodeEnter.append('text')
.attr("dy", "2em")
.attr("x", function (d) {
return d.children || d._children ? 13 : 13;
})
.attr("text-anchor", function (d) {
return d.children || d._children ? "start" : "start";
})
.text(function (d) {
return d.data.name;
});
// UPDATE
var nodeUpdate = nodeEnter.merge(node);
// Transition to the proper position for the node
nodeUpdate.transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + d.y + "," + d.x + ")";
});
// Update the node attributes and style
nodeUpdate.select('circle.node')
.attr('r', 10)
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "#fff";
})
.attr('cursor', 'pointer');
// Remove any exiting nodes
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + source.y + "," + source.x + ")";
})
.remove();
// On exit reduce the node circles size to 0
nodeExit.select('circle')
.attr('r', 1e-6);
// On exit reduce the opacity of text labels
nodeExit.select('text')
.style('fill-opacity', 1e-6);
// ****************** links section ***************************
// Update the links...
var link = svg.selectAll('g.link')
.data(links, function (d) {
return d.id;
});
// Enter any new links at the parent's previous position.
var linkEnter = link.enter().insert('g', 'g')
.attr("class", "link");
linkEnter.append('text')
.attr("class","linkLabels")
.text(function (d, i) {
if (d.parent && d.parent.children.length > 1) {
if (!d.parent.index) d.parent.index = 0;
return d.data.linkname;
}
})
.attr("opacity",0)
.attr('dy', "-1em");
linkEnter.append('path')
.attr('d', function (d) {
var o = {
x: source.x0,
y: source.y0
}
return diagonal(o, o)
})
.on("mouseover", function(){
d3.select(this.parentNode).select("text").attr("opacity",1);
})
.on("mouseleave", function(){
d3.select(this.parentNode).select("text").attr("opacity",0);
})
// UPDATE
var linkUpdate = linkEnter.merge(link);
// Transition back to the parent element position
linkUpdate.select('path').transition()
.duration(duration)
.attr('d', function (d) {
return diagonal(d, d.parent)
});
linkUpdate.select('text').transition()
.duration(duration)
.attr('transform', function (d) {
if (d.parent) {
return 'translate(' + ((d.parent.y + d.y) / 2) + ',' + ((d.parent.x + d.x) / 2) + ')'
}
})
// Remove any exiting links
link.exit().each(function (d) {
d.parent.index = 0;
})
var linkExit = link.exit()
.transition()
.duration(duration);
linkExit.select('path')
.attr('d', function (d) {
var o = {
x: source.x,
y: source.y
}
return diagonal(o, o)
})
linkExit.select('text')
.style('opacity', 0);
linkExit.remove();
// Store the old positions for transition.
nodes.forEach(function (d) {
d.x0 = d.x;
d.y0 = d.y;
});
// 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
}
// 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>
Probably not 100% what you want, but can be a starting point for you, basically I did it by manipulating marker attributes .attr("orient", "auto-start-reverse") check the MDN documentation for more information about this attribute, also refX, and refY finally the path attribute I used marker-start instead of marker-end since in this example the path drawn from the children to the parent not the reverse
if this is not what you want, there is another stack-overflow question that is a bit close to your case but its not a tree but can help:
Align Marker on node edges D3 Force Layout
var treeData = {
name: "Top Level",
linkname: "null",
children: [
{
name: "Level 2: A",
linkname: "Link_1",
children: [
{ name: "Son of A", linkname: "Link_2.1" },
{ name: "Daughter of A", linkname: "Link_2.2" }
]
},
{ name: "Level 2: B", linkname: "Link_3" }
]
};
// Set the dimensions and margins of the diagram
var margin = { top: 20, right: 90, bottom: 30, left: 90 },
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// append the svg object to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
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 + ")");
svg
.append("svg:defs")
.selectAll("marker")
.data(["end"]) // Different link/path types can be defined here
.enter()
.append("svg:marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", 0)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto-start-reverse")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
var i = 0,
duration = 750,
root;
// declares a tree layout and assigns the size
var treemap = d3.tree().size([height, width]);
// Assigns parent, children, height, depth
root = d3.hierarchy(treeData, function(d) {
return d.children;
});
root.x0 = height / 2;
root.y0 = 0;
// Collapse after the second level
root.children.forEach(collapse);
update(root);
// Collapse the node and all it's children
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
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;
});
// ****************** Nodes section ***************************
// Update the nodes...
var node = svg.selectAll("g.node").data(nodes, function(d) {
return d.id || (d.id = ++i);
});
// Enter any new modes 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);
// Add Circle for the nodes
nodeEnter
.filter(function(d) {
return !d.data.type || d.data.type !== "data";
})
.append("circle")
.attr("class", "node")
.attr("r", 1e-6)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter
.filter(function(d) {
return d.data.type && d.data.type === "data";
})
.append("rect")
.attr("class", "node")
.attr("width", 20)
.attr("height", 20)
.attr("y", -10)
.attr("x", -10)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
// Add labels for the nodes
nodeEnter
.append("text")
.attr("dy", "2em")
.attr("x", function(d) {
return d.children || d._children ? 13 : 13;
})
.attr("text-anchor", function(d) {
return d.children || d._children ? "start" : "start";
})
.text(function(d) {
return d.data.name;
});
// UPDATE
var nodeUpdate = nodeEnter.merge(node);
// Transition to the proper position for the node
nodeUpdate
.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
});
// Update the node attributes and style
nodeUpdate
.select("circle.node")
.attr("r", 10)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
})
.attr("cursor", "pointer");
// Remove any exiting nodes
var nodeExit = node
.exit()
.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + source.y + "," + source.x + ")";
})
.remove();
// On exit reduce the node circles size to 0
nodeExit.select("circle").attr("r", 1e-6);
// On exit reduce the opacity of text labels
nodeExit.select("text").style("fill-opacity", 1e-6);
// ****************** links section ***************************
// Update the links...
var link = svg.selectAll("g.link").data(links, function(d) {
return d.id;
});
// Enter any new links at the parent's previous position.
var linkEnter = link
.enter()
.insert("g", "g")
.attr("class", "link");
linkEnter
.append("text")
.attr("class", "linkLabels")
.text(function(d, i) {
if (d.parent && d.parent.children.length > 1) {
if (!d.parent.index) d.parent.index = 0;
return d.data.linkname;
}
})
.attr("opacity", 0)
.attr("dy", "-1em");
linkEnter
.append("path")
.attr("d", function(d) {
var o = {
x: source.x0,
y: source.y0
};
return diagonal(o, o);
})
.on("mouseover", function() {
d3.select(this.parentNode)
.select("text")
.attr("opacity", 1);
})
.on("mouseleave", function() {
d3.select(this.parentNode)
.select("text")
.attr("opacity", 0);
})
.attr("stroke-linecap", "round")
.attr("marker-start", "url(#end)");
// UPDATE
var linkUpdate = linkEnter.merge(link);
// Transition back to the parent element position
linkUpdate
.select("path")
.transition()
.duration(duration)
.attr("d", function(d) {
return diagonal(d, d.parent);
});
linkUpdate
.select("text")
.transition()
.duration(duration)
.attr("transform", function(d) {
if (d.parent) {
return (
"translate(" +
(d.parent.y + d.y) / 2 +
"," +
(d.parent.x + d.x) / 2 +
")"
);
}
});
// Remove any exiting links
link.exit().each(function(d) {
d.parent.index = 0;
});
var linkExit = link
.exit()
.transition()
.duration(duration);
linkExit.select("path").attr("d", function(d) {
var o = {
x: source.x,
y: source.y
};
return diagonal(o, o);
});
linkExit.select("text").style("opacity", 0);
linkExit.remove();
// Store the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
// 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;
}
// 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);
}
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.node text {
font: 12px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
.link path {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
.link text {
font: 12px sans-serif;
stroke: #333;
stroke-width: 1;
}
<!DOCTYPE html>
<meta charset="UTF-8">
<style>
</style>
<body>
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
</body>

How can I show multiple nodes parent in D3 tree chart?

I'm using D3 Tree chart
I did one node family using this D3 chart. you can check my code in below or in jsfiddle. Now, I want to show multiple nodes in the same chart, How can I achieve this? In my example, I did node1 data as well as I want to add another node like node2 family.
Here, JSFIDDLE
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="//d3js.org/d3.v3.min.js"></script>
</head>
<body>
</body>
</html>
CSS
.node {
cursor: pointer;
}
.overlay{
background-color:#EEE;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font-size:10px;
font-family:sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
.templink {
fill: none;
stroke: red;
stroke-width: 3px;
}
.ghostCircle.show{
display:block;
}
.ghostCircle, .activeDrag .ghostCircle{
display: none;
}
JS
var flare_data = {
"name": "Node1",
"children": [
{
"name": "Bob: Child of Top Node1",
"children": [
{
"name": "Son of Bob"
},
{
"name": "Daughter of Bob"
}
]
},
{
"name": "Sally: Child of Top Node1"
}
]
};
var margin = {top: 20, right: 120, bottom: 20, left: 120},
width = 960 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var svg = 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 = flare_data;
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse);
update(root);
d3.select(self.frameElement).style("height", "800px");
function update(source) {
// 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"; })
.append("svg:title")
.text("Siddhu");
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)
.append("svg:title")
.html("<b>Siddhu</b>");
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; })
.style("fill", function(d) { return (d.name == 'analytics') ? "#f20000" : "#04f100"; });
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);
}
//Expend all wrote by siddhu
function expand(d){
var children = (d.children)?d.children:d._children;
if (d._children) {
d.children = d._children;
d._children = null;
}
if(children)
children.forEach(expand);
}
function expandAll(){
expand(root);
update(root);
}
//expandAll();

d3.js Tree Node Layout remove root node

Please, I am searching for a solution to not display the root node and connecting lines to it.
I have already tried to append multiple append("svg:svg") and populate those with root.children[...] nodes, but I don't like that because it looks inefficient to me.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<link type="text/css" rel="stylesheet" href="style.css"/>
<script type="text/javascript" src="d3/d3.js"></script>
<script type="text/javascript" src="d3/d3.layout.js"></script>
<style type="text/css">
.node circle {
cursor: pointer;
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font-size: 11px;
}
path.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<div id="body">
<div id="footer">
d3.layout.tree
<div class="hint">click or option-click to expand or collapse</div>
</div>
</div>
<script type="text/javascript">
var m = [20, 120, 20, 120],
w = 1280 - m[1] - m[3],
h = 800 - m[0] - m[2],
i = 0,
root;
var tree = d3.layout.tree()
.size([h, w]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var vis = d3.select("#body").append("svg:svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
d3.json("flare.json", function(json) {
root = json;
root.x0 = h / 2;
root.y0 = 0;
function toggleAll(d) {
if (d.children) {
d.children.forEach(toggleAll);
toggle(d);
}
}
// Initialize the display to show a few nodes.
root.children.forEach(toggleAll);
toggle(root.children[1]);
toggle(root.children[1].children[2]);
toggle(root.children[9]);
toggle(root.children[9].children[0]);
update(root);
});
function update(source) {
var duration = d3.event && d3.event.altKey ? 5000 : 500;
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", function(d) { toggle(d); update(d); });
nodeEnter.append("svg:circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeEnter.append("svg:text")
.attr("x", function(d) { return d.children || d._children ? -10 : 10; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function(d) { return d._children ? "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 = 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.
function toggle(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
}
</script>
</body>
</html>
You can just pop out the last node you make in update(source), which is the root node.
like this:
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
nodes.pop()

Add d3-tip infobox to d3.js SVG

Would like to add an infobox to a d3.js file.
Have studied this SO question, and this SO question, and this SO question, and this fiddle.
Most of the following HTML + JavaScrip + d3.js + JSON file works as planned.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js" charset="utf-8"></script>
<style type="text/css">
.node { cursor: pointer; }
.node circle { fill: #fff; stroke: steelblue; stroke-width: 1.5px; }
.node text { font: 10px sans-serif; }
.link { fill: none; stroke: #ccc; stroke-width: 1.5px; }
.link:hover { stroke:blue; }
div#tooltip{ color:#ffffff; background:#000000; opacity:1; padding:5px; }
</style>
<title>Soils with Local JSON</title>
</head>
<body>
<h1>Soils with Local JSON</h1>
<div id="tooltip" style="display:none"></div>
<script type="text/javascript">
var margin = {
top: 20,
right: 120,
bottom: 20,
left: 120
},
width = 1000 - margin.right - margin.left,
height = 400 - 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];
});
//Add tool tip: d3-tip.
var tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d) { return '' + d.name + '' });
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 + ")")
//Call tool-tip in var svg =
.call(tip);
var root = {
"name":"Soil","children":[
{"name":"Albaqualfs","url":"http://en.wikipedia.org/wiki/Albaqualfs","children":[
{"name":"Aeric Albaqualfs","children":[
{"name":"Auxvasse"},
{"name":"Cayagua"},
{"name":"Mamou"},
{"name":"Marine"},
{"name":"Medoc"},
{"name":"Springfield"},
{"name":"Tenot"}]}]}]};
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse);
update(root);
d3.select(self.frameElement).style("height", "800px");
function update(source) {
// 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 ? -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)
.on("mouseover", function (d) {
var r = d3.select(this).node().getBoundingClientRect();
d3.select("div#tooltip")
.style("display", "inline")
.style("top", (r.top-25) + "px")
.style("left", r.left + "px")
.style("position", "absolute")
.text(d.test);
})
.on("mouseout", function(){
d3.select("div#tooltip").style("display", "none")
});
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + d.y + "," + d.x + ")";
});
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function (d) {
return d._children ? "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>
Now would like to add an infobox for an item that displays information like this:
Am currently working with d3-tip.
The included file has a JSON field for "name" and "url". It also includes an attempt to map the "url" to d.url and "name" to d.name.
One issue is the need to keep the infobox temporarily persistent so that users can click the item's URL if they choose. Once the cursor is moved away from the infobox, it should clear.
The target infobox image above shows an X to close the infobox if clicked. However, I don't see how to introduce a second selector - the current selector opens the next level of the tree. Therefore, I'm hoping that a temporarily persistent infobox, revealed on mouseover, can be implemented.
The infobox can overlay the tree data - no need to re-draw the tree to adjust to the placement of the infobox.
How to correct the d3-tip code to work as desired?
If an SO reader uses an alternative to d3-tip that basically accomplishes the same task, that would be good too.

How to increase space vertically between nodes in Collapse Tree D3.js

I am new to JS and trying to increase the node distance vertically. I have found the answer to increase the node distance horizontally by modifying the following code:
nodes.forEach(function(d) { d.y = d.depth * 180; });
But I did not see the similar code to set vertical distance. How to modify d.x?
Here is the code for D3.js Collapse Tree:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 120, bottom: 20, left: 120},
width = 960 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var svg = 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 + ")");
d3.json("/d/4063550/flare.json", function(error, flare) {
root = flare;
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse);
update(root);
});
d3.select(self.frameElement).style("height", "800px");
function update(source) {
// 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 ? -10 : 10; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function(d) { return d._children ? "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>

Categories