Created
January 22, 2018 14:35
-
-
Save johangithub/0f0f8311d7d515a443ce7c97aac56e59 to your computer and use it in GitHub Desktop.
Collapsible Tree
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
.node circle { | |
fill: #fff; | |
stroke: steelblue; | |
stroke-width: 3px; | |
} | |
.node text { | |
font: 15px sans-serif; | |
} | |
.link { | |
fill: none; | |
stroke: #ccc; | |
stroke-width: 4px; | |
} | |
</style> | |
<script src="http://d3js.org/d3.v4.min.js"></script> | |
<body> | |
<button id="collapse">Collapse</button> | |
<button id="uncollapse">UnCollapse</button> | |
<svg></svg> | |
</body> | |
<script> | |
var margin = {top: 20, right: 120, bottom: 20, left: 120}, | |
width = 1900 - margin.right - margin.left, | |
height = 1000 - margin.top - margin.bottom | |
var svg = d3.select("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 textMargin = 200 | |
var tree = d3.tree() | |
.size([height, width - textMargin]) | |
var stratify = d3.stratify() | |
.parentId(function(d) { return d.id.substring(0, d.id.lastIndexOf(".")) }) | |
d3.csv("flare.csv", function(error, data) { | |
if (error) throw error | |
root = stratify(data) | |
.sort(function(a, b) { return (a.height - b.height) || a.id.localeCompare(b.id) }) | |
root.x0 = height / 2 | |
root.y0 = 0 | |
root.children.forEach(collapse) | |
// sumData(root) | |
update(root) | |
}) | |
function sumData(d){ | |
var temp = 0 | |
if (d.data.value) return d.data.value | |
if (d.children){ | |
temp += d3.sum(d.children, d=>sumData(d)) | |
} | |
if (d._children){ | |
temp += d3.sum(d._children, d=>sumData(d)) | |
} | |
return temp | |
} | |
function collapse(d){ | |
if (d.children){ | |
d._children = d.children | |
d._children.forEach(collapse) | |
d.children = null | |
} | |
} | |
function uncollapse(d){ | |
if (!d.children){ | |
d.children = d._children | |
d.children ? d.children.forEach(uncollapse) : null | |
} else { | |
d.children.forEach(uncollapse) | |
} | |
d._children = null | |
} | |
function update(source){ | |
var treeData = tree(root) | |
var nodes = treeData.descendants() | |
var links = treeData.descendants().slice(1) | |
var t = d3.transition().duration(750) | |
// distance between each depth | |
nodes.forEach(d=>{ d.y = d.depth * 300 }) | |
var node = svg.selectAll("g.node") | |
.data(nodes, function(d){return d.id || (d.id = ++i)}) | |
var nodeEnter = node.enter().append('g') | |
.attr("class", "node") | |
.attr("transform", `translate(${source.y0}, ${source.x0})`) | |
.on("click", click) | |
nodeEnter.append('circle') | |
.attr('class', 'node') | |
.attr('r', 1e-6) | |
.style("fill", d => d._children ? "lightsteelblue" : "#fff") | |
nodeEnter.append("text") | |
.attr("dy", "-.5em") | |
.attr("x", d => d.children || d._children ? -8 : 8) | |
.attr("text-anchor", d => d.children || d._children ? "end" : "start") | |
.text(d => {return d.id.substring(d.id.lastIndexOf(".") + 1) + ' ' + sumData(d).toString()}) | |
var nodeUpdate = nodeEnter.merge(node) | |
nodeUpdate | |
.transition(t) | |
.attr("transform", d => `translate(${d.y},${d.x})`) | |
nodeUpdate.select("circle.node") | |
.attr("r", 15) | |
.style("fill", d => d._children ? "lightsteelblue" : "#fff") | |
.attr("cursor", "pointer") | |
var nodeExit = node.exit().transition(t) | |
.attr("transform", `translate(${source.y}, ${source.x})`) | |
.remove() | |
nodeExit.select("circle") | |
.attr("r", 1e-6) | |
nodeExit.select("text") | |
.attr("fill-opacity", 1e-6) | |
var link = svg.selectAll("path.link") | |
.data(links, function(d){ return d.id}) | |
var linkEnter = link | |
.enter() | |
.insert("path","g") | |
.attr("class", "link") | |
.attr("d", diagonal({x: source.x0, y: source.y0}, {x: source.x0, y: source.y0})) | |
var linkUpdate = linkEnter.merge(link) | |
linkUpdate.transition(t) | |
.attr("d", function(d){ | |
return diagonal(d, d.parent) | |
}) | |
var linkExit = link.exit().transition(t) | |
.attr("d", diagonal({x: source.x, y: source.y}, {x: source.x, y: source.y})) | |
.remove() | |
nodes.forEach(d => {d.x0 = d.x; d.y0 = d.y}) | |
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("#collapse").on("click",()=>{ | |
collapse(root) | |
update(root) | |
}) | |
d3.select("#uncollapse").on("click",()=>{ | |
uncollapse(root) | |
update(root) | |
}) | |
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 | |
} | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment