http://bl.ocks.org/mbostock/5100636
Click on any arc to zoom in, and click on the center circle to zoom out.
forked from maybelinot's block: Zoomable Sunburst on d3.js v4
license: gpl-3.0 |
http://bl.ocks.org/mbostock/5100636
Click on any arc to zoom in, and click on the center circle to zoom out.
forked from maybelinot's block: Zoomable Sunburst on d3.js v4
{ | |
"name": "total", | |
"children": [ | |
{ | |
"name": "A", | |
"children": [ | |
{ | |
"name": "1", | |
"children": [ | |
{"name": "x", "size": 15}, | |
{"name": "y", "size": 3}, | |
{"name": "z", "size": 2} | |
] | |
}, | |
{"name": "2", "size": 20}, | |
{"name": "3", "size": 15} | |
] | |
}, | |
{"name": "B","size": 30}, | |
{"name": "C","size": 15} | |
] | |
} |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
path { | |
stroke: #fff; | |
} | |
</style> | |
<body> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script> | |
console.clear() | |
var width = 960, | |
height = 480, | |
radius = (Math.min(width, height) / 2) - 10; | |
var formatNumber = d3.format(",d"); | |
var x = d3.scaleLinear() | |
.range([0, 2 * Math.PI]); | |
var y = d3.scaleSqrt() | |
.range([0, radius]); | |
var color = d3.scaleOrdinal(d3.schemeCategory10); | |
var arcColor = function(d){ return d3.hsl(color(d.depth)).brighter(d.children ? 0 : 1); } | |
var partition = d3.partition(); | |
var depth = 0, | |
showKids = 0; | |
var arc = d3.arc() | |
.startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x0))); }) | |
.endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x1))); }) | |
.innerRadius(0) | |
.outerRadius(function(d) { | |
if(d.depth == 0){ | |
// root node -- alway radius + 10 | |
//console.log("outerRadius1", d.data.name, radius + 10); | |
return Math.max(0, radius + 10); | |
} else if (d.depth == depth){ | |
//console.log("outerRadius2", d.data.name, y(d.value) + 5); | |
return Math.max(0, y(d.value) + 5); | |
} else if (d.depth > depth && showKids){ | |
//console.log("outerRadius3", d.data.name, y(d.parent.value) + 5); | |
return Math.max(0, y(d.parent.value) + 5); | |
} else { | |
//console.log("outerRadius4", d.data.name, y(d.value)); | |
return Math.max(0, y(d.value)); | |
} | |
}) | |
function tweenIn(b) { | |
console.log("tweenZoomIn", b.data.name, | |
"from: " + (b.parent ? y(b.parent.value) : y(b.value)), | |
"to: " + Math.max(0, y(b.value) + 5)) | |
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b); | |
return function(t) { return arc(i(t)); }; | |
} | |
function tweenZoomIn(b) { | |
console.log("tweenZoomIn", b.data.name, | |
"from: " + (b.parent ? y(b.parent.value) : y(b.value)), | |
"to: " + Math.max(0, y(b.value) + 5)) | |
b.outerRadius = Math.max(0, y(b.value) + 5); | |
var i = d3.interpolate({outerRadius: b.parent ? y(b.parent.value) : y(b.value)}, b); | |
return function(t) { return arc(i(t)); }; | |
} | |
function tweenOut(b) { | |
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b); | |
return function(t) { return arc(i(1-t)); }; | |
} | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height) | |
.append("g") | |
.attr("transform", "translate(" + width / 2 + "," + (height / 2) + ")"); | |
d3.json("data.json", function(error, root) { | |
if (error) throw error; | |
root = d3.hierarchy(root); | |
root.sum(function(d) { return d.size; }); | |
console.log("root", partition(root).descendants(), root.value); | |
y.domain([0, root.value]) | |
svg.selectAll("path") | |
.data(partition(root).descendants().filter((d)=>{ return d.depth <= depth;}), | |
function(d) { return d.data.name; }) | |
.enter().append("path") | |
.attr("d", arc) | |
.style("fill", arcColor) | |
.style("pointer-events", "all") | |
.style("stroke", arcColor) | |
.on("click", click) | |
.append("title") | |
.text(function(d) { return d.data.name + "\n" + formatNumber(d.value); }); | |
function click(d) { | |
console.log("old", "depth: " + depth, "showKids: " + (showKids ? 'true' : 'false')) | |
if(!d.children){ | |
//console.log('X') | |
// ignore clicks if the member has no children | |
d = d.parent; | |
} else { | |
if(depth == d.depth){ // d is at max current depth | |
if(showKids == 0){ | |
//console.log('A') | |
showKids = 1; | |
} else { | |
//console.log('B') | |
showKids = 0; | |
//depth = depth + 1; | |
} | |
} else { | |
if(showKids == 1){ | |
//console.log('C') | |
showKids = 0; | |
depth = d.depth; | |
} else { | |
//console.log('D') | |
showKids = 1; | |
depth = Math.max(0, depth - 1); // decrease depth by one, up to current depth | |
} | |
} | |
} | |
console.log("new", "depth: " + depth, "showKids: " + (showKids ? 'true' : 'false')) | |
//console.log("ancestors", d.ancestors()) | |
//console.log("children", d.children, d.children ? "yes" : "no") | |
var nodes = null; | |
if(showKids == 1){ | |
nodes = d3.merge([ | |
d.ancestors(), | |
d.children | |
]) | |
} else { | |
nodes = d.ancestors() | |
} | |
nodes.sort(function(a, b){ return b.value - a.value; }) | |
console.log("nodes", nodes) //.sort(function()) | |
//console.log("old x.domain", x.domain()) | |
x.domain([0, d.x1]); | |
//console.log("new x.domain", x.domain()) | |
//console.log("ancestorsAndChildren", nodes) | |
var arcs = svg.selectAll("path") | |
//.data(partition(root).descendants().filter((d)=>{ return d.depth <= depth;})) | |
.data(nodes, function(d) { return d.data.name; }) | |
var arcsEnter = arcs.enter().append("path") | |
.style("fill", arcColor) | |
.style("pointer-events", "all") | |
.style("stroke", arcColor) | |
.attr("d", arcZero) | |
.on("click", click) | |
arcsEnter.append("title") | |
.text(function(d) { return d.data.name + "\n" + formatNumber(d.value); }); | |
arcsEnter.transition() | |
.duration(2000) | |
.attrTween("d", tweenIn) | |
arcs.transition() | |
.duration(2000) | |
.attrTween("d", tweenZoomIn) | |
arcs.exit().transition() | |
.duration(2000) | |
.attrTween("d", tweenOut) | |
.transition() | |
.remove() | |
/* | |
svg.transition() | |
.duration(750) | |
/*.tween("scale", function() { | |
var xd = d3.interpolate(x.domain(), [d.x0, d.x1]), | |
yd = d3.interpolate(y.domain(), [d.y0, 1]), | |
yr = d3.interpolate(y.range(), [d.y0 ? 20 : 0, radius]); | |
return function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); }; | |
}) | |
.selectAll("path") | |
.attrTween("d", function(d) { return function() { return arc(d); }; });*/ | |
} | |
}); | |
d3.select(self.frameElement).style("height", height + "px"); | |
</script> |