Skip to content

Instantly share code, notes, and snippets.

@anisotropi4
Last active April 23, 2017 14:49
Show Gist options
  • Save anisotropi4/003ed4f355160a49f0c4b3e169191ac8 to your computer and use it in GitHub Desktop.
Save anisotropi4/003ed4f355160a49f0c4b3e169191ac8 to your computer and use it in GitHub Desktop.
UK and Ireland Railway OSM with overlap based scale filter
license: gpl-3.0
data: Open Data Commons Open Database License (ODbL) http://www.openstreetmap.org/copyright

This more sophisticated d3 (https://d3js.org) and leaflet (http://leafletjs.com) mash-up displays OpenStreetMap Railway Points of Interest for the UK and Ireland with the quadtree and a precalculated "valid" distance attribute to quickly find nodes to display.

As before, the large dataset is problematic without the combined quadtree and heuristic filters at larger scale. In this case UK and Ireland railways have about 912k points. Rather than applying a random heuristic, in this case the number of points displaced at a given scale is based on a distance between points calculation described in the associated 'goldfinch' github repository (https://github.com/anisotropi4/goldfinch/tree/master/overlapfilter)

The data visualised is extracted from OpenStreetMap (http://www.openstreetmap.org) uses Overpass API (http://www.overpass-api.de) plus:
Arangodb (https://www.arangodb.com)
jq (https://stedolan.github.io/jq)

The data is used under the OpenStreetMap Creative Commons Attribution (http://www.openstreetmap.org/copyright)

<!DOCTYPE html>
<html>
<head>
<title>d3.js with leaflet.js rendering OSM points-of-interest</title>
<link rel="stylesheet" href="https://npmcdn.com/[email protected]/dist/leaflet.css">
<script src="https://npmcdn.com/[email protected]/dist/leaflet.js"></script>
<script src="http://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div id="map" style="width: 1340px; height: 635px"></div>
<script type="text/javascript">
var radius = 4;
var log2 = Math.log(2.0);
var minZoom = 3;
var maxZoom = 18;
// var map = L.map('map').setView([51.53, -0.124], 14); //KGX
var map = L.map('map').setView([53.96, -1.08], 14); //YRK
mapLink = '<a href="http://openstreetmap.org">OpenStreetMap</a>';
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; ' + mapLink + ' Contributors',
minZoom: minZoom,
maxZoom: maxZoom
}).addTo(map);
L.svg().addTo(map);
var svg = d3.select("#map").select("svg")
, g = svg.selectAll("g");
var collections = [];
var colours15 = {0: "GreenYellow", 13: "DeepSkyBlue", 3: "Gold", 5: "Red", 4: "Purple", 6: "Orange", 7: "DeepPink", 8: "Magenta", 9: "DarkSlateBlue", 10: "GreenYellow", 11: "Lime", 12: "Cyan", 1: "Blue", 14: "DarkBlue", 15: "DarkOrange", 16: "DarkOrchid"};
var colourscale = function(n) {
return colours15[n];
}
// mapply works for big data sets while Math.{min,max}.apply() fails
function mapply(a, fn) {
var m = a[0];
for (i=1; i < a.length; i++) {
if (fn(a[i], m) != m) {
m = a[i];
}
}
return m;
}
var arange = [25, 0];
d3.json("raildata.json", function(err, d) {
if (err)
return console.warn(err);
d.forEach(function(v, i) {
v.type = "output";
v.colour = colourscale(5);
v.LatLng = new L.LatLng(v.lat,v.lon);
arange[0] = Math.min(arange[0], v.lvalid);
if (v.lvalid < 25) {
arange[1] = Math.max(arange[1], v.lvalid);
}
});
collections = collections.concat(d);
render();
});
function render() {
var tree = d3.quadtree().x(function(d) {
return d.lat;
}).y(function(d) {
return d.lon;
}).addAll(collections);
var zscale = d3.scaleLinear().domain([minZoom+1, maxZoom]).range([arange[1], arange[0]]);
function visiblenodes() {
var nodes = [];
var z = map.getZoom();
console.log("zoom:", z, " zoomu:", zscale(z));
var bounds = map.getBounds();
var p0 = bounds._southWest
, p3 = bounds._northEast;
tree.visit(function(node, x1, y1, x2, y2) {
if (node.data && node.data.lvalid >= zscale(map.getZoom())) {
//if (node.data) {
nodes.push(node.data);
}
return x1 >= p3.lat || y1 >= p3.lon || x2 < p0.lat || y2 < p0.lon;
});
console.log("# nodes selected", nodes.length);
return nodes;
}
map.on("viewreset", update);
map.on("moveend", update);
update();
function update() {
g.selectAll("circle").remove();
g.selectAll("text").remove();
g.selectAll("rect").remove();
var nodes = visiblenodes()
, i = 0;
var feature = g.selectAll("circle").data(nodes).enter().append("g").style("fill", function(d, i) {
return d.colour;
}).append("svg:circle").style("stroke", "black").style("opacity", function(d, i) {
return 0.6;
}).attr("r", radius).attr("transform", function(d) {
var p = map.latLngToLayerPoint(d.LatLng);
d.x = p.x;
d.y = p.y;
return "translate(" + d.x + "," + d.y + ")";
});
}
}
</script>
</body>
</html>
This file has been truncated, but you can view the full file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment