|
<html> |
|
|
|
<head> |
|
<style> |
|
body { |
|
margin: 0; |
|
font-family: "Helvetica Neue", sans-serif; |
|
} |
|
|
|
#map .subunit { |
|
fill: #ddd; |
|
stroke: #fff; |
|
stroke-width: 1px; |
|
} |
|
|
|
#map .subunit.selected { |
|
stroke: #000; |
|
stroke-width: 2px; |
|
} |
|
|
|
#map .subunit-boundary { |
|
fill: none; |
|
stroke: #3a403d; |
|
} |
|
|
|
#map .place, |
|
.place-label { |
|
pointer-events: none; |
|
} |
|
|
|
#map .place-label { |
|
font-size: .7em; |
|
text-shadow: 0px 0px 2px #fff; |
|
} |
|
|
|
#tip { |
|
position: absolute; |
|
background: #fff; |
|
opacity: .9; |
|
padding: 10px; |
|
} |
|
|
|
#legend { |
|
position: absolute; |
|
left: 10px; |
|
top: 10px; |
|
} |
|
|
|
#legend .legend-title { |
|
margin-bottom: 4px; |
|
font-weight: bold; |
|
} |
|
|
|
#legend .legend-item { |
|
margin-bottom: 4px; |
|
font-size: .8em; |
|
} |
|
|
|
#legend .legend-swatch, |
|
#legend .legend-value { |
|
display: inline-block; |
|
vertical-align: bottom; |
|
} |
|
|
|
#legend .legend-swatch { |
|
width: 16px; |
|
height: 16px; |
|
margin-right: 4px; |
|
} |
|
</style> |
|
|
|
</head> |
|
|
|
<body> |
|
<div id="tip"></div> |
|
<div id="legend"> |
|
<div class="legend-title">Legend</div> |
|
</div> |
|
<div id="map"></div> |
|
|
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script src="https://unpkg.com/[email protected]/build/d3-moveto.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.20/topojson.min.js"></script> |
|
<script src="https://unpkg.com/[email protected]/lib/jeezy.min.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/1.3.4/chroma.min.js"></script> |
|
|
|
<script> |
|
var match_property = "dist", |
|
value_property = "value", |
|
colors = ["#edf8fb", "#b2e2e2", "#66c2a4", "#2ca25f", "#006d2c"], |
|
breakType = "e"; |
|
|
|
var width = window.innerWidth, |
|
height = window.innerHeight; |
|
|
|
var projection = d3.geoMercator(); |
|
|
|
var path = d3.geoPath() |
|
.projection(projection) |
|
.pointRadius(2); |
|
|
|
var svg = d3.select("#map").append("svg") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
d3.queue() |
|
.defer(d3.json, "map.json") |
|
.defer(d3.csv, "data.csv") |
|
.await(ready); |
|
|
|
function ready(error, geo, data) { |
|
if (error) throw error; |
|
|
|
centerZoom(geo, width, height); |
|
drawSubUnits(geo); |
|
drawPlaces(geo); |
|
drawOuterBoundary(geo); |
|
|
|
fillSubUnits(data); |
|
drawTip(data); |
|
drawLegend(data); |
|
|
|
window.addEventListener("resize", resize); |
|
|
|
function resize(){ |
|
var width = window.innerWidth, |
|
height = window.innerHeight; |
|
|
|
svg.attr("width", width).attr("height", height); |
|
|
|
centerZoom(geo, width, height); |
|
|
|
d3.selectAll("path").attr("d", path); |
|
d3.selectAll("text").attr("transform", function(d) { return "translate(" + projection(d.geometry.coordinates) + ")"; }); |
|
|
|
} |
|
|
|
} |
|
|
|
function drawLegend(data, breakType, breakCount) { |
|
var breakCount = colors.length; |
|
var limits = chroma.limits(data.map(function(d) { |
|
return +d[value_property]; |
|
}), breakType, breakCount); |
|
|
|
colors.forEach(function(color, color_index) { |
|
|
|
d3.select("#legend").append("div") |
|
.attr("class", "legend-item") |
|
.html("<div class='legend-swatch' style='background: " + color + "'></div><div class='legend-value'>" + jz.str.numberLakhs(limits[color_index].toFixed(1)) + " - " + jz.str.numberLakhs(limits[color_index + 1].toFixed(1)) + "</div>"); |
|
|
|
}); |
|
|
|
} |
|
|
|
function fillSubUnits(data, breakType, breakCount) { |
|
var breakCount = colors.length; |
|
var limits = chroma.limits(data.map(function(d) { |
|
return +d[value_property]; |
|
}), breakType, breakCount); |
|
|
|
|
|
svg.selectAll(".subunit") |
|
.style("fill", function(d, i) { |
|
var match = matchData(d, data); |
|
|
|
var return_color = []; |
|
limits.forEach(function(limit, limit_index) { |
|
if (+match[value_property] >= limit && +match[value_property] <= limits[limit_index + 1]) { |
|
return_color.push(colors[limit_index]); |
|
} |
|
}); |
|
return return_color[0]; |
|
|
|
}); |
|
|
|
} |
|
|
|
function drawTip(data) { |
|
svg.selectAll(".subunit") |
|
.on("mouseover", function(d) { |
|
|
|
d3.select("#tip").style("display", "block"); |
|
var match = matchData(d, data); |
|
|
|
// make the content |
|
var keys = Object.keys(match); |
|
var content = keys.map(function(key) { |
|
return "<b>" + key + "</b>: " + match[key]; |
|
}).join("<br />"); |
|
d3.select("#tip").html(content); |
|
|
|
d3.select(".subunit." + jz.str.toSlugCase(d.properties[match_property])).classed("selected", true).moveToFront(); |
|
d3.selectAll(".place").moveToFront(); |
|
d3.selectAll(".place-label").moveToFront(); |
|
}) |
|
.on("mousemove", function() { |
|
// tip positioning |
|
var coordinates = [0, 0]; |
|
coordinates = d3.mouse(this); |
|
var x = coordinates[0]; |
|
var y = coordinates[1]; |
|
|
|
d3.select("#tip") |
|
.style("left", x + 20) |
|
.style("top", y - 20); |
|
}) |
|
.on("mouseout", function() { |
|
d3.select("#tip").style("display", "none"); |
|
d3.selectAll(".subunit").classed("selected", false); |
|
d3.select(".subunit-boundary").moveToFront(); |
|
}); |
|
} |
|
|
|
function matchData(d, data) { |
|
return data.filter(function(e) { |
|
return d.properties[match_property] == e[match_property]; |
|
})[0]; |
|
} |
|
|
|
function centerZoom(data, width, height) { |
|
projection.fitSize([width, height], topojson.feature(data, data.objects.polygons)); |
|
} |
|
|
|
function drawOuterBoundary(data) { |
|
var boundary = topojson.mesh(data, data.objects.polygons, function(a, b) { return a === b; }); |
|
svg.append("path") |
|
.datum(boundary) |
|
.attr("d", path) |
|
.attr("class", "subunit-boundary"); |
|
} |
|
|
|
function drawPlaces(data) { |
|
svg.append("path") |
|
.datum(topojson.feature(data, data.objects.places)) |
|
.attr("d", path) |
|
.attr("class", "place"); |
|
|
|
svg.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", function(d) { |
|
return projection(d.geometry.coordinates)[0] <= width / 2 ? -6 : 6; |
|
}) |
|
.style("text-anchor", function(d) { |
|
return projection(d.geometry.coordinates)[0] <= width / 2 ? "end" : "start"; |
|
}) |
|
.text(function(d) { |
|
return d.properties.name; |
|
}); |
|
} |
|
|
|
function drawSubUnits(data) { |
|
svg.selectAll(".subunit") |
|
.data(topojson.feature(data, data.objects.polygons).features) |
|
.enter().append("path") |
|
.attr("class", function(d) { |
|
return "subunit " + jz.str.toSlugCase(d.properties[match_property]); |
|
}) |
|
.attr("d", path); |
|
} |
|
</script> |
|
|
|
</body> |
|
|
|
</html> |