Last active
November 16, 2019 04:07
-
-
Save arrayjam/5362978 to your computer and use it in GitHub Desktop.
Australia Postcode Decoder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
text, label { | |
font-family: sans-serif; | |
} | |
label { | |
position: absolute; | |
text-align: center; | |
font-weight: bold; | |
padding: 0 10px; | |
line-height: 50px; | |
} | |
input { | |
text-align: center; | |
width: 5em; | |
padding: 5px; | |
} | |
.feature { | |
stroke: none; | |
} | |
.divider { | |
stroke: #dedede; | |
stroke-width: 0.5px; | |
} | |
</style> | |
<body> | |
<label for="postcode"> | |
Enter a Postcode: | |
<input id="postcode" autofocus maxlength=4 placeholder="Postcode" type="text" /> | |
</label> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="http://d3js.org/topojson.v0.min.js"></script> | |
<script> | |
var width = 750, | |
height = 700; | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height + 50); | |
var g = svg.append("g") | |
.attr("transform", "translate(0, 50)") | |
.append("g"); | |
var color = d3.scale.category10(); | |
var loading = svg.append("text") | |
.attr("x", width / 2) | |
.attr("y", height / 2) | |
.attr("dy", ".35em") | |
.attr("text-anchor", "middle") | |
.style("font-size", 40) | |
.text("Loading..."); | |
d3.json("b53aa41b4c61df6272fd67fd2691517e87af63a5/postcodes.json", function(error, postcodes) { | |
var postcodesgeo = topojson.object(postcodes, postcodes.objects.postcodesgeo).geometries; | |
var mainlandWidth = 236; | |
var leftMargin = 186; | |
var rightMargin = 64; | |
var allAus = mainlandWidth + leftMargin + rightMargin; | |
var translateWidth = width / (allAus / mainlandWidth); | |
var projection = d3.geo.albers() | |
.translate([translateWidth, height / 2]) | |
.scale(1100) | |
.rotate([-132.5, 0]) | |
.center([0, -26.5]) // Center of Australia, accounting for tasmania | |
.parallels([-36, -18]); | |
var path = d3.geo.path() | |
.projection(projection); | |
var input = d3.select("input") | |
.on("cut", change) | |
.on("paste", change) | |
.on("change", change) | |
.on("keyup", change); | |
var feature = g.selectAll("path") | |
.data(postcodesgeo) | |
.enter().append("path") | |
.attr("class", "feature") | |
.attr("id", function (d, i) { | |
// Here we can compute "id" using datums | |
console.log(d); | |
return i; | |
}) | |
.attr("d", path); | |
loading.remove(); | |
svg.append("rect") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("height", 50) | |
.attr("width", width) | |
.style("fill", "white"); | |
svg.append("line") | |
.attr("class", "divider") | |
.attr("x1", 0) | |
.attr("x2", width) | |
.attr("y1", 51) | |
.attr("y2", 51); | |
var legends = svg.append("g").attr("class", "legends"); | |
svg.selectAll("text.legend") | |
.data([0,1,2,3,4,5,6,7,8,9]) | |
.enter().append("text") | |
.attr("class", "legend") | |
.attr("y", 25) | |
.attr("x", function(d) { return width - (10 - d) * 50 + 25; }) | |
.style("fill", "white") | |
.attr("dy", ".35em") | |
.attr("text-anchor", "middle") | |
.style("font-size", 20) | |
.text(String); | |
var prefix = "POA"; | |
var selectedPostcode; | |
change(); | |
function updateLegend(legend) { | |
var container = legends.selectAll("rect.legend") | |
.data(legend, function(d) { return d; }); | |
container | |
.transition().duration(750) | |
.attr("x", function(d) { return width - (10 - d) * 50; }) | |
.style("fill", function(d) { return color(d); }) | |
.attr("y", 0); | |
container.enter().append("rect") | |
.attr("class", "legend") | |
.attr("y", -50) | |
.attr("width", 50) | |
.attr("height", 50) | |
.attr("x", function(d) { return width - (10 - d) * 50; }) | |
.transition() | |
.duration(750) | |
.ease("bounce") | |
.style("fill", function(d) { return color(d); }) | |
.attr("y", 0); | |
container.exit().transition().duration(400) | |
.ease("backs") | |
.attr("y", -50) | |
.remove(); | |
} | |
function setFoundStyle(selection, postcode) { | |
selection.style("fill", color(postcode.slice(-1))); | |
} | |
function unzoom(selection) { | |
selection.transition().duration(750).attr("transform", ""); | |
} | |
function zoom(selection, b, maxScale) { | |
var scale = 0.95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height); | |
var usedScale = Math.min(scale, maxScale); | |
selection.transition().duration(750).attr("transform", | |
"translate(" + projection.translate() + ")" + | |
"scale(" + usedScale + ")" + | |
"translate(" + -(b[1][0] + b[0][0]) / 2 + "," + -(b[1][1] + b[0][1]) / 2 + ")"); | |
} | |
function change() { | |
var lastPostcode = selectedPostcode; | |
selectedPostcode = input.property("value"); | |
if (lastPostcode === selectedPostcode) { | |
return; | |
} | |
var shouldUnzoom = selectedPostcode === ""; | |
var shouldZoom = selectedPostcode.match(/\d{1,4}/); | |
if (!shouldUnzoom && !shouldZoom) { | |
return; | |
} | |
var matchString = prefix + selectedPostcode; | |
var findBounds = findMinMaxBounds(); | |
var bounds; | |
var legendObj = {}; | |
var matching = feature.filter(function(d) { | |
var match = matchingFeature(d, matchString); | |
var next = nextDigit(d, matchString); | |
this.style.fill = match ? color(+next) : "#222"; | |
if (match) { | |
if (next) { legendObj[+next] = true; } | |
bounds = findBounds(path.bounds(d)); | |
} | |
return match; | |
}); | |
updateLegend(d3.keys(legendObj).map(function(d) { return +d; })); | |
if (matching[0].length === 0) { return; } | |
if (selectedPostcode.length === 4 && matching[0].length === 1) { matching.call(setFoundStyle, matchString); } | |
var zoomers = function() { | |
if (shouldZoom) { g.call(zoom, bounds, 100); } | |
if (shouldUnzoom) { g.call(unzoom); } | |
}; | |
setTimeout(zoomers, 0); | |
} | |
function nextDigit(feature, string) { | |
return feature.id.charAt(string.length); | |
} | |
function matchingFeature(feature, string) { | |
return feature.id.indexOf(string) !== -1; | |
} | |
function findMinMaxBounds() { | |
var topBound = -Infinity; | |
var rightBound = -Infinity; | |
var bottomBound = Infinity; | |
var leftBound = Infinity; | |
return function (bound) { | |
leftBound = Math.min(bound[0][0], leftBound); | |
bottomBound = Math.min(bound[0][1], bottomBound); | |
rightBound = Math.max(bound[1][0], rightBound); | |
topBound = Math.max(bound[1][1], topBound); | |
return [[leftBound, bottomBound], [rightBound, topBound]]; | |
}; | |
} | |
}); | |
d3.select(self.frameElement).style("height", height + "px"); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment