Skip to content

Instantly share code, notes, and snippets.

@arrayjam
Last active November 16, 2019 04:07
Show Gist options
  • Save arrayjam/5362978 to your computer and use it in GitHub Desktop.
Save arrayjam/5362978 to your computer and use it in GitHub Desktop.
Australia Postcode Decoder
<!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>
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment