Draw a map of India with D3.js, Topojson, and five simple functions:
centerZoom
- Automatically centers and scales your map to its container, and returns your map’s outer boundaries in case you want to draw them.drawOuterBoundary
- Uses the boundary returned from centerZoom
to draw a boundary around your whole map.drawPlaces
- Draws place names, if your topojson has places.drawSubunits
- Draws subunits.colorSubunits
- Colors the subunits.This map uses a Mercator projection, and the colors are generated from d3.schemeCategory20
. For a tutorial on converting Geojson to Topojson and for finding the coordinates of major cities, see this tutorial.
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: "Helvetica Neue", sans-serif;
margin: 0;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.20/topojson.min.js"></script>
<script>
var width = window.innerWidth, height = window.innerHeight;
var projection = d3.geoMercator();
var path = d3.geoPath()
.projection(projection)
.pointRadius(2);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g");
d3.json("india.json", function(error, data){
var boundary = centerZoom(data);
var subunits = drawSubUnits(data);
colorSubunits(subunits);
drawSubUnitLabels(data);
drawPlaces(data);
drawOuterBoundary(data, boundary);
});
function centerZoom(data){
var o = topojson.mesh(data, data.objects.polygons, function(a, b) { return a === b; });
projection
.scale(1)
.translate([0, 0]);
var b = path.bounds(o),
s = 1 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
var p = projection
.scale(s)
.translate(t);
return o;
}
function drawOuterBoundary(data, boundary){
g.append("path")
.datum(boundary)
.attr("d", path)
.attr("class", "subunit-boundary")
.attr("fill", "none")
.attr("stroke", "#3a403d");
}
function drawPlaces(data){
g.append("path")
.datum(topojson.feature(data, data.objects.places))
.attr("d", path)
.attr("class", "place");
g.selectAll(".place-label")
.data(topojson.feature(data, data.objects.places).features)
.enter().append("text")
.attr("class", "place-label")
.attr("transform", function(d) { return "translate(" + projection(d.geometry.coordinates) + ")"; })
.attr("dy", ".35em")
.attr("x", 6)
.attr("text-anchor", "start")
.style("font-size", ".7em")
.style("text-shadow", "0px 0px 2px #fff")
.text(function(d) { return d.properties.name; });
}
function drawSubUnits(data){
var subunits = g.selectAll(".subunit")
.data(topojson.feature(data, data.objects.polygons).features)
.enter().append("path")
.attr("class", "subunit")
.attr("d", path)
.style("stroke", "#fff")
.style("stroke-width", "1px");
return subunits;
}
function drawSubUnitLabels(data){
g.selectAll(".subunit-label")
.data(topojson.feature(data, data.objects.polygons).features)
.enter().append("text")
.attr("class", "subunit-label")
.attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.style("font-size", ".5em")
.style("text-shadow", "0px 0px 2px #fff")
.style("text-transform", "uppercase")
.text(function(d) { return d.properties.st_nm; });
}
function colorSubunits(subunits) {
var c = d3.scaleOrdinal(d3.schemeCategory20);
subunits
.style("fill", function(d,i){ return c(i); })
.style("opacity", ".6");
}
</script>
</body>
</html>