Using the still not-quite-ready-for-prime-time d3.geom.concaveHull to draw concave hulls around cities of the world between 50k and 1m population.
xxxxxxxxxx
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Concave Hulls Complex</title>
<style>
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js" charset="utf-8" type="text/javascript"></script>
<script src="d3.geom.concaveHull.js" charset="utf-8" type="text/javascript"></script>
<script type="text/javascript">
d3.select("body").append("svg").attr("height", 1000).attr("width", 1000)
d3.csv("cities.csv", mapCities)
function mapCities(cities) {
var projection = d3.geo.mercator();
colorScale = d3.scale.ordinal().domain(cities.map(function (d) {return d.ccode}))
.range(["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"]);
countries = colorScale.domain();
cities.forEach(function (d) {
d.x = projection([d.xcoord, d.ycoord])[0];
d.y = projection([d.xcoord, d.ycoord])[1];
})
d3.select("svg").selectAll("circle")
.data(cities)
.enter()
.append("circle")
.attr("r", 1)
.style("fill-opacity", .5)
.attr("cx", function (d) {return d.x})
.attr("cy", function (d) {return d.y});
concaveHull = d3.geom.concaveHull();
countries.forEach(function (ccode) {
theseCities = cities.filter(function (d) {return d.ccode === ccode})
.map(function (d) {return [d.x,d.y]});
console.log(theseCities)
if (theseCities.length > 3) {
d3.select("svg")
.selectAll("path.nothing")
.data(concaveHull(theseCities))
.enter()
.append("path")
.attr("d", function(d) { return "M" + d.join("L") + "Z"; })
.style("fill-opacity", 0.5)
.style("fill", colorScale(ccode))
.style("stroke", colorScale(ccode))
.style("stroke-width", 1)
}
});
}
</script>
</body>
</html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js