Skip to content

Instantly share code, notes, and snippets.

@Kcnarf
Last active June 28, 2019 12:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kcnarf/8d2b13fb307b480120d0ebbba0c62182 to your computer and use it in GitHub Desktop.
Save Kcnarf/8d2b13fb307b480120d0ebbba0c62182 to your computer and use it in GitHub Desktop.
Voronoï <-> Rect treemap transition with flubber
license: lgpl-3.0
{
"name": "world",
"children": [
{
"name": "Asia",
"color": "#f58321",
"children": [
{"name": "China", "weight": 14.84, "code": "CN"},
{"name": "Japan", "weight": 5.91, "code": "JP"},
{"name": "India", "weight": 2.83, "code": "IN"},
{"name": "South Korea", "weight": 1.86, "code": "KR"},
{"name": "Russia", "weight": 1.8, "code": "RU"},
{"name": "Indonesia", "weight": 1.16, "code": "ID"},
{"name": "Turkey", "weight": 0.97, "code": "TR"},
{"name": "Saudi Arabia", "weight": 0.87, "code": "SA"},
{"name": "Iran", "weight": 0.57, "code": "IR"},
{"name": "Thaïland", "weight": 0.53, "code": "TH"},
{"name": "United Arab Emirates", "weight": 0.5, "code": "AE"},
{"name": "Hong Kong", "weight": 0.42, "code": "HK"},
{"name": "Israel", "weight": 0.4, "code": "IL"},
{"name": "Malasya", "weight": 0.4, "code": "MY"},
{"name": "Singapore", "weight": 0.39, "code": "SG"},
{"name": "Philippines", "weight": 0.39, "code": "PH"}
]
},
{
"name": "North America",
"color": "#ef1621",
"children": [
{"name": "United States", "weight": 24.32, "code": "US"},
{"name": "Canada", "weight": 2.09, "code": "CA"},
{"name": "Mexico", "weight": 1.54, "code": "MX"}
]
},
{
"name": "Europe",
"color": "#77bc45",
"children": [
{"name": "Germany", "weight": 4.54, "code": "DE"},
{"name": "United Kingdom", "weight": 3.85, "code": "UK"},
{"name": "France", "weight": 3.26, "code": "FR"},
{"name": "Italy", "weight": 2.46, "code": "IT"},
{"name": "Spain", "weight": 1.62, "code": "ES"},
{"name": "Netherlands", "weight": 1.01, "code": "NL"},
{"name": "Switzerland", "weight": 0.9, "code": "CH"},
{"name": "Sweden", "weight": 0.67, "code": "SE"},
{"name": "Poland", "weight": 0.64, "code": "PL"},
{"name": "Belgium", "weight": 0.61, "code": "BE"},
{"name": "Norway", "weight": 0.52, "code": "NO"},
{"name": "Austria", "weight": 0.51, "code": "AT"},
{"name": "Denmark", "weight": 0.4, "code": "DK"},
{"name": "Ireland", "weight": 0.38, "code": "IE"}
]
},
{
"name": "South America",
"color": "#4aaaea",
"children": [
{"name": "Brazil", "weight": 2.39, "code": "BR"},
{"name": "Argentina", "weight": 0.79, "code": "AR"},
{"name": "Venezuela", "weight": 0.5, "code": "VE"},
{"name": "Colombia", "weight": 0.39, "code": "CO"}
]
},
{
"name": "Australia",
"color": "#00acad",
"children": [
{"name": "Australia", "weight": 1.81, "code": "AU"}
]
},
{
"name": "Africa",
"color": "#f575a3",
"children": [
{"name": "Nigeria", "weight": 0.65, "code": "NG"},
{"name": "Egypt", "weight": 0.45, "code": "EG"},
{"name": "South Africa", "weight": 0.42, "code": "ZA"}
]
},
{"name": "Rest of the World",
"color": "#592c94",
"children": [
{"name": "Rest of the World", "weight": 9.41, "code": "RotW"}
]
}
]
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>d3-voronoi-treemap</title>
<script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.3/seedrandom.min.js"></script>
<script src="https://raw.githack.com/Kcnarf/d3-weighted-voronoi/master/build/d3-weighted-voronoi.js"></script>
<script src="https://rawcdn.githack.com/Kcnarf/d3-voronoi-map/v1.2.0/build/d3-voronoi-map.js"></script>
<script src="https://rawcdn.githack.com/Kcnarf/d3-voronoi-treemap/v1.1.0/build/d3-voronoi-treemap.js"></script>
<script src="https://unpkg.com/flubber@0.3.0"></script>
<style>
path {
stroke: white;
stroke-width: 1px;
}
</style>
</head>
<body>
<svg></svg>
<script>
var width = 960,
height = 500,
radius = 200;
var svg = d3
.select("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + [width / 2 - radius, height / 2 - radius] + ")");
d3.json("globalEconomyByGDP.json", function(error, rootData) {
if (error) throw error;
var hierarchy = d3.hierarchy(rootData).sum(function(d) {
return d.weight;
});
var rectangles = getRectangles(hierarchy),
voronoi = getVoronoiPolygons(hierarchy);
var paired = d3
.nest()
.key(function(d) {
return d.name;
})
.key(function(d) {
return d.polygon ? "voronoi" : "rectangle";
})
.rollup(values => values[0])
.object(voronoi.concat(rectangles));
var animationPairs = d3.values(paired).map(function(value) {
return {
color: value.voronoi.color,
voronoi: value.voronoi,
rectangle: value.rectangle,
interpolator: flubber.fromRect(
value.rectangle.x,
value.rectangle.y,
value.rectangle.width,
value.rectangle.height,
value.voronoi.polygon
)
};
});
svg
.selectAll("path")
.data(animationPairs)
.enter()
.append("path")
.style("fill", function(d) {
return d.color;
})
.call(animate, true);
});
function animate(cells, direction) {
cells
.attr("d", function(d) {
return d.interpolator(direction ? 0 : 1);
})
.transition()
.delay(500)
.duration(1000)
.attrTween("d", function(d) {
return direction
? d.interpolator
: function(t) {
return d.interpolator(1 - t);
};
})
.filter(function(d, i) {
return !i;
})
.on("end", function() {
cells.call(animate, !direction);
});
}
function getVoronoiPolygons(hierarchy) {
//for reproducibility purpose, use a seedable pseudo random number generator
var myseededprng = new Math.seedrandom('my seed'); // (from seedrandom's doc) Use "new" to create a local pprng without altering Math.random
d3.voronoiTreemap().prng(myseededprng).clip(
d3.range(0, 2 * Math.PI, Math.PI / 30).map(function(a) {
return [
radius + radius * Math.cos(a),
radius + radius * Math.sin(a)
];
})
)(hierarchy);
return hierarchy.leaves().map(function(d) {
return {
name: d.data.name,
polygon: d.polygon,
color: d.parent.data.color
};
});
}
function getRectangles(hierarchy) {
return d3.treemap().size([radius * 2, radius * 2])(hierarchy)
.leaves()
.map(function(d) {
return {
name: d.data.name,
x: d.x0,
y: d.y0,
width: d.x1 - d.x0,
height: d.y1 - d.y0
};
});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment