Skip to content

Instantly share code, notes, and snippets.

@crabmusket
Forked from arrayjam/index.html
Created March 19, 2019 04:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crabmusket/db7fae39fc5238c318b3557ef481be5d to your computer and use it in GitHub Desktop.
Save crabmusket/db7fae39fc5238c318b3557ef481be5d 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("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("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
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