The trick here is that we dissociate MultiPolygons before using centroids.
Built with blockbuilder.org
forked from Fil's block: Country map + voronoi.find
license: mit |
The trick here is that we dissociate MultiPolygons before using centroids.
Built with blockbuilder.org
forked from Fil's block: Country map + voronoi.find
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
background: white; | |
} | |
.stroke { | |
fill: none; | |
stroke: #000; | |
stroke-width: 1.5px; | |
} | |
.fill { | |
fill: #fff; | |
} | |
.graticule { | |
fill: none; | |
stroke: #777; | |
stroke-width: .5px; | |
stroke-opacity: .5; | |
} | |
.land { | |
fill: #222; | |
} | |
.boundary { | |
fill: none; | |
stroke: #fff; | |
stroke-width: .5px; | |
} | |
svg {border: 1px solid black} | |
</style> | |
<body> | |
<script src="https://unpkg.com/d3@4"></script> | |
<script src="https://unpkg.com/d3-geo-projection@2"></script> | |
<script src="https://unpkg.com/topojson-client@3"></script> | |
<script src="https://unpkg.com/d3-scale-chromatic"></script> | |
<script> | |
var width = 600, | |
height = 580; | |
var color = d3.scaleThreshold() | |
.domain(d3.range(9)) | |
.range(d3.schemeCategory10); | |
var svg = d3.select("body").append("svg") | |
.attr("xmlns:xlink","http://www.w3.org/1999/xlink") | |
.attr("width", width) | |
.attr("height", height); | |
var map = svg.append('g'); | |
var voronoi = svg.append('g'); | |
var vor = null; | |
d3.json("110m.json", function(error, world) { | |
if (error) throw error; | |
var countries = topojson.feature(world, world.objects['caribis']).features, | |
neighbors = topojson.neighbors(world.objects['caribis'].geometries); | |
var borders = topojson.feature( | |
world, | |
world.objects['caribis'] | |
); | |
// borders.features = borders.features.filter(d => d.properties.name != 'Antarctica'); | |
var projection = d3.geoNaturalEarth2().fitSize([width, height], borders) | |
var path = d3.geoPath() | |
.projection(projection); | |
function countryid(d){ | |
switch (d.properties.CNTRY_NAME) { | |
case 'Somaliland': | |
return 'SM'; | |
case 'Kosovo': | |
return 'XK'; | |
case 'N. Cyprus': | |
return 'C0'; | |
} | |
return d.properties.CNTRY_NAME; | |
} | |
map.selectAll('.border') | |
.data(borders.features) | |
.enter() | |
.append('a') | |
.attr('target', '_parent') | |
.append('path') | |
.attr('d', path) | |
.attr('stroke', 'black') | |
.attr('stroke-width', 0.25) | |
.attr('id', d => countryid(d)) | |
.attr('fill', d => color( Math.random() * 10 )); | |
var centroids = d3.merge( | |
borders.features.map(d => { | |
if (d.geometry.type == 'MultiPolygon') | |
return d.geometry.coordinates.map(e => ({ | |
type: "Point", | |
properties: d.properties, | |
coordinates: d3.geoCentroid({ type:"Polygon", coordinates: e }) | |
})); | |
else return [ { | |
type: "Point", | |
properties: d.properties, | |
coordinates: d3.geoCentroid(d) | |
} ]; | |
}) | |
); | |
centroids.forEach(d => { | |
var p = projection(d.coordinates); | |
d.x = p[0]; | |
d.y = p[1]; | |
}) | |
vor = d3.voronoi().x(d => d.x).y(d => d.y).extent([[0,0],[width, height]])(centroids); | |
voronoi.selectAll('.polygon') | |
.data(vor.polygons()) | |
.enter() | |
.append('path') | |
.attr('d', d => d ? "M" + d.join("L") + "Z" : null) | |
.attr('stroke', '#dbdbdb') | |
.attr('fill', 'none'); | |
svg.on('mousemove click', function() { | |
var m = d3.mouse(this); | |
var site = vor.find(m[0], m[1], 1050); | |
var country = site ? site.data.properties : null; | |
map.selectAll('path') | |
.style('fill', d => d.properties == country ? 'white' : null) | |
}) | |
svg.append('path') | |
.datum({type:"Sphere"}) | |
.attr('d', path) | |
.attr('class', 'stroke') | |
}); | |
</script> |