index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Click to Zoom</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
</head>
<body>
<style>
body {
margin: 20px;
}
.sphere {
fill: #A7DBD8;
stroke: #79A09E;
stroke-width: 2px;
}
.country {
fill: #E0E4CC;
stroke: #ACAF9F;
stroke-width: 1;
}
.graticule {
fill: none;
stroke: #79A09E;
stroke-width: 1;
stroke-dasharray: 1,1;
}
.country:hover {
fill: #ECD078;
cursor: pointer;
}
</style>
<div id="map-container"></div>
<script>
var width = 960,
height = width / 2;
var centerX = width / 2,
centerY = height / 2,
zoomFactor = 4;
var div = d3.select('#map-container'),
svg = div.append('svg');
svg
.attr('width', width)
.attr('height', height);
var projection = d3.geo.equirectangular()
.scale(height / Math.PI)
.translate([width / 2, height / 2]);
var pathGenerator = d3.geo.path()
.projection(projection);
var graticule = d3.geo.graticule();
d3.json('countries.geojson', function(err, data) {
if (err) { throw err; }
var grp = svg.selectAll('g.container').data([data]);
grp.enter().append('g').classed('container', true);
grp.exit().remove();
var sphere = grp.selectAll('path.sphere').data([{type: 'Sphere'}]);
sphere.enter().append('path').classed('sphere', true);
sphere.attr('d', pathGenerator);
sphere.exit().remove();
var lines = grp.selectAll('path.graticule').data([graticule()]);
lines.enter().append('path').classed('graticule', true);
lines.attr('d', pathGenerator);
lines.exit().remove();
var path = grp.selectAll('path.country').data(data.features);
path.enter().append('path').classed('country', true);
path.attr('d', pathGenerator);
path.exit().remove();
path.on('click', function(d) {
d.centered = !d.centered;
var centerCoords = d3.geo.centroid(d),
centerPixels = projection(centerCoords);
if (d.centered) {
grp.transition().duration(2e3)
.attr('transform', function() {
var dx = (width / 2) - zoomFactor * centerPixels[0],
dy = (height / 2) - zoomFactor * centerPixels[1];
var t = 'translate(' + [dx, dy] + ')',
s = 'scale(' + zoomFactor + ')';
return t + s;
});
} else {
grp.transition().duration(1500).attr('transform', '');
}
});
});
</script>
</body>
</html>
Makefile
URL = http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/50m/cultural/ne_50m_admin_0_countries.zip
ne_50m_admin_0_countries.zip:
curl -LO $(URL)
ne_50m_admin_0_countries.shp: ne_50m_admin_0_countries.zip
unzip ne_50m_admin_0_countries.zip
touch ne_50m_admin_0_countries.shp
countries.geojson: ne_50m_admin_0_countries.shp
ogr2ogr -f GeoJSON countries.geojson ne_50m_admin_0_countries.shp
countries.topojson: countries.geojson
topojson -p -o countries.topojson countries.geojson
clean:
rm ne_50m_admin_0_countries*