Step 3: Location maps. India’s topojson created using makefile.
This code is part of the Wikimaps team push for better wikipedia maps. An efforts for both GIS data collection and map generation for the purpose of encyclopedic cartography and free knowledge.
Meta: v13.08.28. Makefile: Make2/data. Focus: India. Type: location_map.
With: Auto-focus. Wikipedia styles : polygons and conditional boundaries. Download button. Provinces name for fun.
Sources & thanks:
Mike Bostock: Why Use Make
Eidmanna: Austria D3 TopoJSON (makefile in action)
Wikipedia maps’ guidelines: Wikipedia:WikiProject_Maps/Conventions
To do: add water bodies.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg { border: 5px solid #646464; background-color: #C6ECFF;}
path.L0 { fill:#E0E0E0;}
path.L1 { fill:#FEFEE9;}
path.invisible,text.invisible { fill:none;stroke:none; visibility:none;}
path.L1:hover { fill: #B10000 ;}
.red { border: 5px solid red;} /* Class for tests */
.Topo_50 { border: green; fill:purple; }
.subunit-boundary {
fill: none;
stroke-width:1px;
stroke: #646464;
/* stroke-dasharray: 10,3,3,3; */
stroke-linejoin: round;
}
.international-boundary {
fill: none;
stroke-width:2px;
stroke: #646464;
stroke-dasharray: 16,4,3,4;
stroke-linejoin: round;
}
.place,
.place-label {
fill: #444;
font-size:12px;
}
.coastline {fill: none; stroke:#0978AB;}
text {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
pointer-events: none;
}
.subunit-label {
fill: #777;
fill-opacity: .5;
font-weight: 900;
text-anchor: middle;
font-size: 14px;
}
.download { background: #333; color: #FFF; font-weight: 900; border: 2px solid #B10000; padding: 4px; margin:4px;}
</style>
<body>
<script src="//code.jquery.com/jquery-2.0.2.min.js"></script>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
// 1. -------------- SETTINGS ------------- //
// India geo-frame borders in decimal ⁰
var WNES = { "W": 67.0, "N":37.5, "E": 99.0, "S": 5.0, "vert_%": 106, "item":"India" },
target =WNES.item;
// Function Click > Console
function click(a){ var name = a.properties.name || a.id ; console.log(name);}
// var WNES = { "W": -5.8, "N":51.5, "E": 10, "S": 41.0, "vert_%": 140, "stone":"France" };
// Geo values of interest :
var latCenter = (WNES.S + WNES.N)/2,
lonCenter = (WNES.W + WNES.E)/2,
geo_width = (WNES.E - WNES.W),
geo_height= (WNES.N - WNES.S);
// HTML expected Stoneme dimensions
var width = 600,
height = width * (geo_height / geo_width);
// var color = d3.scale.category10(); // d3.scale.ordinal().domain(["000000", "FFFFFF", "baz"]).range(colorbrewer.RdBu[9]);
// Projection: projection, reset scale and translate
var projection = d3.geo.equirectangular()
.scale(1)
.translate([0, 0]);
// SVG injection:
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
//Pattern injection : disputed-in, disputed-out
var pattern = svg.append("defs")
.append("pattern")
.attr({ id:"hash2_4", width:"6", height:"6", patternUnits:"userSpaceOnUse", patternTransform:"rotate(-45)"})
.append("rect")
.attr({ width:"2", height:"6", transform:"translate(0,0)", fill:"#E0E0E0" });
var pattern = svg.append("defs")
.append("pattern")
.attr({ id:"hash4_2", width:"6", height:"6", patternUnits:"userSpaceOnUse", patternTransform:"rotate(-45)"})
.append("rect")
.attr({ width:"2", height:"6", transform:"translate(0,0)", fill:"#FEFEE9" });
// Path
var path = d3.geo.path()
.projection(projection)
.pointRadius(4);
// Data (getJSON: TopoJSON)
d3.json("./administrative.topo.json", showData);
// ---------- FUNCTION ------------- //
function showData(error, Stone) {
// var #Coord: projection formerly here
// var #Path: formerly here
var countries = topojson.feature(Stone, Stone.objects.admin_0),
subunits = topojson.feature(Stone, Stone.objects.admin_1),
disputed = topojson.feature(Stone, Stone.objects.disputed),
places = topojson.feature(Stone, Stone.objects.places),
neighbors = topojson.neighbors(Stone.objects.admin_1.geometries); // coloring: full line
// Focus area box compute for derive scale & translate.
// [[left, bottom], [right, top]] // E W N S
var b = path.bounds(countries),
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];
// Projection update
projection = projection
.scale(s)
.translate(t);
/* Polygons ********************************************* */
//Append L0 polygons
svg.selectAll(".countries")
.data(countries.features)
.enter().append("path")
.attr("class", "L0")
.attr({fill:"url(#hash4_4);"})
.attr("data-name-en", function(d) { return d.properties.id; })
.attr("d", path)
//.style("fill", function(d, i) { return color(d.color = d3.max(neighbors[i], function(n) { return subunits[n].color; }) + 1 | 0); }) // coloring: fill
.on("click", click);
//Append L1 polygons
svg.selectAll(".subunit")
.data(subunits.features)
.enter().append("path")
.attr("class", function(d){ return d.properties.L0 === target? "L1": "L1 invisible"; } )
.attr("data-name-en", function(d) { return d.id; })
.attr("d", path )
//.style("fill", function(d, i) { return color(d.color = d3.max(neighbors[i], function(n) { return subunits[n].color; }) + 1 | 0); }) // coloring: fill
.on("click", click);
//Append disputed polygons
svg.selectAll(".disputed")
.data(disputed.features)
.enter().append("path")
.attr("class", function(d){ return d.properties.L0 === target? "disputed in": "disputed out"; } )
.attr("fill", function(d){ return d.properties.L0 === target? "url(#hash2_4)": "url(#hash4_2)"} )
.attr("data-name-en", function(d) { return d.id; })
.attr("d", path )
//.style("fill", function(d, i) { return color(d.color = d3.max(neighbors[i], function(n) { return subunits[n].color; }) + 1 | 0); }) // coloring: fill
.on("click", click);
/* Arcs ************************************************* */
// Admin1-borders filtered
svg.append("path")
.datum(topojson.mesh(Stone, Stone.objects.admin_1, function(a,b) { return a !==b && a.properties.L0 === b.properties.L0 && a.properties.L0 === target ;}))
.attr("d", path)
.attr("class", "subunit-boundary");
// Admin0-borders filtered
svg.append("path")
.datum(topojson.mesh(Stone, Stone.objects.admin_0, function(a,b) { return a!==b;}))
.attr("d", path)
.attr("class", "international-boundary");
// Coast-borders filtered
svg.append("path")
.datum(topojson.mesh(Stone, Stone.objects.admin_0, function(a,b) { return a===b;}))
.attr("d", path)
.attr("class", "coastline");
/* DOT & LABELS ******************************************* */
// Places: dot placement ********************************** */
svg.append("path")
.datum(places)
.attr("d", path)
.attr("class", "place");
// Places label placement
svg.selectAll(".place-label")
.data(places.features)
.enter().append("text")
.attr("class", "place-label")
.attr("transform", function(d) { return "translate(" + projection(d.geometry.coordinates) + ")"; })
.attr("dy", ".35em")
.text( function(d) { return d.id;} )
.attr("x", function(d) { return d.geometry.coordinates[0] > -1 ? 6 : -6; })
.style("text-anchor", function(d) { return d.geometry.coordinates[0] > -1 ? "start" : "end"; });
/* L1 labels ******************************************** */
svg.selectAll(".subunit-label")
.data(subunits.features)
.enter().append("text")
.attr("class", function(d){ return d.properties.L0 === target? "subunit-label": "subunit-label invisible"; } )
.attr("data-name-en", function(d) { return d.properties.id ;})
.attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
// Vertical adjustment custom:
.attr("dy", function(d){
if(d.id==="Delhi"|| d.id==="2nd capital" ){return ".5em"}
else{return ".2em"}}) // default
// Vertical adjustment custom:
.attr("font-size", function(d){
if(d.id==="Delhi"|| d.id==="2nd capital" ){return "1.2"}
else{return "6px"} }) // default
.text(function(d) { return d.id; });
}
</script>
<br />
<div>
<a class="download ac-icon-download" href="javascript:javascript: (function () { var e = document.createElement('script'); if (window.location.protocol === 'https:') { e.setAttribute('src', 'https://raw.github.com/NYTimes/svg-crowbar/gh-pages/svg-crowbar.js'); } else { e.setAttribute('src', '//nytimes.github.com/svg-crowbar/svg-crowbar.js'); } e.setAttribute('class', 'svg-crowbar'); document.body.appendChild(e); })();"><!--⤋--><big>⇩</big> Download</a> -- Works on Chrome. Feedback welcome for others web browsers.
</div>
<br />
</body>
</html>